@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/LICENSE +21 -0
- package/README.md +39 -2
- package/dist/adapters/index.cjs +10 -8
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js +10 -8
- package/dist/adapters/index.js.map +1 -1
- package/dist/index.cjs +74 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +74 -63
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
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
|
|
2133
|
-
const
|
|
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
|
|
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
|
|
2179
|
-
const
|
|
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
|
|
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
|
|
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(
|
|
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,
|
|
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
|
-
|
|
2544
|
-
|
|
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
|
|
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) {
|