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