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