@t2000/sdk 0.10.4 → 0.11.1
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/README.md +19 -1
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/index.cjs +189 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -3
- package/dist/index.d.ts +61 -3
- package/dist/index.js +187 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var path = require('path');
|
|
|
12
12
|
var os = require('os');
|
|
13
13
|
var bcs = require('@mysten/sui/bcs');
|
|
14
14
|
var aggregatorSdk = require('@cetusprotocol/aggregator-sdk');
|
|
15
|
+
var fs = require('fs');
|
|
15
16
|
|
|
16
17
|
// src/t2000.ts
|
|
17
18
|
|
|
@@ -2496,7 +2497,10 @@ async function trySponsored(client, keypair, tx) {
|
|
|
2496
2497
|
gasCostSui: gasCost
|
|
2497
2498
|
};
|
|
2498
2499
|
}
|
|
2499
|
-
async function executeWithGas(client, keypair, buildTx) {
|
|
2500
|
+
async function executeWithGas(client, keypair, buildTx, options) {
|
|
2501
|
+
if (options?.enforcer && options?.metadata) {
|
|
2502
|
+
options.enforcer.check(options.metadata);
|
|
2503
|
+
}
|
|
2500
2504
|
const errors = [];
|
|
2501
2505
|
try {
|
|
2502
2506
|
const tx = await buildTx();
|
|
@@ -2533,18 +2537,182 @@ async function executeWithGas(client, keypair, buildTx) {
|
|
|
2533
2537
|
);
|
|
2534
2538
|
}
|
|
2535
2539
|
|
|
2536
|
-
// src/
|
|
2540
|
+
// src/safeguards/types.ts
|
|
2541
|
+
var OUTBOUND_OPS = /* @__PURE__ */ new Set([
|
|
2542
|
+
"send",
|
|
2543
|
+
"pay",
|
|
2544
|
+
"sentinel"
|
|
2545
|
+
]);
|
|
2546
|
+
var DEFAULT_SAFEGUARD_CONFIG = {
|
|
2547
|
+
locked: false,
|
|
2548
|
+
maxPerTx: 0,
|
|
2549
|
+
maxDailySend: 0,
|
|
2550
|
+
dailyUsed: 0,
|
|
2551
|
+
dailyResetDate: ""
|
|
2552
|
+
};
|
|
2553
|
+
|
|
2554
|
+
// src/safeguards/errors.ts
|
|
2555
|
+
var SafeguardError = class extends T2000Error {
|
|
2556
|
+
rule;
|
|
2557
|
+
details;
|
|
2558
|
+
constructor(rule, details, message) {
|
|
2559
|
+
const msg = message ?? buildMessage(rule, details);
|
|
2560
|
+
super("SAFEGUARD_BLOCKED", msg, { rule, ...details });
|
|
2561
|
+
this.name = "SafeguardError";
|
|
2562
|
+
this.rule = rule;
|
|
2563
|
+
this.details = details;
|
|
2564
|
+
}
|
|
2565
|
+
toJSON() {
|
|
2566
|
+
return {
|
|
2567
|
+
error: "SAFEGUARD_BLOCKED",
|
|
2568
|
+
message: this.message,
|
|
2569
|
+
retryable: this.retryable,
|
|
2570
|
+
data: { rule: this.rule, ...this.details }
|
|
2571
|
+
};
|
|
2572
|
+
}
|
|
2573
|
+
};
|
|
2574
|
+
function buildMessage(rule, details) {
|
|
2575
|
+
switch (rule) {
|
|
2576
|
+
case "locked":
|
|
2577
|
+
return "Agent is locked. All operations are frozen.";
|
|
2578
|
+
case "maxPerTx":
|
|
2579
|
+
return `Amount $${(details.attempted ?? 0).toFixed(2)} exceeds per-transaction limit ($${(details.limit ?? 0).toFixed(2)})`;
|
|
2580
|
+
case "maxDailySend":
|
|
2581
|
+
return `Daily send limit reached ($${(details.current ?? 0).toFixed(2)}/$${(details.limit ?? 0).toFixed(2)} used today)`;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
// src/safeguards/enforcer.ts
|
|
2586
|
+
var SafeguardEnforcer = class {
|
|
2587
|
+
config;
|
|
2588
|
+
configPath;
|
|
2589
|
+
constructor(configDir) {
|
|
2590
|
+
this.config = { ...DEFAULT_SAFEGUARD_CONFIG };
|
|
2591
|
+
this.configPath = configDir ? path.join(configDir, "config.json") : null;
|
|
2592
|
+
}
|
|
2593
|
+
load() {
|
|
2594
|
+
if (!this.configPath) return;
|
|
2595
|
+
try {
|
|
2596
|
+
const raw = JSON.parse(fs.readFileSync(this.configPath, "utf-8"));
|
|
2597
|
+
this.config = {
|
|
2598
|
+
...DEFAULT_SAFEGUARD_CONFIG,
|
|
2599
|
+
locked: raw.locked ?? false,
|
|
2600
|
+
maxPerTx: raw.maxPerTx ?? 0,
|
|
2601
|
+
maxDailySend: raw.maxDailySend ?? 0,
|
|
2602
|
+
dailyUsed: raw.dailyUsed ?? 0,
|
|
2603
|
+
dailyResetDate: raw.dailyResetDate ?? ""
|
|
2604
|
+
};
|
|
2605
|
+
} catch {
|
|
2606
|
+
this.config = { ...DEFAULT_SAFEGUARD_CONFIG };
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
assertNotLocked() {
|
|
2610
|
+
this.load();
|
|
2611
|
+
if (this.config.locked) {
|
|
2612
|
+
throw new SafeguardError("locked", {});
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
check(metadata) {
|
|
2616
|
+
this.load();
|
|
2617
|
+
if (this.config.locked) {
|
|
2618
|
+
throw new SafeguardError("locked", {});
|
|
2619
|
+
}
|
|
2620
|
+
if (!OUTBOUND_OPS.has(metadata.operation)) return;
|
|
2621
|
+
const amount = metadata.amount ?? 0;
|
|
2622
|
+
if (this.config.maxPerTx > 0 && amount > this.config.maxPerTx) {
|
|
2623
|
+
throw new SafeguardError("maxPerTx", {
|
|
2624
|
+
attempted: amount,
|
|
2625
|
+
limit: this.config.maxPerTx
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
this.resetDailyIfNewDay();
|
|
2629
|
+
if (this.config.maxDailySend > 0 && this.config.dailyUsed + amount > this.config.maxDailySend) {
|
|
2630
|
+
throw new SafeguardError("maxDailySend", {
|
|
2631
|
+
attempted: amount,
|
|
2632
|
+
limit: this.config.maxDailySend,
|
|
2633
|
+
current: this.config.dailyUsed
|
|
2634
|
+
});
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
recordUsage(amount) {
|
|
2638
|
+
this.resetDailyIfNewDay();
|
|
2639
|
+
this.config.dailyUsed += amount;
|
|
2640
|
+
this.save();
|
|
2641
|
+
}
|
|
2642
|
+
lock() {
|
|
2643
|
+
this.config.locked = true;
|
|
2644
|
+
this.save();
|
|
2645
|
+
}
|
|
2646
|
+
unlock() {
|
|
2647
|
+
this.config.locked = false;
|
|
2648
|
+
this.save();
|
|
2649
|
+
}
|
|
2650
|
+
set(key, value) {
|
|
2651
|
+
if (key === "locked" && typeof value === "boolean") {
|
|
2652
|
+
this.config.locked = value;
|
|
2653
|
+
} else if (key === "maxPerTx" && typeof value === "number") {
|
|
2654
|
+
this.config.maxPerTx = value;
|
|
2655
|
+
} else if (key === "maxDailySend" && typeof value === "number") {
|
|
2656
|
+
this.config.maxDailySend = value;
|
|
2657
|
+
}
|
|
2658
|
+
this.save();
|
|
2659
|
+
}
|
|
2660
|
+
getConfig() {
|
|
2661
|
+
this.load();
|
|
2662
|
+
this.resetDailyIfNewDay();
|
|
2663
|
+
return { ...this.config };
|
|
2664
|
+
}
|
|
2665
|
+
isConfigured() {
|
|
2666
|
+
return this.config.maxPerTx > 0 || this.config.maxDailySend > 0;
|
|
2667
|
+
}
|
|
2668
|
+
resetDailyIfNewDay() {
|
|
2669
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2670
|
+
if (this.config.dailyResetDate !== today) {
|
|
2671
|
+
this.config.dailyUsed = 0;
|
|
2672
|
+
this.config.dailyResetDate = today;
|
|
2673
|
+
this.save();
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
save() {
|
|
2677
|
+
if (!this.configPath) return;
|
|
2678
|
+
try {
|
|
2679
|
+
let existing = {};
|
|
2680
|
+
try {
|
|
2681
|
+
existing = JSON.parse(fs.readFileSync(this.configPath, "utf-8"));
|
|
2682
|
+
} catch {
|
|
2683
|
+
}
|
|
2684
|
+
const merged = {
|
|
2685
|
+
...existing,
|
|
2686
|
+
locked: this.config.locked,
|
|
2687
|
+
maxPerTx: this.config.maxPerTx,
|
|
2688
|
+
maxDailySend: this.config.maxDailySend,
|
|
2689
|
+
dailyUsed: this.config.dailyUsed,
|
|
2690
|
+
dailyResetDate: this.config.dailyResetDate
|
|
2691
|
+
};
|
|
2692
|
+
const dir = this.configPath.replace(/[/\\][^/\\]+$/, "");
|
|
2693
|
+
if (!fs.existsSync(dir)) {
|
|
2694
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2695
|
+
}
|
|
2696
|
+
fs.writeFileSync(this.configPath, JSON.stringify(merged, null, 2) + "\n");
|
|
2697
|
+
} catch {
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
};
|
|
2701
|
+
var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".t2000");
|
|
2537
2702
|
var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
2538
2703
|
keypair;
|
|
2539
2704
|
client;
|
|
2540
2705
|
_address;
|
|
2541
2706
|
registry;
|
|
2542
|
-
|
|
2707
|
+
enforcer;
|
|
2708
|
+
constructor(keypair, client, registry, configDir) {
|
|
2543
2709
|
super();
|
|
2544
2710
|
this.keypair = keypair;
|
|
2545
2711
|
this.client = client;
|
|
2546
2712
|
this._address = getAddress(keypair);
|
|
2547
2713
|
this.registry = registry ?? _T2000.createDefaultRegistry(client);
|
|
2714
|
+
this.enforcer = new SafeguardEnforcer(configDir);
|
|
2715
|
+
this.enforcer.load();
|
|
2548
2716
|
}
|
|
2549
2717
|
static createDefaultRegistry(client) {
|
|
2550
2718
|
const registry = new ProtocolRegistry();
|
|
@@ -2568,7 +2736,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2568
2736
|
if (secret) {
|
|
2569
2737
|
await saveKey(keypair2, secret, keyPath);
|
|
2570
2738
|
}
|
|
2571
|
-
return new _T2000(keypair2, client);
|
|
2739
|
+
return new _T2000(keypair2, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2572
2740
|
}
|
|
2573
2741
|
const exists = await walletExists(keyPath);
|
|
2574
2742
|
if (!exists) {
|
|
@@ -2581,7 +2749,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2581
2749
|
throw new T2000Error("WALLET_LOCKED", "PIN required to unlock wallet");
|
|
2582
2750
|
}
|
|
2583
2751
|
const keypair = await loadKey(secret, keyPath);
|
|
2584
|
-
return new _T2000(keypair, client);
|
|
2752
|
+
return new _T2000(keypair, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2585
2753
|
}
|
|
2586
2754
|
static fromPrivateKey(privateKey, options = {}) {
|
|
2587
2755
|
const keypair = keypairFromPrivateKey(privateKey);
|
|
@@ -2593,7 +2761,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2593
2761
|
const keypair = generateKeypair();
|
|
2594
2762
|
await saveKey(keypair, secret, options.keyPath);
|
|
2595
2763
|
const client = getSuiClient();
|
|
2596
|
-
const agent = new _T2000(keypair, client);
|
|
2764
|
+
const agent = new _T2000(keypair, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2597
2765
|
const address = agent.address();
|
|
2598
2766
|
let sponsored = false;
|
|
2599
2767
|
if (options.sponsored !== false) {
|
|
@@ -2619,6 +2787,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2619
2787
|
return this._address;
|
|
2620
2788
|
}
|
|
2621
2789
|
async send(params) {
|
|
2790
|
+
this.enforcer.assertNotLocked();
|
|
2622
2791
|
const asset = params.asset ?? "USDC";
|
|
2623
2792
|
if (!(asset in SUPPORTED_ASSETS)) {
|
|
2624
2793
|
throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
|
|
@@ -2628,8 +2797,10 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2628
2797
|
const gasResult = await executeWithGas(
|
|
2629
2798
|
this.client,
|
|
2630
2799
|
this.keypair,
|
|
2631
|
-
() => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset })
|
|
2800
|
+
() => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset }),
|
|
2801
|
+
{ metadata: { operation: "send", amount: sendAmount }, enforcer: this.enforcer }
|
|
2632
2802
|
);
|
|
2803
|
+
this.enforcer.recordUsage(sendAmount);
|
|
2633
2804
|
const balance = await this.balance();
|
|
2634
2805
|
this.emitBalanceChange(asset, sendAmount, "send", gasResult.digest);
|
|
2635
2806
|
return {
|
|
@@ -2685,6 +2856,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2685
2856
|
}
|
|
2686
2857
|
// -- Savings --
|
|
2687
2858
|
async save(params) {
|
|
2859
|
+
this.enforcer.assertNotLocked();
|
|
2688
2860
|
const asset = "USDC";
|
|
2689
2861
|
const bal = await queryBalance(this.client, this._address);
|
|
2690
2862
|
const usdcBalance = bal.stables.USDC ?? 0;
|
|
@@ -2779,6 +2951,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2779
2951
|
};
|
|
2780
2952
|
}
|
|
2781
2953
|
async withdraw(params) {
|
|
2954
|
+
this.enforcer.assertNotLocked();
|
|
2782
2955
|
if (params.amount === "all" && !params.protocol) {
|
|
2783
2956
|
return this.withdrawAllProtocols();
|
|
2784
2957
|
}
|
|
@@ -3016,6 +3189,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3016
3189
|
}
|
|
3017
3190
|
// -- Borrowing --
|
|
3018
3191
|
async borrow(params) {
|
|
3192
|
+
this.enforcer.assertNotLocked();
|
|
3019
3193
|
const asset = "USDC";
|
|
3020
3194
|
const adapter = await this.resolveLending(params.protocol, asset, "borrow");
|
|
3021
3195
|
const maxResult = await adapter.maxBorrow(this._address, asset);
|
|
@@ -3048,6 +3222,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3048
3222
|
};
|
|
3049
3223
|
}
|
|
3050
3224
|
async repay(params) {
|
|
3225
|
+
this.enforcer.assertNotLocked();
|
|
3051
3226
|
const allPositions = await this.registry.allPositions(this._address);
|
|
3052
3227
|
const borrows = [];
|
|
3053
3228
|
for (const pos of allPositions) {
|
|
@@ -3201,6 +3376,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3201
3376
|
}
|
|
3202
3377
|
// -- Exchange --
|
|
3203
3378
|
async exchange(params) {
|
|
3379
|
+
this.enforcer.assertNotLocked();
|
|
3204
3380
|
const fromAsset = params.from;
|
|
3205
3381
|
const toAsset = params.to;
|
|
3206
3382
|
if (!(fromAsset in SUPPORTED_ASSETS) || !(toAsset in SUPPORTED_ASSETS)) {
|
|
@@ -3301,6 +3477,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3301
3477
|
return this.registry.allRatesAcrossAssets();
|
|
3302
3478
|
}
|
|
3303
3479
|
async rebalance(opts = {}) {
|
|
3480
|
+
this.enforcer.assertNotLocked();
|
|
3304
3481
|
const dryRun = opts.dryRun ?? false;
|
|
3305
3482
|
const minYieldDiff = opts.minYieldDiff ?? 0.5;
|
|
3306
3483
|
const maxBreakEven = opts.maxBreakEven ?? 30;
|
|
@@ -3582,6 +3759,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3582
3759
|
return getSentinelInfo(this.client, id);
|
|
3583
3760
|
}
|
|
3584
3761
|
async sentinelAttack(id, prompt, fee) {
|
|
3762
|
+
this.enforcer.check({ operation: "sentinel", amount: fee ? Number(fee) / 1e9 : 0.1 });
|
|
3585
3763
|
return attack(this.client, this.keypair, id, prompt, fee);
|
|
3586
3764
|
}
|
|
3587
3765
|
// -- Helpers --
|
|
@@ -3737,12 +3915,16 @@ exports.BPS_DENOMINATOR = BPS_DENOMINATOR;
|
|
|
3737
3915
|
exports.CLOCK_ID = CLOCK_ID;
|
|
3738
3916
|
exports.CetusAdapter = CetusAdapter;
|
|
3739
3917
|
exports.DEFAULT_NETWORK = DEFAULT_NETWORK;
|
|
3918
|
+
exports.DEFAULT_SAFEGUARD_CONFIG = DEFAULT_SAFEGUARD_CONFIG;
|
|
3740
3919
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
3741
3920
|
exports.NaviAdapter = NaviAdapter;
|
|
3921
|
+
exports.OUTBOUND_OPS = OUTBOUND_OPS;
|
|
3742
3922
|
exports.ProtocolRegistry = ProtocolRegistry;
|
|
3743
3923
|
exports.SENTINEL = SENTINEL;
|
|
3744
3924
|
exports.SUI_DECIMALS = SUI_DECIMALS;
|
|
3745
3925
|
exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
3926
|
+
exports.SafeguardEnforcer = SafeguardEnforcer;
|
|
3927
|
+
exports.SafeguardError = SafeguardError;
|
|
3746
3928
|
exports.SuilendAdapter = SuilendAdapter;
|
|
3747
3929
|
exports.T2000 = T2000;
|
|
3748
3930
|
exports.T2000Error = T2000Error;
|