@t2000/sdk 0.1.3 → 0.1.5

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
@@ -20,7 +20,7 @@ var USDC_DECIMALS = 6;
20
20
  var BPS_DENOMINATOR = 10000n;
21
21
  var AUTO_TOPUP_THRESHOLD = 50000000n;
22
22
  var AUTO_TOPUP_AMOUNT = 1000000n;
23
- var AUTO_TOPUP_MIN_USDC = 5000000n;
23
+ var AUTO_TOPUP_MIN_USDC = 2000000n;
24
24
  var SAVE_FEE_BPS = 10n;
25
25
  var SWAP_FEE_BPS = 10n;
26
26
  var BORROW_FEE_BPS = 5n;
@@ -236,39 +236,27 @@ function formatSui(amount) {
236
236
  }
237
237
 
238
238
  // src/wallet/send.ts
239
- async function buildAndExecuteSend({
239
+ async function buildSendTx({
240
240
  client,
241
- keypair,
241
+ address,
242
242
  to,
243
243
  amount,
244
244
  asset = "USDC"
245
245
  }) {
246
246
  const recipient = validateAddress(to);
247
247
  const assetInfo = SUPPORTED_ASSETS[asset];
248
- if (!assetInfo) {
249
- throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
250
- }
251
- if (amount <= 0) {
252
- throw new T2000Error("INVALID_AMOUNT", "Amount must be greater than zero");
253
- }
254
- const senderAddress = keypair.getPublicKey().toSuiAddress();
248
+ if (!assetInfo) throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
249
+ if (amount <= 0) throw new T2000Error("INVALID_AMOUNT", "Amount must be greater than zero");
255
250
  const rawAmount = displayToRaw(amount, assetInfo.decimals);
256
251
  const tx = new Transaction();
252
+ tx.setSender(address);
257
253
  if (asset === "SUI") {
258
254
  const [coin] = tx.splitCoins(tx.gas, [rawAmount]);
259
255
  tx.transferObjects([coin], recipient);
260
256
  } else {
261
- const coins = await client.getCoins({
262
- owner: senderAddress,
263
- coinType: assetInfo.type
264
- });
265
- if (coins.data.length === 0) {
266
- throw new T2000Error("INSUFFICIENT_BALANCE", `No ${asset} coins found`);
267
- }
268
- const totalBalance = coins.data.reduce(
269
- (sum, c) => sum + BigInt(c.balance),
270
- 0n
271
- );
257
+ const coins = await client.getCoins({ owner: address, coinType: assetInfo.type });
258
+ if (coins.data.length === 0) throw new T2000Error("INSUFFICIENT_BALANCE", `No ${asset} coins found`);
259
+ const totalBalance = coins.data.reduce((sum, c) => sum + BigInt(c.balance), 0n);
272
260
  if (totalBalance < rawAmount) {
273
261
  throw new T2000Error("INSUFFICIENT_BALANCE", `Insufficient ${asset} balance`, {
274
262
  available: Number(totalBalance) / 10 ** assetInfo.decimals,
@@ -277,28 +265,12 @@ async function buildAndExecuteSend({
277
265
  }
278
266
  const primaryCoin = tx.object(coins.data[0].coinObjectId);
279
267
  if (coins.data.length > 1) {
280
- tx.mergeCoins(
281
- primaryCoin,
282
- coins.data.slice(1).map((c) => tx.object(c.coinObjectId))
283
- );
268
+ tx.mergeCoins(primaryCoin, coins.data.slice(1).map((c) => tx.object(c.coinObjectId)));
284
269
  }
285
270
  const [sendCoin] = tx.splitCoins(primaryCoin, [rawAmount]);
286
271
  tx.transferObjects([sendCoin], recipient);
287
272
  }
288
- const result = await client.signAndExecuteTransaction({
289
- signer: keypair,
290
- transaction: tx,
291
- options: { showEffects: true }
292
- });
293
- await client.waitForTransaction({ digest: result.digest });
294
- const gasUsed = result.effects?.gasUsed;
295
- const gasCost = gasUsed ? Math.abs(
296
- (Number(gasUsed.computationCost) + Number(gasUsed.storageCost) - Number(gasUsed.storageRebate)) / 1e9
297
- ) : 0;
298
- return {
299
- digest: result.digest,
300
- gasCost
301
- };
273
+ return tx;
302
274
  }
303
275
 
304
276
  // src/wallet/balance.ts
@@ -396,12 +368,6 @@ var NAVI_BALANCE_DECIMALS = 9;
396
368
  function clientOpt(client, fresh = false) {
397
369
  return { client, ...ENV, ...fresh ? { disableCache: true } : {} };
398
370
  }
399
- function extractGasCost(effects) {
400
- if (!effects?.gasUsed) return 0;
401
- return Math.abs(
402
- (Number(effects.gasUsed.computationCost) + Number(effects.gasUsed.storageCost) - Number(effects.gasUsed.storageRebate)) / 1e9
403
- );
404
- }
405
371
  function rateToApy(rawRate) {
406
372
  if (!rawRate || rawRate === "0") return 0;
407
373
  return Number(BigInt(rawRate)) / 10 ** RATE_DECIMALS * 100;
@@ -434,8 +400,7 @@ async function updateOracle(tx, client, address) {
434
400
  } catch {
435
401
  }
436
402
  }
437
- async function save(client, keypair, amount) {
438
- const address = keypair.getPublicKey().toSuiAddress();
403
+ async function buildSaveTx(client, address, amount) {
439
404
  const rawAmount = Number(usdcToRaw(amount));
440
405
  const coins = await getCoins(address, { coinType: USDC_TYPE, client });
441
406
  if (!coins || coins.length === 0) {
@@ -445,25 +410,9 @@ async function save(client, keypair, amount) {
445
410
  tx.setSender(address);
446
411
  const coinObj = mergeCoinsPTB(tx, coins, { balance: rawAmount });
447
412
  await depositCoinPTB(tx, USDC_TYPE, coinObj, ENV);
448
- const result = await client.signAndExecuteTransaction({
449
- signer: keypair,
450
- transaction: tx,
451
- options: { showEffects: true }
452
- });
453
- await client.waitForTransaction({ digest: result.digest });
454
- const rates = await getRates();
455
- return {
456
- success: true,
457
- tx: result.digest,
458
- amount,
459
- apy: rates.USDC.saveApy,
460
- fee: 0,
461
- gasCost: extractGasCost(result.effects),
462
- gasMethod: "self-funded"
463
- };
413
+ return tx;
464
414
  }
465
- async function withdraw(client, keypair, amount) {
466
- const address = keypair.getPublicKey().toSuiAddress();
415
+ async function buildWithdrawTx(client, address, amount) {
467
416
  const state = await getLendingState(address, clientOpt(client, true));
468
417
  const usdcPos = findUsdcPosition(state);
469
418
  const deposited = usdcPos ? Number(usdcPos.supplyBalance) / 10 ** NAVI_BALANCE_DECIMALS : 0;
@@ -475,47 +424,18 @@ async function withdraw(client, keypair, amount) {
475
424
  await updateOracle(tx, client, address);
476
425
  const withdrawnCoin = await withdrawCoinPTB(tx, USDC_TYPE, rawAmount, ENV);
477
426
  tx.transferObjects([withdrawnCoin], address);
478
- const result = await client.signAndExecuteTransaction({
479
- signer: keypair,
480
- transaction: tx,
481
- options: { showEffects: true }
482
- });
483
- await client.waitForTransaction({ digest: result.digest });
484
- return {
485
- success: true,
486
- tx: result.digest,
487
- amount: effectiveAmount,
488
- gasCost: extractGasCost(result.effects),
489
- gasMethod: "self-funded"
490
- };
427
+ return { tx, effectiveAmount };
491
428
  }
492
- async function borrow(client, keypair, amount) {
493
- const address = keypair.getPublicKey().toSuiAddress();
429
+ async function buildBorrowTx(client, address, amount) {
494
430
  const rawAmount = Number(usdcToRaw(amount));
495
431
  const tx = new Transaction();
496
432
  tx.setSender(address);
497
433
  await updateOracle(tx, client, address);
498
434
  const borrowedCoin = await borrowCoinPTB(tx, USDC_TYPE, rawAmount, ENV);
499
435
  tx.transferObjects([borrowedCoin], address);
500
- const result = await client.signAndExecuteTransaction({
501
- signer: keypair,
502
- transaction: tx,
503
- options: { showEffects: true }
504
- });
505
- await client.waitForTransaction({ digest: result.digest });
506
- const hf = await getHealthFactor$1(address, clientOpt(client, true));
507
- return {
508
- success: true,
509
- tx: result.digest,
510
- amount,
511
- fee: 0,
512
- healthFactor: hf,
513
- gasCost: extractGasCost(result.effects),
514
- gasMethod: "self-funded"
515
- };
436
+ return tx;
516
437
  }
517
- async function repay(client, keypair, amount) {
518
- const address = keypair.getPublicKey().toSuiAddress();
438
+ async function buildRepayTx(client, address, amount) {
519
439
  const rawAmount = Number(usdcToRaw(amount));
520
440
  const coins = await getCoins(address, { coinType: USDC_TYPE, client });
521
441
  if (!coins || coins.length === 0) {
@@ -525,23 +445,7 @@ async function repay(client, keypair, amount) {
525
445
  tx.setSender(address);
526
446
  const coinObj = mergeCoinsPTB(tx, coins, { balance: rawAmount });
527
447
  await repayCoinPTB(tx, USDC_TYPE, coinObj, { ...ENV, amount: rawAmount });
528
- const result = await client.signAndExecuteTransaction({
529
- signer: keypair,
530
- transaction: tx,
531
- options: { showEffects: true }
532
- });
533
- await client.waitForTransaction({ digest: result.digest });
534
- const state = await getLendingState(address, clientOpt(client, true));
535
- const usdcPos = findUsdcPosition(state);
536
- const remainingDebt = usdcPos ? Number(usdcPos.borrowBalance) / 10 ** NAVI_BALANCE_DECIMALS : 0;
537
- return {
538
- success: true,
539
- tx: result.digest,
540
- amount,
541
- remainingDebt,
542
- gasCost: extractGasCost(result.effects),
543
- gasMethod: "self-funded"
544
- };
448
+ return tx;
545
449
  }
546
450
  async function getHealthFactor(client, keypair) {
547
451
  const address = keypair.getPublicKey().toSuiAddress();
@@ -633,10 +537,6 @@ async function maxBorrowAmount(client, keypair) {
633
537
  };
634
538
  }
635
539
  var DEFAULT_SLIPPAGE_BPS = 300;
636
- function extractGasCost2(effects) {
637
- if (!effects?.gasUsed) return 0;
638
- return (Number(effects.gasUsed.computationCost) + Number(effects.gasUsed.storageCost) - Number(effects.gasUsed.storageRebate)) / 1e9;
639
- }
640
540
  function isA2B(from) {
641
541
  return from === "USDC";
642
542
  }
@@ -647,9 +547,8 @@ function getCetusSDK() {
647
547
  }
648
548
  return _cetusSDK;
649
549
  }
650
- async function executeSwap(params) {
651
- const { client, keypair, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
652
- const address = keypair.getPublicKey().toSuiAddress();
550
+ async function buildSwapTx(params) {
551
+ const { address, fromAsset, toAsset, amount, maxSlippageBps = DEFAULT_SLIPPAGE_BPS } = params;
653
552
  const a2b = isA2B(fromAsset);
654
553
  const fromInfo = SUPPORTED_ASSETS[fromAsset];
655
554
  const toInfo = SUPPORTED_ASSETS[toAsset];
@@ -680,32 +579,10 @@ async function executeSwap(params) {
680
579
  amount: preSwapResult.amount.toString(),
681
580
  amount_limit: amountLimit.toString()
682
581
  });
683
- const result = await client.signAndExecuteTransaction({
684
- signer: keypair,
685
- transaction: swapPayload,
686
- options: { showEffects: true, showBalanceChanges: true }
687
- });
688
- await client.waitForTransaction({ digest: result.digest });
689
- let actualReceived = 0;
690
- if (result.balanceChanges) {
691
- for (const change of result.balanceChanges) {
692
- if (change.coinType === toInfo.type && change.owner && typeof change.owner === "object" && "AddressOwner" in change.owner && change.owner.AddressOwner === address) {
693
- const amt = Number(change.amount) / 10 ** toInfo.decimals;
694
- if (amt > 0) actualReceived += amt;
695
- }
696
- }
697
- }
698
- const expectedOutput = estimatedOut / 10 ** toInfo.decimals;
699
- if (actualReceived === 0) actualReceived = expectedOutput;
700
- const priceImpact = expectedOutput > 0 ? Math.abs(actualReceived - expectedOutput) / expectedOutput : 0;
701
582
  return {
702
- digest: result.digest,
703
- fromAmount: amount,
704
- fromAsset,
705
- toAmount: actualReceived,
706
- toAsset,
707
- priceImpact,
708
- gasCost: extractGasCost2(result.effects)
583
+ tx: swapPayload,
584
+ estimatedOut,
585
+ toDecimals: toInfo.decimals
709
586
  };
710
587
  }
711
588
  async function getPoolPrice(client) {
@@ -982,12 +859,120 @@ async function executeAutoTopUp(client, keypair) {
982
859
  };
983
860
  }
984
861
 
862
+ // src/gas/manager.ts
863
+ function extractGasCost(effects) {
864
+ if (!effects?.gasUsed) return 0;
865
+ return (Number(effects.gasUsed.computationCost) + Number(effects.gasUsed.storageCost) - Number(effects.gasUsed.storageRebate)) / 1e9;
866
+ }
867
+ async function getSuiBalance(client, address) {
868
+ const bal = await client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.SUI.type });
869
+ return BigInt(bal.totalBalance);
870
+ }
871
+ async function trySelfFunded(client, keypair, tx) {
872
+ const address = keypair.getPublicKey().toSuiAddress();
873
+ const suiBalance = await getSuiBalance(client, address);
874
+ if (suiBalance < AUTO_TOPUP_THRESHOLD) return null;
875
+ tx.setSender(address);
876
+ const result = await client.signAndExecuteTransaction({
877
+ signer: keypair,
878
+ transaction: tx,
879
+ options: { showEffects: true }
880
+ });
881
+ await client.waitForTransaction({ digest: result.digest });
882
+ return {
883
+ digest: result.digest,
884
+ effects: result.effects,
885
+ gasMethod: "self-funded",
886
+ gasCostSui: extractGasCost(result.effects)
887
+ };
888
+ }
889
+ async function tryAutoTopUpThenSelfFund(client, keypair, tx) {
890
+ const address = keypair.getPublicKey().toSuiAddress();
891
+ const canTopUp = await shouldAutoTopUp(client, address);
892
+ if (!canTopUp) return null;
893
+ try {
894
+ await executeAutoTopUp(client, keypair);
895
+ } catch {
896
+ return null;
897
+ }
898
+ tx.setSender(address);
899
+ const result = await client.signAndExecuteTransaction({
900
+ signer: keypair,
901
+ transaction: tx,
902
+ options: { showEffects: true }
903
+ });
904
+ await client.waitForTransaction({ digest: result.digest });
905
+ return {
906
+ digest: result.digest,
907
+ effects: result.effects,
908
+ gasMethod: "auto-topup",
909
+ gasCostSui: extractGasCost(result.effects)
910
+ };
911
+ }
912
+ async function trySponsored(client, keypair, tx) {
913
+ const address = keypair.getPublicKey().toSuiAddress();
914
+ tx.setSender(address);
915
+ let txBytes;
916
+ try {
917
+ txBytes = await tx.build({ client, onlyTransactionKind: true });
918
+ } catch {
919
+ return null;
920
+ }
921
+ const txBytesBase64 = Buffer.from(txBytes).toString("base64");
922
+ let sponsoredResult;
923
+ try {
924
+ sponsoredResult = await requestGasSponsorship(txBytesBase64, address);
925
+ } catch {
926
+ return null;
927
+ }
928
+ const sponsoredTxBytes = Buffer.from(sponsoredResult.txBytes, "base64");
929
+ const { signature: agentSig } = await keypair.signTransaction(sponsoredTxBytes);
930
+ const result = await client.executeTransactionBlock({
931
+ transactionBlock: sponsoredResult.txBytes,
932
+ signature: [agentSig, sponsoredResult.sponsorSignature],
933
+ options: { showEffects: true }
934
+ });
935
+ await client.waitForTransaction({ digest: result.digest });
936
+ const gasCost = extractGasCost(result.effects);
937
+ reportGasUsage(address, result.digest, gasCost, 0, sponsoredResult.type);
938
+ return {
939
+ digest: result.digest,
940
+ effects: result.effects,
941
+ gasMethod: "sponsored",
942
+ gasCostSui: gasCost
943
+ };
944
+ }
945
+ async function executeWithGas(client, keypair, buildTx) {
946
+ try {
947
+ const tx = await buildTx();
948
+ const result = await trySelfFunded(client, keypair, tx);
949
+ if (result) return result;
950
+ } catch {
951
+ }
952
+ try {
953
+ const tx = await buildTx();
954
+ const result = await tryAutoTopUpThenSelfFund(client, keypair, tx);
955
+ if (result) return result;
956
+ } catch {
957
+ }
958
+ try {
959
+ const tx = await buildTx();
960
+ const result = await trySponsored(client, keypair, tx);
961
+ if (result) return result;
962
+ } catch {
963
+ }
964
+ throw new T2000Error(
965
+ "INSUFFICIENT_GAS",
966
+ "No SUI for gas and Gas Station unavailable. Fund your wallet with SUI or USDC.",
967
+ { reason: "all_gas_methods_exhausted" }
968
+ );
969
+ }
970
+
985
971
  // src/t2000.ts
986
972
  var T2000 = class _T2000 extends EventEmitter {
987
973
  keypair;
988
974
  client;
989
975
  _address;
990
- _lastGasMethod = "self-funded";
991
976
  constructor(keypair, client) {
992
977
  super();
993
978
  this.keypair = keypair;
@@ -1041,29 +1026,6 @@ var T2000 = class _T2000 extends EventEmitter {
1041
1026
  return { agent, address, sponsored };
1042
1027
  }
1043
1028
  // -- Gas --
1044
- /**
1045
- * Ensure the agent has enough SUI for gas.
1046
- * If SUI is low and USDC is available, auto-swaps $1 USDC → SUI.
1047
- */
1048
- async ensureGas() {
1049
- this._lastGasMethod = "self-funded";
1050
- const needsTopUp = await shouldAutoTopUp(this.client, this._address);
1051
- if (!needsTopUp) return;
1052
- try {
1053
- const result = await executeAutoTopUp(this.client, this.keypair);
1054
- this._lastGasMethod = "auto-topup";
1055
- this.emit("gasAutoTopUp", {
1056
- usdcSpent: result.usdcSpent,
1057
- suiReceived: result.suiReceived
1058
- });
1059
- } catch {
1060
- this.emit("gasStationFallback", {
1061
- reason: "auto-topup failed",
1062
- method: "self-funded",
1063
- suiUsed: 0
1064
- });
1065
- }
1066
- }
1067
1029
  /** SuiClient used by this agent — exposed for x402 and other integrations. */
1068
1030
  get suiClient() {
1069
1031
  return this.client;
@@ -1081,24 +1043,23 @@ var T2000 = class _T2000 extends EventEmitter {
1081
1043
  if (!(asset in SUPPORTED_ASSETS)) {
1082
1044
  throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
1083
1045
  }
1084
- await this.ensureGas();
1085
- const result = await buildAndExecuteSend({
1086
- client: this.client,
1087
- keypair: this.keypair,
1088
- to: params.to,
1089
- amount: params.amount,
1090
- asset
1091
- });
1046
+ const sendAmount = params.amount;
1047
+ const sendTo = params.to;
1048
+ const gasResult = await executeWithGas(
1049
+ this.client,
1050
+ this.keypair,
1051
+ () => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset })
1052
+ );
1092
1053
  const balance = await this.balance();
1093
- this.emitBalanceChange(asset, params.amount, "send", result.digest);
1054
+ this.emitBalanceChange(asset, sendAmount, "send", gasResult.digest);
1094
1055
  return {
1095
1056
  success: true,
1096
- tx: result.digest,
1097
- amount: params.amount,
1057
+ tx: gasResult.digest,
1058
+ amount: sendAmount,
1098
1059
  to: params.to,
1099
- gasCost: result.gasCost,
1060
+ gasCost: gasResult.gasCostSui,
1100
1061
  gasCostUnit: "SUI",
1101
- gasMethod: this._lastGasMethod,
1062
+ gasMethod: gasResult.gasMethod,
1102
1063
  balance
1103
1064
  };
1104
1065
  }
@@ -1154,11 +1115,24 @@ var T2000 = class _T2000 extends EventEmitter {
1154
1115
  amount = params.amount;
1155
1116
  }
1156
1117
  const fee = calculateFee("save", amount);
1157
- await this.ensureGas();
1158
- const result = await save(this.client, this.keypair, amount);
1159
- reportFee(this._address, "save", fee.amount, fee.rate, result.tx);
1160
- this.emitBalanceChange("USDC", amount, "save", result.tx);
1161
- return { ...result, fee: fee.amount, gasMethod: this._lastGasMethod };
1118
+ const saveAmount = amount;
1119
+ const gasResult = await executeWithGas(
1120
+ this.client,
1121
+ this.keypair,
1122
+ () => buildSaveTx(this.client, this._address, saveAmount)
1123
+ );
1124
+ const rates = await getRates(this.client);
1125
+ reportFee(this._address, "save", fee.amount, fee.rate, gasResult.digest);
1126
+ this.emitBalanceChange("USDC", saveAmount, "save", gasResult.digest);
1127
+ return {
1128
+ success: true,
1129
+ tx: gasResult.digest,
1130
+ amount: saveAmount,
1131
+ apy: rates.USDC.saveApy,
1132
+ fee: fee.amount,
1133
+ gasCost: gasResult.gasCostSui,
1134
+ gasMethod: gasResult.gasMethod
1135
+ };
1162
1136
  }
1163
1137
  async withdraw(params) {
1164
1138
  let amount;
@@ -1186,10 +1160,21 @@ var T2000 = class _T2000 extends EventEmitter {
1186
1160
  }
1187
1161
  }
1188
1162
  }
1189
- await this.ensureGas();
1190
- const result = await withdraw(this.client, this.keypair, amount);
1191
- this.emitBalanceChange("USDC", amount, "withdraw", result.tx);
1192
- return { ...result, gasMethod: this._lastGasMethod };
1163
+ const withdrawAmount = amount;
1164
+ let effectiveAmount = withdrawAmount;
1165
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1166
+ const built = await buildWithdrawTx(this.client, this._address, withdrawAmount);
1167
+ effectiveAmount = built.effectiveAmount;
1168
+ return built.tx;
1169
+ });
1170
+ this.emitBalanceChange("USDC", effectiveAmount, "withdraw", gasResult.digest);
1171
+ return {
1172
+ success: true,
1173
+ tx: gasResult.digest,
1174
+ amount: effectiveAmount,
1175
+ gasCost: gasResult.gasCostSui,
1176
+ gasMethod: gasResult.gasMethod
1177
+ };
1193
1178
  }
1194
1179
  async maxWithdraw() {
1195
1180
  return maxWithdrawAmount(this.client, this.keypair);
@@ -1204,27 +1189,52 @@ var T2000 = class _T2000 extends EventEmitter {
1204
1189
  });
1205
1190
  }
1206
1191
  const fee = calculateFee("borrow", params.amount);
1207
- await this.ensureGas();
1208
- const result = await borrow(this.client, this.keypair, params.amount);
1209
- reportFee(this._address, "borrow", fee.amount, fee.rate, result.tx);
1210
- this.emitBalanceChange("USDC", params.amount, "borrow", result.tx);
1211
- return { ...result, fee: fee.amount, gasMethod: this._lastGasMethod };
1192
+ const borrowAmount = params.amount;
1193
+ const gasResult = await executeWithGas(
1194
+ this.client,
1195
+ this.keypair,
1196
+ () => buildBorrowTx(this.client, this._address, borrowAmount)
1197
+ );
1198
+ const hf = await getHealthFactor(this.client, this.keypair);
1199
+ reportFee(this._address, "borrow", fee.amount, fee.rate, gasResult.digest);
1200
+ this.emitBalanceChange("USDC", borrowAmount, "borrow", gasResult.digest);
1201
+ return {
1202
+ success: true,
1203
+ tx: gasResult.digest,
1204
+ amount: borrowAmount,
1205
+ fee: fee.amount,
1206
+ healthFactor: hf.healthFactor,
1207
+ gasCost: gasResult.gasCostSui,
1208
+ gasMethod: gasResult.gasMethod
1209
+ };
1212
1210
  }
1213
1211
  async repay(params) {
1214
1212
  let amount;
1215
1213
  if (params.amount === "all") {
1216
- const hf = await this.healthFactor();
1217
- amount = hf.borrowed;
1214
+ const hf2 = await this.healthFactor();
1215
+ amount = hf2.borrowed;
1218
1216
  if (amount <= 0) {
1219
1217
  throw new T2000Error("NO_COLLATERAL", "No outstanding borrow to repay");
1220
1218
  }
1221
1219
  } else {
1222
1220
  amount = params.amount;
1223
1221
  }
1224
- await this.ensureGas();
1225
- const result = await repay(this.client, this.keypair, amount);
1226
- this.emitBalanceChange("USDC", amount, "repay", result.tx);
1227
- return { ...result, gasMethod: this._lastGasMethod };
1222
+ const repayAmount = amount;
1223
+ const gasResult = await executeWithGas(
1224
+ this.client,
1225
+ this.keypair,
1226
+ () => buildRepayTx(this.client, this._address, repayAmount)
1227
+ );
1228
+ const hf = await getHealthFactor(this.client, this.keypair);
1229
+ this.emitBalanceChange("USDC", repayAmount, "repay", gasResult.digest);
1230
+ return {
1231
+ success: true,
1232
+ tx: gasResult.digest,
1233
+ amount: repayAmount,
1234
+ remainingDebt: hf.borrowed,
1235
+ gasCost: gasResult.gasCostSui,
1236
+ gasMethod: gasResult.gasMethod
1237
+ };
1228
1238
  }
1229
1239
  async maxBorrow() {
1230
1240
  return maxBorrowAmount(this.client, this.keypair);
@@ -1249,28 +1259,51 @@ var T2000 = class _T2000 extends EventEmitter {
1249
1259
  throw new T2000Error("INVALID_AMOUNT", "Cannot swap same asset");
1250
1260
  }
1251
1261
  const fee = calculateFee("swap", params.amount);
1252
- await this.ensureGas();
1253
- const result = await executeSwap({
1254
- client: this.client,
1255
- keypair: this.keypair,
1256
- fromAsset,
1257
- toAsset,
1258
- amount: params.amount,
1259
- maxSlippageBps: params.maxSlippage ? params.maxSlippage * 100 : void 0
1262
+ const swapAmount = params.amount;
1263
+ const slippageBps = params.maxSlippage ? params.maxSlippage * 100 : void 0;
1264
+ let swapMeta = { estimatedOut: 0, toDecimals: 0 };
1265
+ const gasResult = await executeWithGas(this.client, this.keypair, async () => {
1266
+ const built = await buildSwapTx({
1267
+ client: this.client,
1268
+ address: this._address,
1269
+ fromAsset,
1270
+ toAsset,
1271
+ amount: swapAmount,
1272
+ maxSlippageBps: slippageBps
1273
+ });
1274
+ swapMeta = { estimatedOut: built.estimatedOut, toDecimals: built.toDecimals };
1275
+ return built.tx;
1276
+ });
1277
+ const toInfo = SUPPORTED_ASSETS[toAsset];
1278
+ const txDetail = await this.client.getTransactionBlock({
1279
+ digest: gasResult.digest,
1280
+ options: { showBalanceChanges: true }
1260
1281
  });
1261
- reportFee(this._address, "swap", fee.amount, fee.rate, result.digest);
1262
- this.emitBalanceChange(result.fromAsset, result.fromAmount, "swap", result.digest);
1282
+ let actualReceived = 0;
1283
+ if (txDetail.balanceChanges) {
1284
+ for (const change of txDetail.balanceChanges) {
1285
+ if (change.coinType === toInfo.type && change.owner && typeof change.owner === "object" && "AddressOwner" in change.owner && change.owner.AddressOwner === this._address) {
1286
+ const amt = Number(change.amount) / 10 ** toInfo.decimals;
1287
+ if (amt > 0) actualReceived += amt;
1288
+ }
1289
+ }
1290
+ }
1291
+ const expectedOutput = swapMeta.estimatedOut / 10 ** swapMeta.toDecimals;
1292
+ if (actualReceived === 0) actualReceived = expectedOutput;
1293
+ const priceImpact = expectedOutput > 0 ? Math.abs(actualReceived - expectedOutput) / expectedOutput : 0;
1294
+ reportFee(this._address, "swap", fee.amount, fee.rate, gasResult.digest);
1295
+ this.emitBalanceChange(fromAsset, swapAmount, "swap", gasResult.digest);
1263
1296
  return {
1264
1297
  success: true,
1265
- tx: result.digest,
1266
- fromAmount: result.fromAmount,
1267
- fromAsset: result.fromAsset,
1268
- toAmount: result.toAmount,
1269
- toAsset: result.toAsset,
1270
- priceImpact: result.priceImpact,
1298
+ tx: gasResult.digest,
1299
+ fromAmount: swapAmount,
1300
+ fromAsset,
1301
+ toAmount: actualReceived,
1302
+ toAsset,
1303
+ priceImpact,
1271
1304
  fee: fee.amount,
1272
- gasCost: result.gasCost,
1273
- gasMethod: this._lastGasMethod
1305
+ gasCost: gasResult.gasCostSui,
1306
+ gasMethod: gasResult.gasMethod
1274
1307
  };
1275
1308
  }
1276
1309
  async swapQuote(params) {
@@ -1401,115 +1434,6 @@ function parseMoveAbort(errorStr) {
1401
1434
  return { reason: errorStr };
1402
1435
  }
1403
1436
 
1404
- // src/gas/manager.ts
1405
- function extractGasCost3(effects) {
1406
- if (!effects?.gasUsed) return 0;
1407
- return (Number(effects.gasUsed.computationCost) + Number(effects.gasUsed.storageCost) - Number(effects.gasUsed.storageRebate)) / 1e9;
1408
- }
1409
- async function getSuiBalance(client, address) {
1410
- const bal = await client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.SUI.type });
1411
- return BigInt(bal.totalBalance);
1412
- }
1413
- async function trySelfFunded(client, keypair, tx) {
1414
- const address = keypair.getPublicKey().toSuiAddress();
1415
- const suiBalance = await getSuiBalance(client, address);
1416
- if (suiBalance < AUTO_TOPUP_THRESHOLD) return null;
1417
- tx.setSender(address);
1418
- const result = await client.signAndExecuteTransaction({
1419
- signer: keypair,
1420
- transaction: tx,
1421
- options: { showEffects: true }
1422
- });
1423
- await client.waitForTransaction({ digest: result.digest });
1424
- return {
1425
- digest: result.digest,
1426
- effects: result.effects,
1427
- gasMethod: "self-funded",
1428
- gasCostSui: extractGasCost3(result.effects)
1429
- };
1430
- }
1431
- async function tryAutoTopUpThenSelfFund(client, keypair, tx) {
1432
- const address = keypair.getPublicKey().toSuiAddress();
1433
- const canTopUp = await shouldAutoTopUp(client, address);
1434
- if (!canTopUp) return null;
1435
- try {
1436
- await executeAutoTopUp(client, keypair);
1437
- } catch {
1438
- return null;
1439
- }
1440
- tx.setSender(address);
1441
- const result = await client.signAndExecuteTransaction({
1442
- signer: keypair,
1443
- transaction: tx,
1444
- options: { showEffects: true }
1445
- });
1446
- await client.waitForTransaction({ digest: result.digest });
1447
- return {
1448
- digest: result.digest,
1449
- effects: result.effects,
1450
- gasMethod: "auto-topup",
1451
- gasCostSui: extractGasCost3(result.effects)
1452
- };
1453
- }
1454
- async function trySponsored(client, keypair, tx) {
1455
- const address = keypair.getPublicKey().toSuiAddress();
1456
- tx.setSender(address);
1457
- let txBytes;
1458
- try {
1459
- txBytes = await tx.build({ client, onlyTransactionKind: true });
1460
- } catch {
1461
- return null;
1462
- }
1463
- const txBytesBase64 = Buffer.from(txBytes).toString("base64");
1464
- let sponsoredResult;
1465
- try {
1466
- sponsoredResult = await requestGasSponsorship(txBytesBase64, address);
1467
- } catch {
1468
- return null;
1469
- }
1470
- const sponsoredTxBytes = Buffer.from(sponsoredResult.txBytes, "base64");
1471
- const { signature: agentSig } = await keypair.signTransaction(sponsoredTxBytes);
1472
- const result = await client.executeTransactionBlock({
1473
- transactionBlock: sponsoredResult.txBytes,
1474
- signature: [agentSig, sponsoredResult.sponsorSignature],
1475
- options: { showEffects: true }
1476
- });
1477
- await client.waitForTransaction({ digest: result.digest });
1478
- const gasCost = extractGasCost3(result.effects);
1479
- reportGasUsage(address, result.digest, gasCost, 0, sponsoredResult.type);
1480
- return {
1481
- digest: result.digest,
1482
- effects: result.effects,
1483
- gasMethod: "sponsored",
1484
- gasCostSui: gasCost
1485
- };
1486
- }
1487
- async function executeWithGas(client, keypair, buildTx) {
1488
- try {
1489
- const tx = await buildTx();
1490
- const result = await trySelfFunded(client, keypair, tx);
1491
- if (result) return result;
1492
- } catch {
1493
- }
1494
- try {
1495
- const tx = await buildTx();
1496
- const result = await tryAutoTopUpThenSelfFund(client, keypair, tx);
1497
- if (result) return result;
1498
- } catch {
1499
- }
1500
- try {
1501
- const tx = await buildTx();
1502
- const result = await trySponsored(client, keypair, tx);
1503
- if (result) return result;
1504
- } catch {
1505
- }
1506
- throw new T2000Error(
1507
- "INSUFFICIENT_GAS",
1508
- "No SUI for gas and Gas Station unavailable. Fund your wallet with SUI or USDC.",
1509
- { reason: "all_gas_methods_exhausted" }
1510
- );
1511
- }
1512
-
1513
1437
  export { BPS_DENOMINATOR, CLOCK_ID, DEFAULT_NETWORK, MIST_PER_SUI, SUI_DECIMALS, SUPPORTED_ASSETS, T2000, T2000Error, USDC_DECIMALS, calculateFee, executeAutoTopUp, executeWithGas, exportPrivateKey, formatSui, formatUsd, generateKeypair, getAddress, getGasStatus, getPoolPrice, getRates, getSwapQuote, keypairFromPrivateKey, loadKey, mapMoveAbortCode, mapWalletError, mistToSui, rawToUsdc, saveKey, shouldAutoTopUp, simulateTransaction, solveHashcash, suiToMist, throwIfSimulationFailed, truncateAddress, usdcToRaw, validateAddress, walletExists };
1514
1438
  //# sourceMappingURL=index.js.map
1515
1439
  //# sourceMappingURL=index.js.map