@msafe/sui3-sdk 1.0.7 → 1.0.8

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.cjs CHANGED
@@ -63,6 +63,7 @@ __export(src_exports, {
63
63
  getAllCoins: () => getAllCoins,
64
64
  getMSafeConfig: () => getMSafeConfig,
65
65
  getPublicKeyFromChain: () => getPublicKeyFromChain,
66
+ httpUrlToGrpcBaseUrl: () => httpUrlToGrpcBaseUrl,
66
67
  msafeChainToSuiNetwork: () => msafeChainToSuiNetwork,
67
68
  stringToBuffer: () => stringToBuffer,
68
69
  toSuiTransaction: () => toSuiTransaction
@@ -221,6 +222,23 @@ var import_wallet_standard = require("@mysten/wallet-standard");
221
222
  // src/simulate/simulator.ts
222
223
  var import_transactions = require("@mysten/sui/transactions");
223
224
  var GAS_SAFE_OVERHEAD = 1000n;
225
+ function formatExecutionError(error) {
226
+ return error.message;
227
+ }
228
+ __name(formatExecutionError, "formatExecutionError");
229
+ function gasObjectToReference(gas) {
230
+ if (!gas?.objectId) {
231
+ throw new Error("Gas object missing from simulation effects");
232
+ }
233
+ const version = gas.outputVersion ?? gas.inputVersion ?? "0";
234
+ const digest = gas.outputDigest ?? gas.inputDigest ?? "";
235
+ return {
236
+ objectId: gas.objectId,
237
+ version,
238
+ digest
239
+ };
240
+ }
241
+ __name(gasObjectToReference, "gasObjectToReference");
224
242
  var Simulator = class {
225
243
  static {
226
244
  __name(this, "Simulator");
@@ -234,32 +252,63 @@ var Simulator = class {
234
252
  const { suiClient } = this.globals;
235
253
  const gasPrice = await this.getGasPrice();
236
254
  tx.setGasPrice(gasPrice);
237
- const inspectResult = await suiClient.dryRunTransactionBlock({
238
- transactionBlock: await tx.build({
255
+ let built;
256
+ try {
257
+ built = await tx.build({
239
258
  client: suiClient
240
- })
241
- });
242
- const success = inspectResult.effects.status.status === "success";
259
+ });
260
+ } catch (e) {
261
+ const message = e instanceof Error ? e.message : String(e);
262
+ return {
263
+ success: false,
264
+ gasPrice,
265
+ simulationError: message
266
+ };
267
+ }
268
+ let inspectResult;
269
+ try {
270
+ inspectResult = await suiClient.simulateTransaction({
271
+ transaction: built,
272
+ include: {
273
+ effects: true
274
+ }
275
+ });
276
+ } catch (e) {
277
+ const message = e instanceof Error ? e.message : String(e);
278
+ return {
279
+ success: false,
280
+ gasPrice,
281
+ simulationError: message
282
+ };
283
+ }
284
+ const txRow = inspectResult.Transaction ?? inspectResult.FailedTransaction;
285
+ const { effects } = txRow;
286
+ if (!effects) {
287
+ throw new Error("simulateTransaction did not return effects");
288
+ }
289
+ const success = effects.status.success === true;
243
290
  if (!success) {
291
+ const err = effects.status.success === false ? effects.status.error : null;
244
292
  return {
245
293
  success,
246
294
  gasPrice,
247
295
  response: inspectResult,
248
- simulationError: inspectResult.effects.status.error
296
+ simulationError: err ? formatExecutionError(err) : "Simulation failed"
249
297
  };
250
298
  }
251
- const gasBudget = this.toGasBudget(inspectResult.effects.gasUsed, gasPrice);
299
+ const gasBudget = this.toGasBudget(effects.gasUsed, gasPrice);
252
300
  return {
253
301
  success,
254
302
  gasPrice,
255
- gasObject: inspectResult.effects.gasObject.reference,
256
- gasUsed: inspectResult.effects.gasUsed,
303
+ gasObject: gasObjectToReference(effects.gasObject),
304
+ gasUsed: effects.gasUsed,
257
305
  gasBudget,
258
306
  response: inspectResult
259
307
  };
260
308
  }
261
309
  async getGasPrice() {
262
- return this.globals.suiClient.getReferenceGasPrice();
310
+ const { referenceGasPrice } = await this.globals.suiClient.getReferenceGasPrice();
311
+ return BigInt(referenceGasPrice);
263
312
  }
264
313
  toGasBudget(gasUsed, gasPrice) {
265
314
  const { computationCost, storageCost, storageRebate } = gasUsed;
@@ -321,7 +370,7 @@ var CoinHelper = class {
321
370
  const res = await this._client.getCoinMetadata({
322
371
  coinType
323
372
  });
324
- return res || void 0;
373
+ return res.coinMetadata ?? void 0;
325
374
  }
326
375
  };
327
376
  var COIN_TYPE_ARG_REGEX = /^0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<(.+)>$/;
@@ -343,6 +392,13 @@ var Coin = class _Coin {
343
392
  if (!_Coin.isCoin(data.type)) {
344
393
  return void 0;
345
394
  }
395
+ if (data.json && typeof data.json === "object" && "balance" in data.json) {
396
+ const { balance: balance2 } = data.json;
397
+ if (balance2 === void 0) {
398
+ return void 0;
399
+ }
400
+ return BigInt(balance2);
401
+ }
346
402
  if (data.content?.dataType !== "moveObject") {
347
403
  return void 0;
348
404
  }
@@ -428,29 +484,82 @@ var SignatureVerifier = class _SignatureVerifier {
428
484
  // src/utils/sui.ts
429
485
  var import_sui3_utils3 = require("@msafe/sui3-utils");
430
486
  var import_cryptography = require("@mysten/sui/cryptography");
487
+ var import_graphql = require("@mysten/sui/graphql");
431
488
  var import_multisig = require("@mysten/sui/multisig");
432
489
  var SUI_COIN = "0x2::sui::SUI";
490
+ var GRAPHQL_URL_BY_NETWORK = {
491
+ mainnet: "https://sui-mainnet.mystenlabs.com/graphql",
492
+ testnet: "https://sui-testnet.mystenlabs.com/graphql",
493
+ devnet: "https://sui-devnet.mystenlabs.com/graphql"
494
+ };
495
+ function graphqlClientForGrpc(suiClient) {
496
+ const url = GRAPHQL_URL_BY_NETWORK[suiClient.network] ?? GRAPHQL_URL_BY_NETWORK.testnet;
497
+ return new import_graphql.SuiGraphQLClient({
498
+ url,
499
+ network: suiClient.network
500
+ });
501
+ }
502
+ __name(graphqlClientForGrpc, "graphqlClientForGrpc");
503
+ function collectSignatureStrings(value) {
504
+ if (typeof value === "string") {
505
+ return [
506
+ value
507
+ ];
508
+ }
509
+ if (!value || typeof value !== "object") {
510
+ return [];
511
+ }
512
+ if ("base64" in value && typeof value.base64 === "string") {
513
+ return [
514
+ value.base64
515
+ ];
516
+ }
517
+ if ("scheme" in value && "base64" in value) {
518
+ const b64 = value.base64;
519
+ return typeof b64 === "string" ? [
520
+ b64
521
+ ] : [];
522
+ }
523
+ return [];
524
+ }
525
+ __name(collectSignatureStrings, "collectSignatureStrings");
526
+ var TX_SIG_QUERY = `
527
+ query PublicKeyTxSigs($sender: SuiAddress!, $first: Int!) {
528
+ transactions(first: $first, filter: { sentAddress: $sender }) {
529
+ nodes {
530
+ signatures
531
+ }
532
+ }
533
+ }
534
+ `;
433
535
  async function getPublicKeyFromChain(suiClient, address) {
536
+ const graphql = graphqlClientForGrpc(suiClient);
434
537
  let txs;
435
538
  try {
436
- txs = await suiClient.queryTransactionBlocks({
437
- // Disable naming rule since the variable is defined by Mysten
438
- filter: {
439
- FromAddress: address
440
- },
441
- options: {
442
- showInput: true
443
- },
444
- limit: 2
539
+ const res = await graphql.query({
540
+ query: TX_SIG_QUERY,
541
+ variables: {
542
+ sender: address,
543
+ first: 2
544
+ }
445
545
  });
546
+ if (res.errors?.length) {
547
+ return void 0;
548
+ }
549
+ txs = res.data ?? {};
446
550
  } catch (e) {
447
551
  return void 0;
448
552
  }
449
- if (txs.data.length === 0 || !txs.data[0].transaction?.txSignatures) {
553
+ const nodes = txs.transactions?.nodes ?? [];
554
+ if (nodes.length === 0) {
555
+ return void 0;
556
+ }
557
+ const first = nodes[0];
558
+ const rawSigs = first.signatures;
559
+ const signatures = Array.isArray(rawSigs) ? rawSigs.flatMap((item) => collectSignatureStrings(item)) : [];
560
+ if (signatures.length === 0) {
450
561
  return void 0;
451
562
  }
452
- const tx = txs.data[0];
453
- const signatures = tx.transaction?.txSignatures;
454
563
  for (let i = 0; i !== signatures.length; i++) {
455
564
  const serializedSig = signatures[i];
456
565
  const pk = getAddressFromSignatures(serializedSig, address);
@@ -495,14 +604,14 @@ async function getAllCoins(input) {
495
604
  let cursor;
496
605
  const res = [];
497
606
  while (hasNext) {
498
- const currentPage = await input.suiClient.getCoins({
607
+ const currentPage = await input.suiClient.listCoins({
499
608
  owner: input.owner,
500
609
  coinType: input.coinType,
501
610
  cursor
502
611
  });
503
- res.push(...currentPage.data);
612
+ res.push(...currentPage.objects);
504
613
  hasNext = currentPage.hasNextPage;
505
- cursor = currentPage.nextCursor;
614
+ cursor = currentPage.cursor;
506
615
  }
507
616
  return res;
508
617
  }
@@ -604,6 +713,16 @@ var EntryIterator = class {
604
713
  };
605
714
 
606
715
  // src/utils/iter/object.ts
716
+ var defaultObjectInclude = {
717
+ json: true
718
+ };
719
+ function mergeInclude(options) {
720
+ return {
721
+ ...defaultObjectInclude,
722
+ ...options?.objectInclude
723
+ };
724
+ }
725
+ __name(mergeInclude, "mergeInclude");
607
726
  async function getAllOwnedObjects(provider, owner, options) {
608
727
  const iter = new OwnedObjectIterator(provider, owner, options);
609
728
  return await getAllFromIterator(iter);
@@ -633,7 +752,7 @@ var OwnedObjectRequester = class {
633
752
  nextCursor;
634
753
  filter;
635
754
  pageSize;
636
- objectOptions;
755
+ objectInclude;
637
756
  constructor(provider, owner, options) {
638
757
  this.provider = provider;
639
758
  this.owner = owner;
@@ -641,28 +760,25 @@ var OwnedObjectRequester = class {
641
760
  this.nextCursor = null;
642
761
  this.filter = options?.filter;
643
762
  this.pageSize = options?.pageSize || REQUEST_PAGE_SIZE;
644
- this.objectOptions = options?.objectOptions || {
645
- showType: true,
646
- showContent: true
647
- };
763
+ this.objectInclude = mergeInclude(options);
648
764
  }
649
765
  async doNextRequest() {
650
- const res = await this.provider.getOwnedObjects({
766
+ const res = await this.provider.listOwnedObjects({
651
767
  owner: this.owner,
652
- options: this.objectOptions,
768
+ include: this.objectInclude,
653
769
  cursor: this.nextCursor,
654
770
  limit: this.pageSize
655
771
  });
656
- this.nextCursor = res.nextCursor;
772
+ this.nextCursor = res.cursor;
657
773
  let filtered;
658
774
  if (this.filter) {
659
775
  const { filter } = this;
660
- filtered = res.data.filter((obj) => filter?.(obj));
776
+ filtered = res.objects.filter((obj) => filter(obj));
661
777
  } else {
662
- filtered = res.data;
778
+ filtered = res.objects;
663
779
  }
664
780
  return {
665
- data: filtered.map((r) => r.data).filter((data) => data),
781
+ data: filtered,
666
782
  hasNext: res.hasNextPage
667
783
  };
668
784
  }
@@ -697,23 +813,31 @@ var MSafeAccount = class _MSafeAccount {
697
813
  }
698
814
  }
699
815
  async ownedCoins() {
700
- const balances = await this.suiClient.getAllBalances({
701
- owner: this.address
702
- });
816
+ const balances = [];
817
+ let cursor = null;
818
+ let hasNext = true;
819
+ while (hasNext) {
820
+ const page = await this.suiClient.listBalances({
821
+ owner: this.address,
822
+ cursor,
823
+ limit: 50
824
+ });
825
+ balances.push(...page.balances);
826
+ hasNext = page.hasNextPage;
827
+ cursor = page.cursor;
828
+ }
703
829
  return Promise.all(balances.map(async (balance) => {
704
830
  const meta = await this.coinHelper.getCoinMeta(balance.coinType);
705
- const lockedEntry = balance.lockedBalance && typeof balance.lockedBalance === "object" && "number" in balance.lockedBalance && balance.lockedBalance.number ? BigInt(balance.lockedBalance.number) : 0n;
706
- const unlockedBalance = lockedEntry ? BigInt(balance.totalBalance) - lockedEntry : BigInt(balance.totalBalance);
707
831
  return {
708
832
  type: (0, import_utils3.normalizeStructTag)(balance.coinType),
709
- balance: unlockedBalance,
833
+ balance: BigInt(balance.addressBalance),
710
834
  metadata: meta
711
835
  };
712
836
  }));
713
837
  }
714
838
  async ownedObjects(options) {
715
839
  const filterCoinObjectOptions = {
716
- filter: (objRes) => !objRes?.data?.type?.startsWith("0x2::coin::Coin"),
840
+ filter: (obj) => !obj?.type?.startsWith("0x2::coin::Coin"),
717
841
  ...options
718
842
  };
719
843
  return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
@@ -1034,12 +1158,14 @@ var MSafeAccount = class _MSafeAccount {
1034
1158
  }
1035
1159
  }
1036
1160
  const multiSignature = this.multiSig.combinePartialSignatures(sortedSigs);
1037
- return this.suiClient.executeTransactionBlock({
1038
- transactionBlock: HexToUint8Array(payload),
1039
- signature: multiSignature,
1040
- options: {
1041
- showEffects: true,
1042
- showEvents: true
1161
+ return this.suiClient.executeTransaction({
1162
+ transaction: HexToUint8Array(payload),
1163
+ signatures: [
1164
+ multiSignature
1165
+ ],
1166
+ include: {
1167
+ effects: true,
1168
+ events: true
1043
1169
  }
1044
1170
  });
1045
1171
  }
@@ -1174,7 +1300,7 @@ var ReportSDK = class {
1174
1300
  };
1175
1301
 
1176
1302
  // src/globals/MSafeGlobals.ts
1177
- var import_jsonRpc = require("@mysten/sui/jsonRpc");
1303
+ var import_grpc = require("@mysten/sui/grpc");
1178
1304
 
1179
1305
  // src/backend/BackendImpl.ts
1180
1306
  var import_sui3_utils6 = require("@msafe/sui3-utils");
@@ -1531,6 +1657,17 @@ var MSafeEnv;
1531
1657
  MSafeEnv2["prev"] = "prev";
1532
1658
  MSafeEnv2["prod"] = "prod";
1533
1659
  })(MSafeEnv || (MSafeEnv = {}));
1660
+ function httpUrlToGrpcBaseUrl(url) {
1661
+ const parsed = new URL(url);
1662
+ if (parsed.protocol === "https:" && parsed.port === "") {
1663
+ return `https://${parsed.hostname}:443${parsed.pathname}${parsed.search}`;
1664
+ }
1665
+ if (parsed.protocol === "http:" && parsed.port === "") {
1666
+ return `http://${parsed.hostname}:80${parsed.pathname}${parsed.search}`;
1667
+ }
1668
+ return `${parsed.origin}${parsed.pathname}${parsed.search}`;
1669
+ }
1670
+ __name(httpUrlToGrpcBaseUrl, "httpUrlToGrpcBaseUrl");
1534
1671
  var TESTNET_RPC_URL = "https://fullnode.testnet.sui.io";
1535
1672
  var MAINNET_RPC_URL = "https://fullnode.mainnet.sui.io";
1536
1673
  var LOCAL_API_URL = "http://127.0.0.1:3000";
@@ -1547,9 +1684,9 @@ var ENV_CONFIGS = /* @__PURE__ */ new Map([
1547
1684
  url: TESTNET_RPC_URL
1548
1685
  },
1549
1686
  backend: {
1550
- url: LOCAL_API_URL
1687
+ url: DEV_API_URL
1551
1688
  },
1552
- syncingURL: LOCAL_SYNCING_URL,
1689
+ syncingURL: DEV_SYNCING_URL,
1553
1690
  network: "sui:testnet"
1554
1691
  }
1555
1692
  ],
@@ -1640,12 +1777,11 @@ var MSafeGlobals = class _MSafeGlobals {
1640
1777
  }
1641
1778
  static async New(env, options) {
1642
1779
  const config = getMSafeConfig(env, options);
1643
- const suiClient = new import_jsonRpc.SuiJsonRpcClient({
1644
- ...config.suiClient.transport ? {
1645
- transport: config.suiClient.transport
1646
- } : {
1647
- url: config.suiClient.url
1648
- },
1780
+ const suiClient = config.suiClient.transport ? new import_grpc.SuiGrpcClient({
1781
+ transport: config.suiClient.transport,
1782
+ network: msafeChainToSuiNetwork(config.network)
1783
+ }) : new import_grpc.SuiGrpcClient({
1784
+ baseUrl: httpUrlToGrpcBaseUrl(config.suiClient.url),
1649
1785
  network: msafeChainToSuiNetwork(config.network)
1650
1786
  });
1651
1787
  const backend = new BackendImpl(config.backend.url, options?.mockAddress);