@aptos-labs/wallet-adapter-core 2.6.0 → 3.1.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,17 @@
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
+ AnyRawTransaction,
4
+ AccountAuthenticator,
5
+ AccountAuthenticatorEd25519,
6
+ Ed25519PublicKey,
7
+ InputGenerateTransactionOptions,
8
+ Ed25519Signature,
9
+ AptosConfig,
10
+ generateTransactionPayload,
11
+ InputSubmitTransactionData,
12
+ PendingTransactionResponse,
13
+ InputEntryFunctionDataWithRemoteABI,
14
+ } from "@aptos-labs/ts-sdk";
3
15
  import EventEmitter from "eventemitter3";
4
16
  import nacl from "tweetnacl";
5
17
  import { Buffer } from "buffer";
@@ -24,29 +36,34 @@ import {
24
36
  import {
25
37
  AccountInfo,
26
38
  NetworkInfo,
27
- WalletName,
28
39
  SignMessagePayload,
29
- SignMessageResponse,
30
40
  Wallet,
31
41
  WalletInfo,
32
42
  WalletCoreEvents,
33
- TransactionOptions,
43
+ SignMessageResponse,
44
+ InputTransactionData,
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,167 @@ 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 InputTransactionData
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: InputTransactionData,
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
+ {
305
+ ...transactionInput,
306
+ sender: transactionInput.sender ?? this._account!.address,
307
+ },
308
+ options
309
+ );
310
+ // response should be PendingTransactionResponse
311
+ return response;
312
+ }
310
313
 
311
- try {
312
- this.doesWalletExist();
313
- const response = await (this._wallet as any).signAndSubmitBCSTransaction(
314
- transaction,
315
- options
314
+ // get the payload piece from the input
315
+ const payloadData = transactionInput.data;
316
+
317
+ // if first function arguments is an object (i.e a bcs serialized argument)
318
+ // we assume the transaction should be a bcs serialized transaction
319
+ if (typeof payloadData.functionArguments[0] === "object") {
320
+ const aptosConfig = new AptosConfig({
321
+ network: convertNetwork(this._network),
322
+ });
323
+ const newPayload = await generateTransactionPayload({
324
+ ...(payloadData as InputEntryFunctionDataWithRemoteABI),
325
+ aptosConfig: aptosConfig,
326
+ });
327
+ const oldTransactionPayload =
328
+ convertV2TransactionPayloadToV1BCSPayload(newPayload);
329
+ const response = await this.waletCoreV1.signAndSubmitBCSTransaction(
330
+ oldTransactionPayload,
331
+ this._wallet!,
332
+ {
333
+ max_gas_amount: options?.maxGasAmount
334
+ ? BigInt(options?.maxGasAmount)
335
+ : undefined,
336
+ gas_unit_price: options?.gasUnitPrice
337
+ ? BigInt(options?.gasUnitPrice)
338
+ : undefined,
339
+ }
340
+ );
341
+ const { hash, ...output } = response;
342
+ return { hash, output };
343
+ }
344
+
345
+ // if it is not a bcs serialized arguments transaction, convert to the old
346
+ // json format
347
+ const oldTransactionPayload =
348
+ convertV2PayloadToV1JSONPayload(payloadData);
349
+ const response = await this.waletCoreV1.signAndSubmitTransaction(
350
+ oldTransactionPayload,
351
+ this._wallet!,
352
+ {
353
+ max_gas_amount: options?.maxGasAmount
354
+ ? BigInt(options?.maxGasAmount)
355
+ : undefined,
356
+ gas_unit_price: options?.gasUnitPrice
357
+ ? BigInt(options?.gasUnitPrice)
358
+ : undefined,
359
+ }
316
360
  );
317
- return response;
361
+ const { hash, ...output } = response;
362
+ return { hash, output };
318
363
  } catch (error: any) {
319
- const errMsg =
320
- typeof error == "object" && "message" in error ? error.message : error;
364
+ const errMsg = generalizedErrorMessage(error);
321
365
  throw new WalletSignAndSubmitMessageError(errMsg).message;
322
366
  }
323
367
  }
324
368
 
325
369
  /**
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
370
+ * Signs a transaction
371
+ *
372
+ * To support both existing wallet adapter V1 and V2, we support 2 input types
373
+ *
374
+ * @param transactionOrPayload AnyRawTransaction - V2 input | Types.TransactionPayload - V1 input
375
+ * @param options optional. V1 input
376
+ *
377
+ * @returns AccountAuthenticator
331
378
  */
332
379
  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
-
380
+ transactionOrPayload: AnyRawTransaction | Types.TransactionPayload,
381
+ asFeePayer?: boolean,
382
+ options?: InputGenerateTransactionOptions
383
+ ): Promise<AccountAuthenticator> {
342
384
  try {
343
385
  this.doesWalletExist();
344
- const response = await (this._wallet as any).signTransaction(
345
- transaction,
346
- options
386
+ // if input is AnyRawTransaction, i.e V2
387
+ if ("rawTransaction" in transactionOrPayload) {
388
+ if (this._wallet?.version !== "v2") {
389
+ throw new WalletNotSupportedMethod(
390
+ `Sign Transaction V2 is not supported by ${this.wallet?.name}`
391
+ ).message;
392
+ }
393
+ const accountAuthenticator = (this._wallet as any).signTransaction(
394
+ transactionOrPayload,
395
+ asFeePayer
396
+ );
397
+
398
+ return accountAuthenticator;
399
+ }
400
+
401
+ // check current signTransaction function exists
402
+ if (this._wallet && !("signTransaction" in this._wallet)) {
403
+ throw new WalletNotSupportedMethod(
404
+ `Sign Transaction is not supported by ${this.wallet?.name}`
405
+ ).message;
406
+ }
407
+
408
+ const response = await this.waletCoreV1.signTransaction(
409
+ transactionOrPayload as Types.TransactionPayload,
410
+ this._wallet!,
411
+ {
412
+ max_gas_amount: options?.maxGasAmount
413
+ ? BigInt(options?.maxGasAmount)
414
+ : undefined,
415
+ gas_unit_price: options?.gasUnitPrice
416
+ ? BigInt(options?.gasUnitPrice)
417
+ : undefined,
418
+ }
347
419
  );
348
- return response;
420
+ if (!response) {
421
+ throw new Error("error");
422
+ }
423
+
424
+ // Convert retuned bcs serialized SignedTransaction into V2 AccountAuthenticator
425
+ const deserializer1 = new BCS.Deserializer(response);
426
+ const deserializedSignature =
427
+ TxnBuilderTypes.SignedTransaction.deserialize(deserializer1);
428
+ const transactionAuthenticator =
429
+ deserializedSignature.authenticator as TxnBuilderTypes.TransactionAuthenticatorEd25519;
430
+
431
+ const publicKey = transactionAuthenticator.public_key.value;
432
+ const signature = transactionAuthenticator.signature.value;
433
+
434
+ const accountAuthenticator = new AccountAuthenticatorEd25519(
435
+ new Ed25519PublicKey(publicKey),
436
+ new Ed25519Signature(signature)
437
+ );
438
+ return accountAuthenticator;
349
439
  } catch (error: any) {
350
- const errMsg =
351
- typeof error == "object" && "message" in error ? error.message : error;
440
+ const errMsg = generalizedErrorMessage(error);
352
441
  throw new WalletSignTransactionError(errMsg).message;
353
442
  }
354
443
  }
@@ -359,61 +448,34 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
359
448
  @return response from the wallet's signMessage function
360
449
  @throws WalletSignMessageError
361
450
  */
362
- async signMessage(
363
- message: SignMessagePayload
364
- ): Promise<SignMessageResponse | null> {
451
+ async signMessage(message: SignMessagePayload): Promise<SignMessageResponse> {
365
452
  try {
366
453
  this.doesWalletExist();
367
- if (!this._wallet) return null;
368
- const response = await this._wallet?.signMessage(message);
454
+ const response = await this._wallet!.signMessage(message);
369
455
  return response;
370
456
  } catch (error: any) {
371
- const errMsg =
372
- typeof error == "object" && "message" in error ? error.message : error;
457
+ const errMsg = generalizedErrorMessage(error);
373
458
  throw new WalletSignMessageError(errMsg).message;
374
459
  }
375
460
  }
376
461
 
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
462
  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)) {
463
+ transaction: InputSubmitTransactionData
464
+ ): Promise<PendingTransactionResponse> {
465
+ if (this._wallet && !("submitTransaction" in this._wallet)) {
404
466
  throw new WalletNotSupportedMethod(
405
- `Multi-agent & sponsored transactions are not supported by ${this.wallet?.name}`
467
+ `Submit Transaction is not supported by ${this.wallet?.name}`
406
468
  ).message;
407
469
  }
408
470
  try {
409
471
  this.doesWalletExist();
410
- const response = await (this._wallet as any).signMultiAgentTransaction(
472
+ const pendingTransaction = (this._wallet as any).submitTransaction(
411
473
  transaction
412
474
  );
413
- return response;
475
+
476
+ return pendingTransaction;
414
477
  } catch (error: any) {
415
- const errMsg =
416
- typeof error == "object" && "message" in error ? error.message : error;
478
+ const errMsg = generalizedErrorMessage(error);
417
479
  throw new WalletSignTransactionError(errMsg).message;
418
480
  }
419
481
  }
@@ -432,8 +494,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
432
494
  this.emit("accountChange", this._account);
433
495
  });
434
496
  } catch (error: any) {
435
- const errMsg =
436
- typeof error == "object" && "message" in error ? error.message : error;
497
+ const errMsg = generalizedErrorMessage(error);
437
498
  throw new WalletAccountChangeError(errMsg).message;
438
499
  }
439
500
  }
@@ -452,12 +513,16 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
452
513
  this.emit("networkChange", this._network);
453
514
  });
454
515
  } catch (error: any) {
455
- const errMsg =
456
- typeof error == "object" && "message" in error ? error.message : error;
516
+ const errMsg = generalizedErrorMessage(error);
457
517
  throw new WalletNetworkChangeError(errMsg).message;
458
518
  }
459
519
  }
460
520
 
521
+ /**
522
+ * Signs a message and verifies the signer
523
+ * @param message SignMessagePayload
524
+ * @returns boolean
525
+ */
461
526
  async signMessageAndVerify(message: SignMessagePayload): Promise<boolean> {
462
527
  try {
463
528
  this.doesWalletExist();
@@ -522,8 +587,7 @@ export class WalletCore extends EventEmitter<WalletCoreEvents> {
522
587
  }
523
588
  return verified;
524
589
  } catch (error: any) {
525
- const errMsg =
526
- typeof error == "object" && "message" in error ? error.message : error;
590
+ const errMsg = generalizedErrorMessage(error);
527
591
  throw new WalletSignMessageAndVerifyError(errMsg).message;
528
592
  }
529
593
  }
@@ -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
  }