@movebridge/core 0.1.0 → 0.2.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/dist/index.js CHANGED
@@ -280,6 +280,22 @@ var SUPPORTED_WALLETS = {
280
280
  "okxwallet": "okx"
281
281
  };
282
282
  var STORAGE_KEY = "movebridge:lastWallet";
283
+ function normalizeHash(data) {
284
+ if (typeof data === "string") {
285
+ return data.startsWith("0x") ? data : `0x${data}`;
286
+ }
287
+ if (data instanceof Uint8Array) {
288
+ return "0x" + Array.from(data).map((b) => b.toString(16).padStart(2, "0")).join("");
289
+ }
290
+ if (data && typeof data === "object" && "hash" in data) {
291
+ return normalizeHash(data.hash);
292
+ }
293
+ if (data && typeof data.toString === "function") {
294
+ const str = data.toString();
295
+ return str.startsWith("0x") ? str : `0x${str}`;
296
+ }
297
+ return String(data);
298
+ }
283
299
  function toHexString(data) {
284
300
  if (typeof data === "string") return data;
285
301
  if (data instanceof Uint8Array) {
@@ -290,56 +306,88 @@ function toHexString(data) {
290
306
  }
291
307
  return String(data);
292
308
  }
309
+ function extractUserResponse(response) {
310
+ if (!response) {
311
+ throw new Error("Empty response from wallet");
312
+ }
313
+ const resp = response;
314
+ if (resp.status === "rejected") {
315
+ throw new Error("User rejected the request");
316
+ }
317
+ if (resp.args !== void 0) {
318
+ return resp.args;
319
+ }
320
+ return response;
321
+ }
293
322
  function createStandardAdapter(wallet) {
294
- const connectFeature = wallet.features?.["aptos:connect"];
295
- const disconnectFeature = wallet.features?.["aptos:disconnect"];
296
- const signTxFeature = wallet.features?.["aptos:signAndSubmitTransaction"];
297
- const signOnlyFeature = wallet.features?.["aptos:signTransaction"];
298
- const accountChangeFeature = wallet.features?.["aptos:onAccountChange"];
299
- const networkChangeFeature = wallet.features?.["aptos:onNetworkChange"];
323
+ const features = wallet.features || {};
324
+ const connectFeature = features["aptos:connect"];
325
+ const disconnectFeature = features["aptos:disconnect"];
326
+ const signTxFeature = features["aptos:signAndSubmitTransaction"];
327
+ const signOnlyFeature = features["aptos:signTransaction"];
328
+ const accountChangeFeature = features["aptos:onAccountChange"];
329
+ const networkChangeFeature = features["aptos:onNetworkChange"];
300
330
  return {
301
331
  name: wallet.name,
302
332
  icon: wallet.icon || "",
303
333
  async connect() {
304
- if (!connectFeature) throw new Error("Wallet does not support connect");
305
- const response = await connectFeature.connect();
306
- const result = response?.args ?? response;
307
- if (response?.status === "rejected") {
308
- throw new Error("User rejected the connection");
334
+ if (!connectFeature) {
335
+ throw new Error("Wallet does not support connect");
309
336
  }
337
+ const response = await connectFeature.connect();
338
+ const result = extractUserResponse(response);
310
339
  return {
311
340
  address: toHexString(result.address),
312
341
  publicKey: toHexString(result.publicKey)
313
342
  };
314
343
  },
315
344
  async disconnect() {
316
- if (disconnectFeature) await disconnectFeature.disconnect();
345
+ if (disconnectFeature) {
346
+ await disconnectFeature.disconnect();
347
+ }
317
348
  },
318
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
319
349
  async signAndSubmitTransaction(payload) {
320
- if (!signTxFeature) throw new Error("Wallet does not support signAndSubmitTransaction");
350
+ if (!signTxFeature) {
351
+ throw new Error("Wallet does not support signAndSubmitTransaction");
352
+ }
321
353
  const response = await signTxFeature.signAndSubmitTransaction(payload);
322
- if (response?.status === "rejected") {
323
- throw new Error("User rejected the transaction");
354
+ const result = extractUserResponse(response);
355
+ let hash;
356
+ if (result && typeof result === "object" && "hash" in result) {
357
+ hash = normalizeHash(result.hash);
358
+ } else {
359
+ hash = normalizeHash(result);
324
360
  }
325
- const result = response?.args ?? response;
326
- return { hash: result.hash || toHexString(result) };
361
+ return { hash };
327
362
  },
328
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
329
363
  async signTransaction(payload) {
330
- if (!signOnlyFeature) throw new Error("Wallet does not support signTransaction");
364
+ if (!signOnlyFeature) {
365
+ throw new Error("Wallet does not support signTransaction");
366
+ }
331
367
  const response = await signOnlyFeature.signTransaction(payload);
332
- if (response?.status === "rejected") {
333
- throw new Error("User rejected the transaction");
368
+ const result = extractUserResponse(response);
369
+ if (result instanceof Uint8Array) {
370
+ return result;
371
+ }
372
+ if (result && typeof result === "object") {
373
+ if ("authenticator" in result && result.authenticator) {
374
+ return result.authenticator;
375
+ }
376
+ if ("signature" in result && result.signature) {
377
+ return result.signature;
378
+ }
334
379
  }
335
- const result = response?.args ?? response;
336
- return result.authenticator || result.signature || new Uint8Array();
380
+ return new Uint8Array();
337
381
  },
338
382
  onAccountChange(cb) {
339
383
  if (accountChangeFeature) {
340
384
  accountChangeFeature.onAccountChange((account) => {
341
- if (account) {
342
- cb({ address: toHexString(account.address), publicKey: toHexString(account.publicKey) });
385
+ if (account && typeof account === "object") {
386
+ const acc = account;
387
+ cb({
388
+ address: toHexString(acc.address),
389
+ publicKey: toHexString(acc.publicKey)
390
+ });
343
391
  } else {
344
392
  cb(null);
345
393
  }
@@ -349,7 +397,11 @@ function createStandardAdapter(wallet) {
349
397
  onNetworkChange(cb) {
350
398
  if (networkChangeFeature) {
351
399
  networkChangeFeature.onNetworkChange((network) => {
352
- cb(network?.name || String(network));
400
+ if (network && typeof network === "object" && "name" in network) {
401
+ cb(network.name);
402
+ } else {
403
+ cb(String(network));
404
+ }
353
405
  });
354
406
  }
355
407
  }
@@ -359,17 +411,22 @@ var WalletManager = class extends import_eventemitter3.default {
359
411
  state = { connected: false, address: null, publicKey: null };
360
412
  currentWallet = null;
361
413
  adapter = null;
362
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
363
414
  standardWallets = /* @__PURE__ */ new Map();
364
415
  detectedWallets = [];
365
416
  unsubscribe = null;
417
+ /**
418
+ * Detects available wallets using AIP-62 standard
419
+ * @returns Array of detected wallet types
420
+ */
366
421
  detectWallets() {
367
422
  if (typeof window === "undefined") return [];
368
423
  const available = /* @__PURE__ */ new Set();
369
424
  this.standardWallets.clear();
370
425
  try {
371
426
  const { aptosWallets, on } = (0, import_wallet_standard.getAptosWallets)();
372
- if (this.unsubscribe) this.unsubscribe();
427
+ if (this.unsubscribe) {
428
+ this.unsubscribe();
429
+ }
373
430
  this.unsubscribe = on("register", () => this.detectWallets());
374
431
  for (const wallet of aptosWallets) {
375
432
  const normalizedName = wallet.name.toLowerCase();
@@ -385,21 +442,42 @@ var WalletManager = class extends import_eventemitter3.default {
385
442
  this.detectedWallets = Array.from(available);
386
443
  return this.detectedWallets;
387
444
  }
445
+ /**
446
+ * Gets detailed wallet information for UI display
447
+ * @returns Array of wallet info objects
448
+ */
388
449
  getWalletInfo() {
389
450
  return this.detectedWallets.map((type) => {
390
451
  const wallet = this.standardWallets.get(type);
391
- return { type, name: wallet?.name || type, icon: wallet?.icon || "" };
452
+ return {
453
+ type,
454
+ name: wallet?.name || type,
455
+ icon: wallet?.icon || ""
456
+ };
392
457
  });
393
458
  }
459
+ /**
460
+ * Connects to a wallet
461
+ * @param wallet - Wallet type to connect to
462
+ * @throws MovementError if wallet not found or connection fails
463
+ */
394
464
  async connect(wallet) {
395
465
  const available = this.detectWallets();
396
- if (!available.includes(wallet)) throw Errors.walletNotFound(wallet, available);
466
+ if (!available.includes(wallet)) {
467
+ throw Errors.walletNotFound(wallet, available);
468
+ }
397
469
  try {
398
470
  const standardWallet = this.standardWallets.get(wallet);
399
- if (!standardWallet) throw new Error(`Wallet ${wallet} not found`);
471
+ if (!standardWallet) {
472
+ throw new Error(`Wallet ${wallet} not found`);
473
+ }
400
474
  this.adapter = createStandardAdapter(standardWallet);
401
475
  const result = await this.adapter.connect();
402
- this.state = { connected: true, address: result.address, publicKey: result.publicKey };
476
+ this.state = {
477
+ connected: true,
478
+ address: result.address,
479
+ publicKey: result.publicKey
480
+ };
403
481
  this.currentWallet = wallet;
404
482
  this.saveLastWallet(wallet);
405
483
  this.setupEventListeners();
@@ -409,6 +487,9 @@ var WalletManager = class extends import_eventemitter3.default {
409
487
  throw Errors.walletConnectionFailed(wallet, error);
410
488
  }
411
489
  }
490
+ /**
491
+ * Disconnects from the current wallet
492
+ */
412
493
  async disconnect() {
413
494
  if (this.adapter) {
414
495
  try {
@@ -422,15 +503,28 @@ var WalletManager = class extends import_eventemitter3.default {
422
503
  this.clearLastWallet();
423
504
  this.emit("disconnect");
424
505
  }
506
+ /**
507
+ * Gets the current wallet state
508
+ */
425
509
  getState() {
426
510
  return { ...this.state };
427
511
  }
512
+ /**
513
+ * Gets the currently connected wallet type
514
+ */
428
515
  getWallet() {
429
516
  return this.currentWallet;
430
517
  }
518
+ /**
519
+ * Gets the wallet adapter for direct access
520
+ * @internal
521
+ */
431
522
  getAdapter() {
432
523
  return this.adapter;
433
524
  }
525
+ /**
526
+ * Attempts to auto-connect to the last used wallet
527
+ */
434
528
  async autoConnect() {
435
529
  const lastWallet = this.getLastWallet();
436
530
  if (!lastWallet) return;
@@ -443,6 +537,9 @@ var WalletManager = class extends import_eventemitter3.default {
443
537
  }
444
538
  }
445
539
  }
540
+ /**
541
+ * Cleans up resources
542
+ */
446
543
  destroy() {
447
544
  if (this.unsubscribe) {
448
545
  this.unsubscribe();
@@ -453,18 +550,26 @@ var WalletManager = class extends import_eventemitter3.default {
453
550
  if (!this.adapter) return;
454
551
  this.adapter.onAccountChange((account) => {
455
552
  if (account) {
456
- this.state = { connected: true, address: account.address, publicKey: account.publicKey };
553
+ this.state = {
554
+ connected: true,
555
+ address: account.address,
556
+ publicKey: account.publicKey
557
+ };
457
558
  this.emit("accountChanged", account.address);
458
559
  } else {
459
560
  this.state = { connected: false, address: null, publicKey: null };
460
561
  this.emit("disconnect");
461
562
  }
462
563
  });
463
- this.adapter.onNetworkChange((network) => this.emit("networkChanged", network));
564
+ this.adapter.onNetworkChange((network) => {
565
+ this.emit("networkChanged", network);
566
+ });
464
567
  }
465
568
  saveLastWallet(wallet) {
466
569
  try {
467
- if (typeof localStorage !== "undefined") localStorage.setItem(STORAGE_KEY, wallet);
570
+ if (typeof localStorage !== "undefined") {
571
+ localStorage.setItem(STORAGE_KEY, wallet);
572
+ }
468
573
  } catch {
469
574
  }
470
575
  }
@@ -482,7 +587,9 @@ var WalletManager = class extends import_eventemitter3.default {
482
587
  }
483
588
  clearLastWallet() {
484
589
  try {
485
- if (typeof localStorage !== "undefined") localStorage.removeItem(STORAGE_KEY);
590
+ if (typeof localStorage !== "undefined") {
591
+ localStorage.removeItem(STORAGE_KEY);
592
+ }
486
593
  } catch {
487
594
  }
488
595
  }
@@ -496,98 +603,50 @@ var TransactionBuilder = class {
496
603
  }
497
604
  /**
498
605
  * Builds a transfer transaction payload
606
+ * Uses 0x1::aptos_account::transfer which handles account creation
499
607
  * @param options - Transfer options
500
- * @returns Transaction payload
608
+ * @returns Transaction payload ready for signing
501
609
  */
502
610
  async transfer(options) {
503
- const coinType = options.coinType ?? DEFAULT_COIN_TYPE;
504
611
  return {
505
- type: "entry_function_payload",
506
- function: "0x1::coin::transfer",
507
- typeArguments: [coinType],
508
- arguments: [options.to, options.amount]
612
+ function: "0x1::aptos_account::transfer",
613
+ typeArguments: [],
614
+ functionArguments: [options.to, options.amount]
509
615
  };
510
616
  }
511
617
  /**
512
618
  * Builds a generic transaction payload
513
- * @param options - Build options
514
- * @returns Transaction payload
619
+ * @param options - Build options with function, typeArguments, and arguments
620
+ * @returns Transaction payload ready for signing
515
621
  */
516
622
  async build(options) {
517
623
  return {
518
- type: "entry_function_payload",
519
624
  function: options.function,
520
625
  typeArguments: options.typeArguments,
521
- arguments: options.arguments
626
+ functionArguments: options.arguments
522
627
  };
523
628
  }
524
- /**
525
- * Signs a transaction payload
526
- * @param payload - Transaction payload to sign
527
- * @returns Signed transaction
528
- * @throws MovementError with code WALLET_NOT_CONNECTED if no wallet is connected
529
- */
530
- async sign(payload) {
531
- const adapter = this.walletManager.getAdapter();
532
- const state = this.walletManager.getState();
533
- if (!adapter || !state.connected || !state.address) {
534
- throw Errors.walletNotConnected();
535
- }
536
- try {
537
- const signatureBytes = await adapter.signTransaction({
538
- type: payload.type,
539
- function: payload.function,
540
- type_arguments: payload.typeArguments,
541
- arguments: payload.arguments
542
- });
543
- const signature = Array.from(signatureBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
544
- return {
545
- payload,
546
- signature: `0x${signature}`,
547
- sender: state.address
548
- };
549
- } catch (error) {
550
- throw wrapError(error, "TRANSACTION_FAILED", "Failed to sign transaction");
551
- }
552
- }
553
- /**
554
- * Submits a signed transaction to the network
555
- * @param signed - Signed transaction
556
- * @returns Transaction hash
557
- */
558
- async submit(signed) {
559
- const adapter = this.walletManager.getAdapter();
560
- if (!adapter) {
561
- throw Errors.walletNotConnected();
562
- }
563
- try {
564
- const result = await adapter.signAndSubmitTransaction({
565
- type: signed.payload.type,
566
- function: signed.payload.function,
567
- type_arguments: signed.payload.typeArguments,
568
- arguments: signed.payload.arguments
569
- });
570
- return result.hash;
571
- } catch (error) {
572
- throw wrapError(error, "TRANSACTION_FAILED", "Failed to submit transaction");
573
- }
574
- }
575
629
  /**
576
630
  * Signs and submits a transaction in one step
631
+ * This is the recommended method for most use cases
577
632
  * @param payload - Transaction payload
578
633
  * @returns Transaction hash
634
+ * @throws MovementError with code WALLET_NOT_CONNECTED if no wallet connected
635
+ * @throws MovementError with code TRANSACTION_FAILED if submission fails
579
636
  */
580
637
  async signAndSubmit(payload) {
581
638
  const adapter = this.walletManager.getAdapter();
582
- if (!adapter) {
639
+ const state = this.walletManager.getState();
640
+ if (!adapter || !state.connected) {
583
641
  throw Errors.walletNotConnected();
584
642
  }
585
643
  try {
586
644
  const result = await adapter.signAndSubmitTransaction({
587
- type: payload.type,
588
- function: payload.function,
589
- type_arguments: payload.typeArguments,
590
- arguments: payload.arguments
645
+ payload: {
646
+ function: payload.function,
647
+ typeArguments: payload.typeArguments,
648
+ functionArguments: payload.functionArguments
649
+ }
591
650
  });
592
651
  return result.hash;
593
652
  } catch (error) {
@@ -596,8 +655,9 @@ var TransactionBuilder = class {
596
655
  }
597
656
  /**
598
657
  * Simulates a transaction without submitting
658
+ * Useful for gas estimation and checking if transaction will succeed
599
659
  * @param payload - Transaction payload
600
- * @returns Simulation result with gas estimate
660
+ * @returns Simulation result with success status and gas estimate
601
661
  */
602
662
  async simulate(payload) {
603
663
  const state = this.walletManager.getState();
@@ -605,16 +665,17 @@ var TransactionBuilder = class {
605
665
  throw Errors.walletNotConnected();
606
666
  }
607
667
  try {
608
- const client = this.aptosClient;
609
- const result = await client.transaction.simulate.simple({
668
+ const transaction = await this.aptosClient.transaction.build.simple({
610
669
  sender: state.address,
611
670
  data: {
612
671
  function: payload.function,
613
672
  typeArguments: payload.typeArguments,
614
- functionArguments: payload.arguments
673
+ functionArguments: payload.functionArguments
615
674
  }
616
675
  });
617
- const simResult = result[0];
676
+ const [simResult] = await this.aptosClient.transaction.simulate.simple({
677
+ transaction
678
+ });
618
679
  return {
619
680
  success: simResult?.success ?? false,
620
681
  gasUsed: String(simResult?.gas_used ?? "0"),
@@ -624,6 +685,15 @@ var TransactionBuilder = class {
624
685
  throw wrapError(error, "TRANSACTION_FAILED", "Failed to simulate transaction");
625
686
  }
626
687
  }
688
+ /**
689
+ * Convenience method: Transfer and wait for confirmation
690
+ * @param options - Transfer options
691
+ * @returns Transaction hash
692
+ */
693
+ async transferAndSubmit(options) {
694
+ const payload = await this.transfer(options);
695
+ return this.signAndSubmit(payload);
696
+ }
627
697
  };
628
698
 
629
699
  // src/contract.ts
@@ -640,17 +710,27 @@ var ContractInterface = class {
640
710
  module;
641
711
  /**
642
712
  * Calls a view function (read-only)
713
+ * View functions don't require a wallet connection
714
+ *
643
715
  * @param functionName - Name of the view function
644
716
  * @param args - Function arguments
645
- * @param typeArgs - Type arguments (optional)
717
+ * @param typeArgs - Type arguments for generic functions
646
718
  * @returns Function result
647
719
  * @throws MovementError with code VIEW_FUNCTION_FAILED if call fails
720
+ *
721
+ * @example
722
+ * ```typescript
723
+ * // Get coin balance
724
+ * const balance = await contract.view('balance', [address], ['0x1::aptos_coin::AptosCoin']);
725
+ *
726
+ * // Check if account exists
727
+ * const exists = await contract.view('exists_at', [address]);
728
+ * ```
648
729
  */
649
- async view(functionName, args, typeArgs = []) {
730
+ async view(functionName, args = [], typeArgs = []) {
650
731
  const fullFunctionName = `${this.address}::${this.module}::${functionName}`;
651
732
  try {
652
- const client = this.aptosClient;
653
- const result = await client.view({
733
+ const result = await this.aptosClient.view({
654
734
  payload: {
655
735
  function: fullFunctionName,
656
736
  typeArguments: typeArgs,
@@ -664,14 +744,25 @@ var ContractInterface = class {
664
744
  }
665
745
  /**
666
746
  * Calls an entry function (write operation)
747
+ * Requires a connected wallet
748
+ *
667
749
  * @param functionName - Name of the entry function
668
750
  * @param args - Function arguments
669
- * @param typeArgs - Type arguments (optional)
751
+ * @param typeArgs - Type arguments for generic functions
670
752
  * @returns Transaction hash
671
- * @throws MovementError with code WALLET_NOT_CONNECTED if no wallet is connected
753
+ * @throws MovementError with code WALLET_NOT_CONNECTED if no wallet connected
672
754
  * @throws MovementError with code TRANSACTION_FAILED if transaction fails
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * // Transfer coins
759
+ * const txHash = await contract.call('transfer', [recipient, amount], ['0x1::aptos_coin::AptosCoin']);
760
+ *
761
+ * // Call a custom function
762
+ * const txHash = await contract.call('increment', []);
763
+ * ```
673
764
  */
674
- async call(functionName, args, typeArgs = []) {
765
+ async call(functionName, args = [], typeArgs = []) {
675
766
  const adapter = this.walletManager.getAdapter();
676
767
  const state = this.walletManager.getState();
677
768
  if (!adapter || !state.connected) {
@@ -680,10 +771,11 @@ var ContractInterface = class {
680
771
  const fullFunctionName = `${this.address}::${this.module}::${functionName}`;
681
772
  try {
682
773
  const result = await adapter.signAndSubmitTransaction({
683
- type: "entry_function_payload",
684
- function: fullFunctionName,
685
- type_arguments: typeArgs,
686
- arguments: args
774
+ payload: {
775
+ function: fullFunctionName,
776
+ typeArguments: typeArgs,
777
+ functionArguments: args
778
+ }
687
779
  });
688
780
  return result.hash;
689
781
  } catch (error) {
@@ -692,13 +784,17 @@ var ContractInterface = class {
692
784
  }
693
785
  /**
694
786
  * Checks if a resource exists at the contract address
695
- * @param resourceType - Full resource type (e.g., '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>')
787
+ * @param resourceType - Full resource type
696
788
  * @returns true if resource exists
789
+ *
790
+ * @example
791
+ * ```typescript
792
+ * const hasCoin = await contract.hasResource('0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>');
793
+ * ```
697
794
  */
698
795
  async hasResource(resourceType) {
699
796
  try {
700
- const client = this.aptosClient;
701
- await client.getAccountResource({
797
+ await this.aptosClient.getAccountResource({
702
798
  accountAddress: this.address,
703
799
  resourceType
704
800
  });
@@ -711,11 +807,17 @@ var ContractInterface = class {
711
807
  * Gets a resource from the contract address
712
808
  * @param resourceType - Full resource type
713
809
  * @returns Resource data or null if not found
810
+ *
811
+ * @example
812
+ * ```typescript
813
+ * const coinStore = await contract.getResource<{ coin: { value: string } }>(
814
+ * '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>'
815
+ * );
816
+ * ```
714
817
  */
715
818
  async getResource(resourceType) {
716
819
  try {
717
- const client = this.aptosClient;
718
- const resource = await client.getAccountResource({
820
+ const resource = await this.aptosClient.getAccountResource({
719
821
  accountAddress: this.address,
720
822
  resourceType
721
823
  });
@@ -744,29 +846,60 @@ var EventListener = class {
744
846
  subscriptionCounter = 0;
745
847
  pollIntervalMs;
746
848
  /**
747
- * Subscribes to contract events
849
+ * Subscribes to blockchain events
850
+ * Supports both new format (accountAddress + eventType) and legacy format (eventHandle)
851
+ *
748
852
  * @param subscription - Subscription configuration
749
- * @returns Subscription ID
750
- * @throws MovementError with code INVALID_EVENT_HANDLE if event handle is invalid
853
+ * @returns Subscription ID for unsubscribing
854
+ *
855
+ * @example
856
+ * ```typescript
857
+ * // New format (recommended)
858
+ * const subId = events.subscribe({
859
+ * accountAddress: '0x1',
860
+ * eventType: '0x1::coin::DepositEvent',
861
+ * callback: (event) => console.log(event),
862
+ * });
863
+ *
864
+ * // Legacy format (backward compatible)
865
+ * const subId = events.subscribe({
866
+ * eventHandle: '0x1::coin::DepositEvent',
867
+ * callback: (event) => console.log(event),
868
+ * });
869
+ * ```
751
870
  */
752
871
  subscribe(subscription) {
753
- if (!isValidEventHandle(subscription.eventHandle)) {
754
- throw Errors.invalidEventHandle(subscription.eventHandle);
755
- }
756
872
  const subscriptionId = `sub_${++this.subscriptionCounter}`;
873
+ let accountAddress;
874
+ let eventType;
875
+ if ("accountAddress" in subscription) {
876
+ accountAddress = subscription.accountAddress;
877
+ eventType = subscription.eventType;
878
+ } else {
879
+ const parts = subscription.eventHandle.split("::");
880
+ if (parts.length >= 3 && parts[0]) {
881
+ accountAddress = parts[0];
882
+ eventType = subscription.eventHandle;
883
+ } else {
884
+ accountAddress = subscription.eventHandle;
885
+ eventType = subscription.eventHandle;
886
+ }
887
+ }
757
888
  const internalSub = {
758
- eventHandle: subscription.eventHandle,
889
+ accountAddress,
890
+ eventType,
759
891
  callback: subscription.callback,
760
- lastSequenceNumber: "0",
892
+ lastSequenceNumber: BigInt(-1),
893
+ // Start at -1 to catch all events
761
894
  intervalId: null
762
895
  };
896
+ this.subscriptions.set(subscriptionId, internalSub);
763
897
  internalSub.intervalId = setInterval(() => {
764
898
  this.pollEvents(subscriptionId).catch(() => {
765
899
  });
766
900
  }, this.pollIntervalMs);
767
901
  this.pollEvents(subscriptionId).catch(() => {
768
902
  });
769
- this.subscriptions.set(subscriptionId, internalSub);
770
903
  return subscriptionId;
771
904
  }
772
905
  /**
@@ -778,6 +911,7 @@ var EventListener = class {
778
911
  if (subscription) {
779
912
  if (subscription.intervalId) {
780
913
  clearInterval(subscription.intervalId);
914
+ subscription.intervalId = null;
781
915
  }
782
916
  this.subscriptions.delete(subscriptionId);
783
917
  }
@@ -806,8 +940,8 @@ var EventListener = class {
806
940
  return this.subscriptions.has(subscriptionId);
807
941
  }
808
942
  /**
809
- * Polls for new events
810
- * @param subscriptionId - Subscription ID
943
+ * Polls for new events for a subscription
944
+ * @internal
811
945
  */
812
946
  async pollEvents(subscriptionId) {
813
947
  const subscription = this.subscriptions.get(subscriptionId);
@@ -815,29 +949,31 @@ var EventListener = class {
815
949
  return;
816
950
  }
817
951
  try {
818
- const parts = subscription.eventHandle.split("::");
819
- if (parts.length !== 3) {
820
- return;
821
- }
822
- const [address, module2, eventType] = parts;
823
- const eventHandleStruct = `${address}::${module2}::${eventType}`;
824
- const client = this.aptosClient;
825
- const events = await client.getAccountEventsByEventType({
826
- accountAddress: address,
827
- eventType: eventHandleStruct,
952
+ const events = await this.aptosClient.getAccountEventsByEventType({
953
+ accountAddress: subscription.accountAddress,
954
+ eventType: subscription.eventType,
828
955
  options: {
829
- limit: 25
956
+ limit: 25,
957
+ orderBy: [{ sequence_number: "desc" }]
830
958
  }
831
959
  });
832
- for (const event of events) {
833
- const sequenceNumber = event.sequence_number?.toString() ?? "0";
834
- if (BigInt(sequenceNumber) > BigInt(subscription.lastSequenceNumber)) {
960
+ const sortedEvents = [...events].sort((a, b) => {
961
+ const seqA = BigInt(a.sequence_number);
962
+ const seqB = BigInt(b.sequence_number);
963
+ return seqA < seqB ? -1 : seqA > seqB ? 1 : 0;
964
+ });
965
+ for (const event of sortedEvents) {
966
+ const sequenceNumber = BigInt(event.sequence_number);
967
+ if (sequenceNumber > subscription.lastSequenceNumber) {
835
968
  const contractEvent = {
836
969
  type: event.type,
837
- sequenceNumber,
970
+ sequenceNumber: String(event.sequence_number),
838
971
  data: event.data
839
972
  };
840
- subscription.callback(contractEvent);
973
+ try {
974
+ subscription.callback(contractEvent);
975
+ } catch {
976
+ }
841
977
  subscription.lastSequenceNumber = sequenceNumber;
842
978
  }
843
979
  }
@@ -953,10 +1089,9 @@ var Movement = class {
953
1089
  sender: userTx.sender,
954
1090
  sequenceNumber: userTx.sequence_number,
955
1091
  payload: {
956
- type: "entry_function_payload",
957
1092
  function: userTx.payload?.function ?? "",
958
1093
  typeArguments: userTx.payload?.type_arguments ?? [],
959
- arguments: userTx.payload?.arguments ?? []
1094
+ functionArguments: userTx.payload?.arguments ?? []
960
1095
  },
961
1096
  timestamp: userTx.timestamp
962
1097
  };