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