@t2000/sdk 0.16.2 → 0.16.7

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
@@ -2129,12 +2129,13 @@ var SuilendAdapter = class {
2129
2129
  if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `${assetInfo.displayName} reserve not found on Suilend`);
2130
2130
  const caps = await this.fetchObligationCaps(address);
2131
2131
  if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
2132
- const positions = await this.getPositions(address);
2133
- const deposited = positions.supplies.find((s) => s.asset === assetKey)?.amount ?? 0;
2132
+ const obligation = await this.fetchObligation(caps[0].obligationId);
2133
+ const dep = obligation.deposits.find((d) => d.reserveIdx === reserve.arrayIndex);
2134
+ const ratio = cTokenRatio(reserve);
2135
+ const deposited = dep ? dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals : 0;
2134
2136
  const effectiveAmount = Math.min(amount, deposited);
2135
2137
  if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on Suilend`);
2136
- const ratio = cTokenRatio(reserve);
2137
- const ctokenAmount = Math.ceil(effectiveAmount * 10 ** reserve.mintDecimals / ratio);
2138
+ const ctokenAmount = dep && effectiveAmount >= deposited * 0.999 ? dep.ctokenAmount : Math.floor(effectiveAmount * 10 ** reserve.mintDecimals / ratio);
2138
2139
  const tx = new transactions.Transaction();
2139
2140
  tx.setSender(address);
2140
2141
  const [ctokens] = tx.moveCall({
@@ -2175,12 +2176,13 @@ var SuilendAdapter = class {
2175
2176
  if (!reserve) throw new T2000Error("ASSET_NOT_SUPPORTED", `${assetInfo.displayName} reserve not found on Suilend`);
2176
2177
  const caps = await this.fetchObligationCaps(address);
2177
2178
  if (caps.length === 0) throw new T2000Error("NO_COLLATERAL", "No Suilend position found");
2178
- const positions = await this.getPositions(address);
2179
- const deposited = positions.supplies.find((s) => s.asset === assetKey)?.amount ?? 0;
2179
+ const obligation = await this.fetchObligation(caps[0].obligationId);
2180
+ const dep = obligation.deposits.find((d) => d.reserveIdx === reserve.arrayIndex);
2181
+ const ratio = cTokenRatio(reserve);
2182
+ const deposited = dep ? dep.ctokenAmount * ratio / 10 ** reserve.mintDecimals : 0;
2180
2183
  const effectiveAmount = Math.min(amount, deposited);
2181
2184
  if (effectiveAmount <= 0) throw new T2000Error("NO_COLLATERAL", `Nothing to withdraw for ${assetInfo.displayName} on Suilend`);
2182
- const ratio = cTokenRatio(reserve);
2183
- const ctokenAmount = Math.ceil(effectiveAmount * 10 ** reserve.mintDecimals / ratio);
2185
+ const ctokenAmount = dep && effectiveAmount >= deposited * 0.999 ? dep.ctokenAmount : Math.floor(effectiveAmount * 10 ** reserve.mintDecimals / ratio);
2184
2186
  const [ctokens] = tx.moveCall({
2185
2187
  target: `${pkg}::lending_market::withdraw_ctokens`,
2186
2188
  typeArguments: [LENDING_MARKET_TYPE, assetInfo.type],
@@ -2388,13 +2390,62 @@ function solveHashcash(challenge) {
2388
2390
  }
2389
2391
  }
2390
2392
 
2393
+ // src/gas/autoTopUp.ts
2394
+ var AUTO_TOPUP_MIN_SUI_FOR_GAS = 5000000n;
2395
+ async function shouldAutoTopUp(client, address) {
2396
+ const [suiBalance, usdcBalance] = await Promise.all([
2397
+ client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.SUI.type }),
2398
+ client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.USDC.type })
2399
+ ]);
2400
+ const suiRaw = BigInt(suiBalance.totalBalance);
2401
+ const usdcRaw = BigInt(usdcBalance.totalBalance);
2402
+ return suiRaw < AUTO_TOPUP_THRESHOLD && suiRaw >= AUTO_TOPUP_MIN_SUI_FOR_GAS && usdcRaw >= AUTO_TOPUP_MIN_USDC;
2403
+ }
2404
+ async function executeAutoTopUp(client, keypair) {
2405
+ const address = keypair.getPublicKey().toSuiAddress();
2406
+ const topupAmountHuman = Number(AUTO_TOPUP_AMOUNT) / 1e6;
2407
+ const { tx } = await buildSwapTx({
2408
+ client,
2409
+ address,
2410
+ fromAsset: "USDC",
2411
+ toAsset: "SUI",
2412
+ amount: topupAmountHuman
2413
+ });
2414
+ const result = await client.signAndExecuteTransaction({
2415
+ signer: keypair,
2416
+ transaction: tx,
2417
+ options: { showEffects: true, showBalanceChanges: true }
2418
+ });
2419
+ await client.waitForTransaction({ digest: result.digest });
2420
+ let suiReceived = 0;
2421
+ if (result.balanceChanges) {
2422
+ for (const change of result.balanceChanges) {
2423
+ if (change.coinType === SUPPORTED_ASSETS.SUI.type && change.owner && typeof change.owner === "object" && "AddressOwner" in change.owner && change.owner.AddressOwner === address) {
2424
+ suiReceived += Number(change.amount) / Number(MIST_PER_SUI);
2425
+ }
2426
+ }
2427
+ }
2428
+ return {
2429
+ success: true,
2430
+ tx: result.digest,
2431
+ usdcSpent: topupAmountHuman,
2432
+ suiReceived: Math.abs(suiReceived)
2433
+ };
2434
+ }
2435
+
2391
2436
  // src/gas/gasStation.ts
2392
- async function requestGasSponsorship(txJson, sender, type) {
2393
- const txBytes = Buffer.from(txJson).toString("base64");
2437
+ async function requestGasSponsorship(txJson, sender, type, txBcsBytes) {
2438
+ const payload = { sender, type };
2439
+ if (txBcsBytes) {
2440
+ payload.txBcsBytes = txBcsBytes;
2441
+ } else {
2442
+ payload.txJson = txJson;
2443
+ payload.txBytes = Buffer.from(txJson).toString("base64");
2444
+ }
2394
2445
  const res = await fetch(`${API_BASE_URL}/api/gas`, {
2395
2446
  method: "POST",
2396
2447
  headers: { "Content-Type": "application/json" },
2397
- body: JSON.stringify({ txJson, txBytes, sender, type })
2448
+ body: JSON.stringify(payload)
2398
2449
  });
2399
2450
  const data = await res.json();
2400
2451
  if (!res.ok) {
@@ -2444,53 +2495,6 @@ async function getGasStatus(address) {
2444
2495
  return await res.json();
2445
2496
  }
2446
2497
 
2447
- // src/gas/autoTopUp.ts
2448
- async function shouldAutoTopUp(client, address) {
2449
- const [suiBalance, usdcBalance] = await Promise.all([
2450
- client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.SUI.type }),
2451
- client.getBalance({ owner: address, coinType: SUPPORTED_ASSETS.USDC.type })
2452
- ]);
2453
- const suiRaw = BigInt(suiBalance.totalBalance);
2454
- const usdcRaw = BigInt(usdcBalance.totalBalance);
2455
- return suiRaw < AUTO_TOPUP_THRESHOLD && usdcRaw >= AUTO_TOPUP_MIN_USDC;
2456
- }
2457
- async function executeAutoTopUp(client, keypair) {
2458
- const address = keypair.getPublicKey().toSuiAddress();
2459
- const topupAmountHuman = Number(AUTO_TOPUP_AMOUNT) / 1e6;
2460
- const { tx } = await buildSwapTx({
2461
- client,
2462
- address,
2463
- fromAsset: "USDC",
2464
- toAsset: "SUI",
2465
- amount: topupAmountHuman
2466
- });
2467
- const txJson = tx.serialize();
2468
- const sponsoredResult = await requestGasSponsorship(txJson, address, "auto-topup");
2469
- const sponsoredTxBytes = Buffer.from(sponsoredResult.txBytes, "base64");
2470
- const { signature: agentSig } = await keypair.signTransaction(sponsoredTxBytes);
2471
- const result = await client.executeTransactionBlock({
2472
- transactionBlock: sponsoredResult.txBytes,
2473
- signature: [agentSig, sponsoredResult.sponsorSignature],
2474
- options: { showEffects: true, showBalanceChanges: true }
2475
- });
2476
- await client.waitForTransaction({ digest: result.digest });
2477
- let suiReceived = 0;
2478
- if (result.balanceChanges) {
2479
- for (const change of result.balanceChanges) {
2480
- if (change.coinType === SUPPORTED_ASSETS.SUI.type && change.owner && typeof change.owner === "object" && "AddressOwner" in change.owner && change.owner.AddressOwner === address) {
2481
- suiReceived += Number(change.amount) / Number(MIST_PER_SUI);
2482
- }
2483
- }
2484
- }
2485
- reportGasUsage(address, result.digest, 0, 0, "auto-topup");
2486
- return {
2487
- success: true,
2488
- tx: result.digest,
2489
- usdcSpent: topupAmountHuman,
2490
- suiReceived: Math.abs(suiReceived)
2491
- };
2492
- }
2493
-
2494
2498
  // src/gas/manager.ts
2495
2499
  function extractGasCost(effects) {
2496
2500
  if (!effects?.gasUsed) return 0;
@@ -2518,11 +2522,12 @@ async function trySelfFunded(client, keypair, tx) {
2518
2522
  gasCostSui: extractGasCost(result.effects)
2519
2523
  };
2520
2524
  }
2521
- async function tryAutoTopUpThenSelfFund(client, keypair, tx) {
2525
+ async function tryAutoTopUpThenSelfFund(client, keypair, buildTx) {
2522
2526
  const address = keypair.getPublicKey().toSuiAddress();
2523
2527
  const canTopUp = await shouldAutoTopUp(client, address);
2524
2528
  if (!canTopUp) return null;
2525
2529
  await executeAutoTopUp(client, keypair);
2530
+ const tx = await buildTx();
2526
2531
  tx.setSender(address);
2527
2532
  const result = await client.signAndExecuteTransaction({
2528
2533
  signer: keypair,
@@ -2540,8 +2545,15 @@ async function tryAutoTopUpThenSelfFund(client, keypair, tx) {
2540
2545
  async function trySponsored(client, keypair, tx) {
2541
2546
  const address = keypair.getPublicKey().toSuiAddress();
2542
2547
  tx.setSender(address);
2543
- const txJson = tx.serialize();
2544
- const sponsoredResult = await requestGasSponsorship(txJson, address);
2548
+ let txJson;
2549
+ let txBcsBase64;
2550
+ try {
2551
+ txJson = tx.serialize();
2552
+ } catch {
2553
+ const bcsBytes = await tx.build({ client });
2554
+ txBcsBase64 = Buffer.from(bcsBytes).toString("base64");
2555
+ }
2556
+ const sponsoredResult = await requestGasSponsorship(txJson ?? "", address, void 0, txBcsBase64);
2545
2557
  const sponsoredTxBytes = Buffer.from(sponsoredResult.txBytes, "base64");
2546
2558
  const { signature: agentSig } = await keypair.signTransaction(sponsoredTxBytes);
2547
2559
  const result = await client.executeTransactionBlock({
@@ -2577,8 +2589,7 @@ async function executeWithGas(client, keypair, buildTx, options) {
2577
2589
  errors.push(`self-funded: ${msg}`);
2578
2590
  }
2579
2591
  try {
2580
- const tx = await buildTx();
2581
- const result = await tryAutoTopUpThenSelfFund(client, keypair, tx);
2592
+ const result = await tryAutoTopUpThenSelfFund(client, keypair, buildTx);
2582
2593
  if (result) return result;
2583
2594
  errors.push("auto-topup: not eligible (low USDC or sufficient SUI)");
2584
2595
  } catch (err) {