@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.js CHANGED
@@ -153,6 +153,23 @@ import { SUI_MAINNET_CHAIN, SUI_TESTNET_CHAIN } from "@mysten/wallet-standard";
153
153
  // src/simulate/simulator.ts
154
154
  import { Transaction } from "@mysten/sui/transactions";
155
155
  var GAS_SAFE_OVERHEAD = 1000n;
156
+ function formatExecutionError(error) {
157
+ return error.message;
158
+ }
159
+ __name(formatExecutionError, "formatExecutionError");
160
+ function gasObjectToReference(gas) {
161
+ if (!gas?.objectId) {
162
+ throw new Error("Gas object missing from simulation effects");
163
+ }
164
+ const version = gas.outputVersion ?? gas.inputVersion ?? "0";
165
+ const digest = gas.outputDigest ?? gas.inputDigest ?? "";
166
+ return {
167
+ objectId: gas.objectId,
168
+ version,
169
+ digest
170
+ };
171
+ }
172
+ __name(gasObjectToReference, "gasObjectToReference");
156
173
  var Simulator = class {
157
174
  static {
158
175
  __name(this, "Simulator");
@@ -166,32 +183,63 @@ var Simulator = class {
166
183
  const { suiClient } = this.globals;
167
184
  const gasPrice = await this.getGasPrice();
168
185
  tx.setGasPrice(gasPrice);
169
- const inspectResult = await suiClient.dryRunTransactionBlock({
170
- transactionBlock: await tx.build({
186
+ let built;
187
+ try {
188
+ built = await tx.build({
171
189
  client: suiClient
172
- })
173
- });
174
- const success = inspectResult.effects.status.status === "success";
190
+ });
191
+ } catch (e) {
192
+ const message = e instanceof Error ? e.message : String(e);
193
+ return {
194
+ success: false,
195
+ gasPrice,
196
+ simulationError: message
197
+ };
198
+ }
199
+ let inspectResult;
200
+ try {
201
+ inspectResult = await suiClient.simulateTransaction({
202
+ transaction: built,
203
+ include: {
204
+ effects: true
205
+ }
206
+ });
207
+ } catch (e) {
208
+ const message = e instanceof Error ? e.message : String(e);
209
+ return {
210
+ success: false,
211
+ gasPrice,
212
+ simulationError: message
213
+ };
214
+ }
215
+ const txRow = inspectResult.Transaction ?? inspectResult.FailedTransaction;
216
+ const { effects } = txRow;
217
+ if (!effects) {
218
+ throw new Error("simulateTransaction did not return effects");
219
+ }
220
+ const success = effects.status.success === true;
175
221
  if (!success) {
222
+ const err = effects.status.success === false ? effects.status.error : null;
176
223
  return {
177
224
  success,
178
225
  gasPrice,
179
226
  response: inspectResult,
180
- simulationError: inspectResult.effects.status.error
227
+ simulationError: err ? formatExecutionError(err) : "Simulation failed"
181
228
  };
182
229
  }
183
- const gasBudget = this.toGasBudget(inspectResult.effects.gasUsed, gasPrice);
230
+ const gasBudget = this.toGasBudget(effects.gasUsed, gasPrice);
184
231
  return {
185
232
  success,
186
233
  gasPrice,
187
- gasObject: inspectResult.effects.gasObject.reference,
188
- gasUsed: inspectResult.effects.gasUsed,
234
+ gasObject: gasObjectToReference(effects.gasObject),
235
+ gasUsed: effects.gasUsed,
189
236
  gasBudget,
190
237
  response: inspectResult
191
238
  };
192
239
  }
193
240
  async getGasPrice() {
194
- return this.globals.suiClient.getReferenceGasPrice();
241
+ const { referenceGasPrice } = await this.globals.suiClient.getReferenceGasPrice();
242
+ return BigInt(referenceGasPrice);
195
243
  }
196
244
  toGasBudget(gasUsed, gasPrice) {
197
245
  const { computationCost, storageCost, storageRebate } = gasUsed;
@@ -253,7 +301,7 @@ var CoinHelper = class {
253
301
  const res = await this._client.getCoinMetadata({
254
302
  coinType
255
303
  });
256
- return res || void 0;
304
+ return res.coinMetadata ?? void 0;
257
305
  }
258
306
  };
259
307
  var COIN_TYPE_ARG_REGEX = /^0x0000000000000000000000000000000000000000000000000000000000000002::coin::Coin<(.+)>$/;
@@ -275,6 +323,13 @@ var Coin = class _Coin {
275
323
  if (!_Coin.isCoin(data.type)) {
276
324
  return void 0;
277
325
  }
326
+ if (data.json && typeof data.json === "object" && "balance" in data.json) {
327
+ const { balance: balance2 } = data.json;
328
+ if (balance2 === void 0) {
329
+ return void 0;
330
+ }
331
+ return BigInt(balance2);
332
+ }
278
333
  if (data.content?.dataType !== "moveObject") {
279
334
  return void 0;
280
335
  }
@@ -360,29 +415,82 @@ var SignatureVerifier = class _SignatureVerifier {
360
415
  // src/utils/sui.ts
361
416
  import { PublicKeySerde as PublicKeySerde2 } from "@msafe/sui3-utils";
362
417
  import { parseSerializedSignature } from "@mysten/sui/cryptography";
418
+ import { SuiGraphQLClient } from "@mysten/sui/graphql";
363
419
  import { MultiSigPublicKey } from "@mysten/sui/multisig";
364
420
  var SUI_COIN = "0x2::sui::SUI";
421
+ var GRAPHQL_URL_BY_NETWORK = {
422
+ mainnet: "https://sui-mainnet.mystenlabs.com/graphql",
423
+ testnet: "https://sui-testnet.mystenlabs.com/graphql",
424
+ devnet: "https://sui-devnet.mystenlabs.com/graphql"
425
+ };
426
+ function graphqlClientForGrpc(suiClient) {
427
+ const url = GRAPHQL_URL_BY_NETWORK[suiClient.network] ?? GRAPHQL_URL_BY_NETWORK.testnet;
428
+ return new SuiGraphQLClient({
429
+ url,
430
+ network: suiClient.network
431
+ });
432
+ }
433
+ __name(graphqlClientForGrpc, "graphqlClientForGrpc");
434
+ function collectSignatureStrings(value) {
435
+ if (typeof value === "string") {
436
+ return [
437
+ value
438
+ ];
439
+ }
440
+ if (!value || typeof value !== "object") {
441
+ return [];
442
+ }
443
+ if ("base64" in value && typeof value.base64 === "string") {
444
+ return [
445
+ value.base64
446
+ ];
447
+ }
448
+ if ("scheme" in value && "base64" in value) {
449
+ const b64 = value.base64;
450
+ return typeof b64 === "string" ? [
451
+ b64
452
+ ] : [];
453
+ }
454
+ return [];
455
+ }
456
+ __name(collectSignatureStrings, "collectSignatureStrings");
457
+ var TX_SIG_QUERY = `
458
+ query PublicKeyTxSigs($sender: SuiAddress!, $first: Int!) {
459
+ transactions(first: $first, filter: { sentAddress: $sender }) {
460
+ nodes {
461
+ signatures
462
+ }
463
+ }
464
+ }
465
+ `;
365
466
  async function getPublicKeyFromChain(suiClient, address) {
467
+ const graphql = graphqlClientForGrpc(suiClient);
366
468
  let txs;
367
469
  try {
368
- txs = await suiClient.queryTransactionBlocks({
369
- // Disable naming rule since the variable is defined by Mysten
370
- filter: {
371
- FromAddress: address
372
- },
373
- options: {
374
- showInput: true
375
- },
376
- limit: 2
470
+ const res = await graphql.query({
471
+ query: TX_SIG_QUERY,
472
+ variables: {
473
+ sender: address,
474
+ first: 2
475
+ }
377
476
  });
477
+ if (res.errors?.length) {
478
+ return void 0;
479
+ }
480
+ txs = res.data ?? {};
378
481
  } catch (e) {
379
482
  return void 0;
380
483
  }
381
- if (txs.data.length === 0 || !txs.data[0].transaction?.txSignatures) {
484
+ const nodes = txs.transactions?.nodes ?? [];
485
+ if (nodes.length === 0) {
486
+ return void 0;
487
+ }
488
+ const first = nodes[0];
489
+ const rawSigs = first.signatures;
490
+ const signatures = Array.isArray(rawSigs) ? rawSigs.flatMap((item) => collectSignatureStrings(item)) : [];
491
+ if (signatures.length === 0) {
382
492
  return void 0;
383
493
  }
384
- const tx = txs.data[0];
385
- const signatures = tx.transaction?.txSignatures;
386
494
  for (let i = 0; i !== signatures.length; i++) {
387
495
  const serializedSig = signatures[i];
388
496
  const pk = getAddressFromSignatures(serializedSig, address);
@@ -427,14 +535,14 @@ async function getAllCoins(input) {
427
535
  let cursor;
428
536
  const res = [];
429
537
  while (hasNext) {
430
- const currentPage = await input.suiClient.getCoins({
538
+ const currentPage = await input.suiClient.listCoins({
431
539
  owner: input.owner,
432
540
  coinType: input.coinType,
433
541
  cursor
434
542
  });
435
- res.push(...currentPage.data);
543
+ res.push(...currentPage.objects);
436
544
  hasNext = currentPage.hasNextPage;
437
- cursor = currentPage.nextCursor;
545
+ cursor = currentPage.cursor;
438
546
  }
439
547
  return res;
440
548
  }
@@ -536,6 +644,16 @@ var EntryIterator = class {
536
644
  };
537
645
 
538
646
  // src/utils/iter/object.ts
647
+ var defaultObjectInclude = {
648
+ json: true
649
+ };
650
+ function mergeInclude(options) {
651
+ return {
652
+ ...defaultObjectInclude,
653
+ ...options?.objectInclude
654
+ };
655
+ }
656
+ __name(mergeInclude, "mergeInclude");
539
657
  async function getAllOwnedObjects(provider, owner, options) {
540
658
  const iter = new OwnedObjectIterator(provider, owner, options);
541
659
  return await getAllFromIterator(iter);
@@ -565,7 +683,7 @@ var OwnedObjectRequester = class {
565
683
  nextCursor;
566
684
  filter;
567
685
  pageSize;
568
- objectOptions;
686
+ objectInclude;
569
687
  constructor(provider, owner, options) {
570
688
  this.provider = provider;
571
689
  this.owner = owner;
@@ -573,28 +691,25 @@ var OwnedObjectRequester = class {
573
691
  this.nextCursor = null;
574
692
  this.filter = options?.filter;
575
693
  this.pageSize = options?.pageSize || REQUEST_PAGE_SIZE;
576
- this.objectOptions = options?.objectOptions || {
577
- showType: true,
578
- showContent: true
579
- };
694
+ this.objectInclude = mergeInclude(options);
580
695
  }
581
696
  async doNextRequest() {
582
- const res = await this.provider.getOwnedObjects({
697
+ const res = await this.provider.listOwnedObjects({
583
698
  owner: this.owner,
584
- options: this.objectOptions,
699
+ include: this.objectInclude,
585
700
  cursor: this.nextCursor,
586
701
  limit: this.pageSize
587
702
  });
588
- this.nextCursor = res.nextCursor;
703
+ this.nextCursor = res.cursor;
589
704
  let filtered;
590
705
  if (this.filter) {
591
706
  const { filter } = this;
592
- filtered = res.data.filter((obj) => filter?.(obj));
707
+ filtered = res.objects.filter((obj) => filter(obj));
593
708
  } else {
594
- filtered = res.data;
709
+ filtered = res.objects;
595
710
  }
596
711
  return {
597
- data: filtered.map((r) => r.data).filter((data) => data),
712
+ data: filtered,
598
713
  hasNext: res.hasNextPage
599
714
  };
600
715
  }
@@ -629,23 +744,31 @@ var MSafeAccount = class _MSafeAccount {
629
744
  }
630
745
  }
631
746
  async ownedCoins() {
632
- const balances = await this.suiClient.getAllBalances({
633
- owner: this.address
634
- });
747
+ const balances = [];
748
+ let cursor = null;
749
+ let hasNext = true;
750
+ while (hasNext) {
751
+ const page = await this.suiClient.listBalances({
752
+ owner: this.address,
753
+ cursor,
754
+ limit: 50
755
+ });
756
+ balances.push(...page.balances);
757
+ hasNext = page.hasNextPage;
758
+ cursor = page.cursor;
759
+ }
635
760
  return Promise.all(balances.map(async (balance) => {
636
761
  const meta = await this.coinHelper.getCoinMeta(balance.coinType);
637
- const lockedEntry = balance.lockedBalance && typeof balance.lockedBalance === "object" && "number" in balance.lockedBalance && balance.lockedBalance.number ? BigInt(balance.lockedBalance.number) : 0n;
638
- const unlockedBalance = lockedEntry ? BigInt(balance.totalBalance) - lockedEntry : BigInt(balance.totalBalance);
639
762
  return {
640
763
  type: normalizeStructTag3(balance.coinType),
641
- balance: unlockedBalance,
764
+ balance: BigInt(balance.addressBalance),
642
765
  metadata: meta
643
766
  };
644
767
  }));
645
768
  }
646
769
  async ownedObjects(options) {
647
770
  const filterCoinObjectOptions = {
648
- filter: (objRes) => !objRes?.data?.type?.startsWith("0x2::coin::Coin"),
771
+ filter: (obj) => !obj?.type?.startsWith("0x2::coin::Coin"),
649
772
  ...options
650
773
  };
651
774
  return getAllOwnedObjects(this.suiClient, this.address, filterCoinObjectOptions);
@@ -966,12 +1089,14 @@ var MSafeAccount = class _MSafeAccount {
966
1089
  }
967
1090
  }
968
1091
  const multiSignature = this.multiSig.combinePartialSignatures(sortedSigs);
969
- return this.suiClient.executeTransactionBlock({
970
- transactionBlock: HexToUint8Array(payload),
971
- signature: multiSignature,
972
- options: {
973
- showEffects: true,
974
- showEvents: true
1092
+ return this.suiClient.executeTransaction({
1093
+ transaction: HexToUint8Array(payload),
1094
+ signatures: [
1095
+ multiSignature
1096
+ ],
1097
+ include: {
1098
+ effects: true,
1099
+ events: true
975
1100
  }
976
1101
  });
977
1102
  }
@@ -1106,7 +1231,7 @@ var ReportSDK = class {
1106
1231
  };
1107
1232
 
1108
1233
  // src/globals/MSafeGlobals.ts
1109
- import { SuiJsonRpcClient } from "@mysten/sui/jsonRpc";
1234
+ import { SuiGrpcClient } from "@mysten/sui/grpc";
1110
1235
 
1111
1236
  // src/backend/BackendImpl.ts
1112
1237
  import { PublicKeySerde as PublicKeySerde3, UserMSafeStatus } from "@msafe/sui3-utils";
@@ -1463,6 +1588,17 @@ var MSafeEnv;
1463
1588
  MSafeEnv2["prev"] = "prev";
1464
1589
  MSafeEnv2["prod"] = "prod";
1465
1590
  })(MSafeEnv || (MSafeEnv = {}));
1591
+ function httpUrlToGrpcBaseUrl(url) {
1592
+ const parsed = new URL(url);
1593
+ if (parsed.protocol === "https:" && parsed.port === "") {
1594
+ return `https://${parsed.hostname}:443${parsed.pathname}${parsed.search}`;
1595
+ }
1596
+ if (parsed.protocol === "http:" && parsed.port === "") {
1597
+ return `http://${parsed.hostname}:80${parsed.pathname}${parsed.search}`;
1598
+ }
1599
+ return `${parsed.origin}${parsed.pathname}${parsed.search}`;
1600
+ }
1601
+ __name(httpUrlToGrpcBaseUrl, "httpUrlToGrpcBaseUrl");
1466
1602
  var TESTNET_RPC_URL = "https://fullnode.testnet.sui.io";
1467
1603
  var MAINNET_RPC_URL = "https://fullnode.mainnet.sui.io";
1468
1604
  var LOCAL_API_URL = "http://127.0.0.1:3000";
@@ -1479,9 +1615,9 @@ var ENV_CONFIGS = /* @__PURE__ */ new Map([
1479
1615
  url: TESTNET_RPC_URL
1480
1616
  },
1481
1617
  backend: {
1482
- url: LOCAL_API_URL
1618
+ url: DEV_API_URL
1483
1619
  },
1484
- syncingURL: LOCAL_SYNCING_URL,
1620
+ syncingURL: DEV_SYNCING_URL,
1485
1621
  network: "sui:testnet"
1486
1622
  }
1487
1623
  ],
@@ -1572,12 +1708,11 @@ var MSafeGlobals = class _MSafeGlobals {
1572
1708
  }
1573
1709
  static async New(env, options) {
1574
1710
  const config = getMSafeConfig(env, options);
1575
- const suiClient = new SuiJsonRpcClient({
1576
- ...config.suiClient.transport ? {
1577
- transport: config.suiClient.transport
1578
- } : {
1579
- url: config.suiClient.url
1580
- },
1711
+ const suiClient = config.suiClient.transport ? new SuiGrpcClient({
1712
+ transport: config.suiClient.transport,
1713
+ network: msafeChainToSuiNetwork(config.network)
1714
+ }) : new SuiGrpcClient({
1715
+ baseUrl: httpUrlToGrpcBaseUrl(config.suiClient.url),
1581
1716
  network: msafeChainToSuiNetwork(config.network)
1582
1717
  });
1583
1718
  const backend = new BackendImpl(config.backend.url, options?.mockAddress);
@@ -1767,6 +1902,7 @@ export {
1767
1902
  getAllCoins,
1768
1903
  getMSafeConfig,
1769
1904
  getPublicKeyFromChain,
1905
+ httpUrlToGrpcBaseUrl,
1770
1906
  msafeChainToSuiNetwork,
1771
1907
  stringToBuffer,
1772
1908
  toSuiTransaction