@t2000/sdk 4.2.1 → 4.3.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.cjs CHANGED
@@ -678,7 +678,15 @@ async function fetchAllCoins(client, owner, coinType) {
678
678
  }
679
679
  async function selectAndSplitCoin(tx, client, owner, coinType, amount, options = {}) {
680
680
  if (options.sponsoredContext) {
681
- return selectCoinObjectsOnly(tx, client, owner, coinType, amount, options.allowSwapAll ?? true);
681
+ return selectCoinObjectsOnly(
682
+ tx,
683
+ client,
684
+ owner,
685
+ coinType,
686
+ amount,
687
+ options.allowSwapAll ?? true,
688
+ options.mergeCache
689
+ );
682
690
  }
683
691
  const balanceResp = await client.getBalance({ owner, coinType });
684
692
  const totalBalance = BigInt(balanceResp.totalBalance);
@@ -985,14 +993,15 @@ async function addSwapToTx(tx, client, address, input) {
985
993
  address,
986
994
  requestedRaw,
987
995
  input.sponsoredContext ?? false,
988
- input.suiMergeCache
996
+ input.coinMergeCache
989
997
  );
990
998
  inputCoin = result.coin;
991
999
  effectiveRaw = result.effectiveAmount;
992
1000
  } else {
993
1001
  const { selectAndSplitCoin: selectAndSplitCoin2 } = await Promise.resolve().then(() => (init_coinSelection(), coinSelection_exports));
994
1002
  const result = await selectAndSplitCoin2(tx, client, address, fromType, requestedRaw, {
995
- sponsoredContext: input.sponsoredContext ?? false
1003
+ sponsoredContext: input.sponsoredContext ?? false,
1004
+ mergeCache: input.coinMergeCache
996
1005
  });
997
1006
  inputCoin = result.coin;
998
1007
  effectiveRaw = result.effectiveAmount;
@@ -1393,6 +1402,27 @@ var KeypairSigner = class {
1393
1402
  }
1394
1403
  };
1395
1404
 
1405
+ // src/wallet/executeTx.ts
1406
+ async function executeTx(client, signer, buildTx, options = {}) {
1407
+ const tx = await buildTx();
1408
+ tx.setSender(signer.getAddress());
1409
+ const txBytes = await tx.build({ client: options.buildClient ?? client });
1410
+ const { signature } = await signer.signTransaction(txBytes);
1411
+ const result = await client.executeTransactionBlock({
1412
+ transactionBlock: txBytes,
1413
+ signature,
1414
+ options: { showEffects: true }
1415
+ });
1416
+ await client.waitForTransaction({ digest: result.digest });
1417
+ const gasUsed = result.effects?.gasUsed;
1418
+ let gasCostSui = 0;
1419
+ if (gasUsed) {
1420
+ const total = BigInt(gasUsed.computationCost) + BigInt(gasUsed.storageCost) - BigInt(gasUsed.storageRebate);
1421
+ gasCostSui = Number(total) / 1e9;
1422
+ }
1423
+ return { digest: result.digest, gasCostSui, effects: result.effects ?? void 0 };
1424
+ }
1425
+
1396
1426
  // src/mpp-cost.ts
1397
1427
  function parseChallengeAmount(challenge) {
1398
1428
  const raw = challenge?.request?.amount;
@@ -1400,6 +1430,66 @@ function parseChallengeAmount(challenge) {
1400
1430
  return Number.isFinite(n) ? n : void 0;
1401
1431
  }
1402
1432
 
1433
+ // src/wallet/pay.ts
1434
+ async function payWithMpp(args) {
1435
+ const { signer, client, options } = args;
1436
+ const { Mppx } = await import('mppx/client');
1437
+ const { sui, USDC } = await import('@suimpp/mpp/client');
1438
+ const { SuiGrpcClient: SuiGrpcClient2 } = await import('@mysten/sui/grpc');
1439
+ const signerAddress = signer.getAddress();
1440
+ let paymentDigest;
1441
+ let gasCostSui = 0;
1442
+ let chargedAmount;
1443
+ const network = client.network === "testnet" ? "testnet" : "mainnet";
1444
+ const grpcBaseUrl = network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
1445
+ const grpcClient = new SuiGrpcClient2({ baseUrl: grpcBaseUrl, network });
1446
+ const mppx = Mppx.create({
1447
+ polyfill: false,
1448
+ onChallenge: async (challenge) => {
1449
+ const parsed = parseChallengeAmount(challenge);
1450
+ if (parsed !== void 0) chargedAmount = parsed;
1451
+ return void 0;
1452
+ },
1453
+ methods: [sui({
1454
+ client,
1455
+ currency: USDC,
1456
+ signer: {
1457
+ toSuiAddress: () => signerAddress,
1458
+ signPersonalMessage: (bytes) => signer.signPersonalMessage(bytes)
1459
+ },
1460
+ execute: async (tx) => {
1461
+ const result = await executeTx(client, signer, () => tx, { buildClient: grpcClient });
1462
+ paymentDigest = result.digest;
1463
+ gasCostSui = result.gasCostSui;
1464
+ return { digest: result.digest };
1465
+ }
1466
+ })]
1467
+ });
1468
+ const method = (options.method ?? "GET").toUpperCase();
1469
+ const canHaveBody = method !== "GET" && method !== "HEAD";
1470
+ const response = await mppx.fetch(options.url, {
1471
+ method,
1472
+ headers: options.headers,
1473
+ body: canHaveBody ? options.body : void 0
1474
+ });
1475
+ const contentType = response.headers.get("content-type") ?? "";
1476
+ let body;
1477
+ try {
1478
+ body = contentType.includes("application/json") ? await response.json() : await response.text();
1479
+ } catch {
1480
+ body = null;
1481
+ }
1482
+ const paid = !!paymentDigest;
1483
+ return {
1484
+ status: response.status,
1485
+ body,
1486
+ paid,
1487
+ cost: paid ? chargedAmount ?? options.maxPrice ?? void 0 : void 0,
1488
+ gasCostSui: paid ? gasCostSui : void 0,
1489
+ receipt: paymentDigest ? { reference: paymentDigest, timestamp: (/* @__PURE__ */ new Date()).toISOString() } : void 0
1490
+ };
1491
+ }
1492
+
1403
1493
  // src/wallet/zkLoginSigner.ts
1404
1494
  var ZkLoginSigner = class {
1405
1495
  constructor(ephemeralKeypair, zkProof, userAddress, maxEpoch) {
@@ -1422,8 +1512,17 @@ var ZkLoginSigner = class {
1422
1512
  })
1423
1513
  };
1424
1514
  }
1425
- async signPersonalMessage(_messageBytes) {
1426
- throw new Error("ZkLoginSigner.signPersonalMessage is not yet implemented. Use KeypairSigner for sdk.pay() until grief-protection signing is wired for zkLogin.");
1515
+ async signPersonalMessage(messageBytes) {
1516
+ const { getZkLoginSignature } = await import('@mysten/zklogin');
1517
+ const { signature: ephSig, bytes } = await this.ephemeralKeypair.signPersonalMessage(messageBytes);
1518
+ return {
1519
+ signature: getZkLoginSignature({
1520
+ inputs: this.zkProof,
1521
+ maxEpoch: this.maxEpoch,
1522
+ userSignature: ephSig
1523
+ }),
1524
+ bytes
1525
+ };
1427
1526
  }
1428
1527
  isExpired(currentEpoch) {
1429
1528
  return currentEpoch >= this.maxEpoch;
@@ -6512,25 +6611,6 @@ var ContactManager = class {
6512
6611
  }
6513
6612
  };
6514
6613
  var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".t2000");
6515
- async function executeTx(client, signer, buildTx, options = {}) {
6516
- const tx = await buildTx();
6517
- tx.setSender(signer.getAddress());
6518
- const txBytes = await tx.build({ client: options.buildClient ?? client });
6519
- const { signature } = await signer.signTransaction(txBytes);
6520
- const result = await client.executeTransactionBlock({
6521
- transactionBlock: txBytes,
6522
- signature,
6523
- options: { showEffects: true }
6524
- });
6525
- await client.waitForTransaction({ digest: result.digest });
6526
- const gasUsed = result.effects?.gasUsed;
6527
- let gasCostSui = 0;
6528
- if (gasUsed) {
6529
- const total = BigInt(gasUsed.computationCost) + BigInt(gasUsed.storageCost) - BigInt(gasUsed.storageRebate);
6530
- gasCostSui = Number(total) / 1e9;
6531
- }
6532
- return { digest: result.digest, gasCostSui, effects: result.effects ?? void 0 };
6533
- }
6534
6614
  var T2000 = class _T2000 extends eventemitter3.EventEmitter {
6535
6615
  _signer;
6536
6616
  _keypair;
@@ -6610,66 +6690,11 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
6610
6690
  async pay(options) {
6611
6691
  this.enforcer.assertNotLocked();
6612
6692
  this.enforcer.check({ operation: "pay", amount: options.maxPrice ?? 1 });
6613
- const { Mppx } = await import('mppx/client');
6614
- const { sui, USDC } = await import('@suimpp/mpp/client');
6615
- const { SuiGrpcClient: SuiGrpcClient2 } = await import('@mysten/sui/grpc');
6616
- const client = this.client;
6617
- const signer = this._signer;
6618
- const signerAddress = signer.getAddress();
6619
- let paymentDigest;
6620
- let gasCostSui = 0;
6621
- let chargedAmount;
6622
- const network = client.network === "testnet" ? "testnet" : "mainnet";
6623
- const grpcBaseUrl = network === "testnet" ? "https://fullnode.testnet.sui.io" : "https://fullnode.mainnet.sui.io";
6624
- const grpcClient = new SuiGrpcClient2({ baseUrl: grpcBaseUrl, network });
6625
- const mppx = Mppx.create({
6626
- polyfill: false,
6627
- onChallenge: async (challenge) => {
6628
- const parsed = parseChallengeAmount(challenge);
6629
- if (parsed !== void 0) chargedAmount = parsed;
6630
- return void 0;
6631
- },
6632
- methods: [sui({
6633
- client,
6634
- currency: USDC,
6635
- signer: {
6636
- toSuiAddress: () => signerAddress,
6637
- signPersonalMessage: (bytes) => signer.signPersonalMessage(bytes)
6638
- },
6639
- execute: async (tx) => {
6640
- const result = await executeTx(client, signer, () => tx, { buildClient: grpcClient });
6641
- paymentDigest = result.digest;
6642
- gasCostSui = result.gasCostSui;
6643
- return { digest: result.digest };
6644
- }
6645
- })]
6646
- });
6647
- const method = (options.method ?? "GET").toUpperCase();
6648
- const canHaveBody = method !== "GET" && method !== "HEAD";
6649
- const response = await mppx.fetch(options.url, {
6650
- method,
6651
- headers: options.headers,
6652
- body: canHaveBody ? options.body : void 0
6653
- });
6654
- const contentType = response.headers.get("content-type") ?? "";
6655
- let body;
6656
- try {
6657
- body = contentType.includes("application/json") ? await response.json() : await response.text();
6658
- } catch {
6659
- body = null;
6693
+ const result = await payWithMpp({ signer: this._signer, client: this.client, options });
6694
+ if (result.paid) {
6695
+ this.enforcer.recordUsage(result.cost ?? options.maxPrice ?? 1);
6660
6696
  }
6661
- const paid = !!paymentDigest;
6662
- if (paid) {
6663
- this.enforcer.recordUsage(chargedAmount ?? options.maxPrice ?? 1);
6664
- }
6665
- return {
6666
- status: response.status,
6667
- body,
6668
- paid,
6669
- cost: paid ? chargedAmount ?? options.maxPrice ?? void 0 : void 0,
6670
- gasCostSui: paid ? gasCostSui : void 0,
6671
- receipt: paymentDigest ? { reference: paymentDigest, timestamp: (/* @__PURE__ */ new Date()).toISOString() } : void 0
6672
- };
6697
+ return result;
6673
6698
  }
6674
6699
  // [S.323 / 2026-05-25] VOLO vSUI staking surfaces removed (full cut).
6675
6700
  // Engine cut Volo in S.277; SDK + CLI + MCP followed in S.323 because the
@@ -7973,7 +7998,8 @@ var WRITE_APPENDER_REGISTRY = {
7973
7998
  effectiveAmount = rawAmount;
7974
7999
  } else {
7975
8000
  const r = await selectAndSplitCoin(tx, ctx.client, ctx.sender, assetInfo.type, rawAmount, {
7976
- sponsoredContext: ctx.sponsoredContext
8001
+ sponsoredContext: ctx.sponsoredContext,
8002
+ mergeCache: ctx.coinMergeCache
7977
8003
  });
7978
8004
  coin = r.coin;
7979
8005
  effectiveAmount = r.effectiveAmount;
@@ -8047,7 +8073,8 @@ var WRITE_APPENDER_REGISTRY = {
8047
8073
  effectiveAmount = rawAmount;
8048
8074
  } else {
8049
8075
  const r = await selectAndSplitCoin(tx, ctx.client, ctx.sender, assetInfo.type, rawAmount, {
8050
- sponsoredContext: ctx.sponsoredContext
8076
+ sponsoredContext: ctx.sponsoredContext,
8077
+ mergeCache: ctx.coinMergeCache
8051
8078
  });
8052
8079
  coin = r.coin;
8053
8080
  effectiveAmount = r.effectiveAmount;
@@ -8091,7 +8118,14 @@ var WRITE_APPENDER_REGISTRY = {
8091
8118
  };
8092
8119
  }
8093
8120
  if (asset === "SUI") {
8094
- const result = await selectSuiCoin(tx, ctx.client, ctx.sender, rawAmount, ctx.sponsoredContext);
8121
+ const result = await selectSuiCoin(
8122
+ tx,
8123
+ ctx.client,
8124
+ ctx.sender,
8125
+ rawAmount,
8126
+ ctx.sponsoredContext,
8127
+ ctx.coinMergeCache
8128
+ );
8095
8129
  addSendToTx(tx, result.coin, recipient);
8096
8130
  return {
8097
8131
  preview: {
@@ -8154,7 +8188,7 @@ var WRITE_APPENDER_REGISTRY = {
8154
8188
  inputCoin: ctx.chainedCoin,
8155
8189
  precomputedRoute: input.precomputedRoute,
8156
8190
  sponsoredContext: ctx.sponsoredContext,
8157
- suiMergeCache: ctx.suiMergeCache
8191
+ coinMergeCache: ctx.coinMergeCache
8158
8192
  });
8159
8193
  if (!ctx.isOutputConsumed) {
8160
8194
  tx.transferObjects([result.coin], ctx.sender);
@@ -8258,10 +8292,10 @@ async function composeTx(opts) {
8258
8292
  sponsoredContext: opts.sponsoredContext ?? false,
8259
8293
  overlayFee: opts.overlayFee,
8260
8294
  feeHooks: opts.feeHooks,
8261
- // One cache per compose run — shared across all legs so multi-leg
8262
- // sponsored bundles that source the same coin (e.g. two SUI swaps)
8263
- // merge that coin's objects exactly once.
8264
- suiMergeCache: /* @__PURE__ */ new Map()
8295
+ // One cache per compose run — shared across all legs (any coin type)
8296
+ // so multi-leg sponsored bundles that source the same coin (two SUI
8297
+ // swaps, swap USDC + save USDC, ...) merge that coin's objects once.
8298
+ coinMergeCache: /* @__PURE__ */ new Map()
8265
8299
  };
8266
8300
  const consumedSteps = /* @__PURE__ */ new Set();
8267
8301
  for (let i = 0; i < opts.steps.length; i++) {
@@ -8632,6 +8666,7 @@ exports.createSuiClient = createSuiClient;
8632
8666
  exports.deriveAllowedAddressesFromPtb = deriveAllowedAddressesFromPtb;
8633
8667
  exports.deserializeCetusRoute = deserializeCetusRoute;
8634
8668
  exports.displayHandle = displayHandle;
8669
+ exports.executeTx = executeTx;
8635
8670
  exports.exportPrivateKey = exportPrivateKey;
8636
8671
  exports.extractAllUserLegs = extractAllUserLegs;
8637
8672
  exports.extractTransferDetails = extractTransferDetails;
@@ -8675,6 +8710,7 @@ exports.normalizeAddressInput = normalizeAddressInput;
8675
8710
  exports.normalizeAsset = normalizeAsset;
8676
8711
  exports.normalizeCoinType = normalizeCoinType;
8677
8712
  exports.parseSuiRpcTx = parseSuiRpcTx;
8713
+ exports.payWithMpp = payWithMpp;
8678
8714
  exports.queryHistory = queryHistory;
8679
8715
  exports.queryTransaction = queryTransaction;
8680
8716
  exports.rawToStable = rawToStable;