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