@t2000/sdk 0.10.4 → 0.11.0
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 +14 -0
- package/dist/adapters/index.cjs.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/index.cjs +184 -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 +182 -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,177 @@ 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
|
+
if (this.config.locked) {
|
|
2611
|
+
throw new SafeguardError("locked", {});
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
check(metadata) {
|
|
2615
|
+
this.assertNotLocked();
|
|
2616
|
+
if (!OUTBOUND_OPS.has(metadata.operation)) return;
|
|
2617
|
+
const amount = metadata.amount ?? 0;
|
|
2618
|
+
if (this.config.maxPerTx > 0 && amount > this.config.maxPerTx) {
|
|
2619
|
+
throw new SafeguardError("maxPerTx", {
|
|
2620
|
+
attempted: amount,
|
|
2621
|
+
limit: this.config.maxPerTx
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2624
|
+
this.resetDailyIfNewDay();
|
|
2625
|
+
if (this.config.maxDailySend > 0 && this.config.dailyUsed + amount > this.config.maxDailySend) {
|
|
2626
|
+
throw new SafeguardError("maxDailySend", {
|
|
2627
|
+
attempted: amount,
|
|
2628
|
+
limit: this.config.maxDailySend,
|
|
2629
|
+
current: this.config.dailyUsed
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
recordUsage(amount) {
|
|
2634
|
+
this.resetDailyIfNewDay();
|
|
2635
|
+
this.config.dailyUsed += amount;
|
|
2636
|
+
this.save();
|
|
2637
|
+
}
|
|
2638
|
+
lock() {
|
|
2639
|
+
this.config.locked = true;
|
|
2640
|
+
this.save();
|
|
2641
|
+
}
|
|
2642
|
+
unlock() {
|
|
2643
|
+
this.config.locked = false;
|
|
2644
|
+
this.save();
|
|
2645
|
+
}
|
|
2646
|
+
set(key, value) {
|
|
2647
|
+
if (key === "locked" && typeof value === "boolean") {
|
|
2648
|
+
this.config.locked = value;
|
|
2649
|
+
} else if (key === "maxPerTx" && typeof value === "number") {
|
|
2650
|
+
this.config.maxPerTx = value;
|
|
2651
|
+
} else if (key === "maxDailySend" && typeof value === "number") {
|
|
2652
|
+
this.config.maxDailySend = value;
|
|
2653
|
+
}
|
|
2654
|
+
this.save();
|
|
2655
|
+
}
|
|
2656
|
+
getConfig() {
|
|
2657
|
+
this.resetDailyIfNewDay();
|
|
2658
|
+
return { ...this.config };
|
|
2659
|
+
}
|
|
2660
|
+
isConfigured() {
|
|
2661
|
+
return this.config.maxPerTx > 0 || this.config.maxDailySend > 0;
|
|
2662
|
+
}
|
|
2663
|
+
resetDailyIfNewDay() {
|
|
2664
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2665
|
+
if (this.config.dailyResetDate !== today) {
|
|
2666
|
+
this.config.dailyUsed = 0;
|
|
2667
|
+
this.config.dailyResetDate = today;
|
|
2668
|
+
this.save();
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
save() {
|
|
2672
|
+
if (!this.configPath) return;
|
|
2673
|
+
try {
|
|
2674
|
+
let existing = {};
|
|
2675
|
+
try {
|
|
2676
|
+
existing = JSON.parse(fs.readFileSync(this.configPath, "utf-8"));
|
|
2677
|
+
} catch {
|
|
2678
|
+
}
|
|
2679
|
+
const merged = {
|
|
2680
|
+
...existing,
|
|
2681
|
+
locked: this.config.locked,
|
|
2682
|
+
maxPerTx: this.config.maxPerTx,
|
|
2683
|
+
maxDailySend: this.config.maxDailySend,
|
|
2684
|
+
dailyUsed: this.config.dailyUsed,
|
|
2685
|
+
dailyResetDate: this.config.dailyResetDate
|
|
2686
|
+
};
|
|
2687
|
+
const dir = this.configPath.replace(/[/\\][^/\\]+$/, "");
|
|
2688
|
+
if (!fs.existsSync(dir)) {
|
|
2689
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
2690
|
+
}
|
|
2691
|
+
fs.writeFileSync(this.configPath, JSON.stringify(merged, null, 2) + "\n");
|
|
2692
|
+
} catch {
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
};
|
|
2696
|
+
var DEFAULT_CONFIG_DIR = path.join(os.homedir(), ".t2000");
|
|
2537
2697
|
var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
2538
2698
|
keypair;
|
|
2539
2699
|
client;
|
|
2540
2700
|
_address;
|
|
2541
2701
|
registry;
|
|
2542
|
-
|
|
2702
|
+
enforcer;
|
|
2703
|
+
constructor(keypair, client, registry, configDir) {
|
|
2543
2704
|
super();
|
|
2544
2705
|
this.keypair = keypair;
|
|
2545
2706
|
this.client = client;
|
|
2546
2707
|
this._address = getAddress(keypair);
|
|
2547
2708
|
this.registry = registry ?? _T2000.createDefaultRegistry(client);
|
|
2709
|
+
this.enforcer = new SafeguardEnforcer(configDir);
|
|
2710
|
+
this.enforcer.load();
|
|
2548
2711
|
}
|
|
2549
2712
|
static createDefaultRegistry(client) {
|
|
2550
2713
|
const registry = new ProtocolRegistry();
|
|
@@ -2568,7 +2731,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2568
2731
|
if (secret) {
|
|
2569
2732
|
await saveKey(keypair2, secret, keyPath);
|
|
2570
2733
|
}
|
|
2571
|
-
return new _T2000(keypair2, client);
|
|
2734
|
+
return new _T2000(keypair2, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2572
2735
|
}
|
|
2573
2736
|
const exists = await walletExists(keyPath);
|
|
2574
2737
|
if (!exists) {
|
|
@@ -2581,7 +2744,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2581
2744
|
throw new T2000Error("WALLET_LOCKED", "PIN required to unlock wallet");
|
|
2582
2745
|
}
|
|
2583
2746
|
const keypair = await loadKey(secret, keyPath);
|
|
2584
|
-
return new _T2000(keypair, client);
|
|
2747
|
+
return new _T2000(keypair, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2585
2748
|
}
|
|
2586
2749
|
static fromPrivateKey(privateKey, options = {}) {
|
|
2587
2750
|
const keypair = keypairFromPrivateKey(privateKey);
|
|
@@ -2593,7 +2756,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2593
2756
|
const keypair = generateKeypair();
|
|
2594
2757
|
await saveKey(keypair, secret, options.keyPath);
|
|
2595
2758
|
const client = getSuiClient();
|
|
2596
|
-
const agent = new _T2000(keypair, client);
|
|
2759
|
+
const agent = new _T2000(keypair, client, void 0, DEFAULT_CONFIG_DIR);
|
|
2597
2760
|
const address = agent.address();
|
|
2598
2761
|
let sponsored = false;
|
|
2599
2762
|
if (options.sponsored !== false) {
|
|
@@ -2619,6 +2782,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2619
2782
|
return this._address;
|
|
2620
2783
|
}
|
|
2621
2784
|
async send(params) {
|
|
2785
|
+
this.enforcer.assertNotLocked();
|
|
2622
2786
|
const asset = params.asset ?? "USDC";
|
|
2623
2787
|
if (!(asset in SUPPORTED_ASSETS)) {
|
|
2624
2788
|
throw new T2000Error("ASSET_NOT_SUPPORTED", `Asset ${asset} is not supported`);
|
|
@@ -2628,8 +2792,10 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2628
2792
|
const gasResult = await executeWithGas(
|
|
2629
2793
|
this.client,
|
|
2630
2794
|
this.keypair,
|
|
2631
|
-
() => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset })
|
|
2795
|
+
() => buildSendTx({ client: this.client, address: this._address, to: sendTo, amount: sendAmount, asset }),
|
|
2796
|
+
{ metadata: { operation: "send", amount: sendAmount }, enforcer: this.enforcer }
|
|
2632
2797
|
);
|
|
2798
|
+
this.enforcer.recordUsage(sendAmount);
|
|
2633
2799
|
const balance = await this.balance();
|
|
2634
2800
|
this.emitBalanceChange(asset, sendAmount, "send", gasResult.digest);
|
|
2635
2801
|
return {
|
|
@@ -2685,6 +2851,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2685
2851
|
}
|
|
2686
2852
|
// -- Savings --
|
|
2687
2853
|
async save(params) {
|
|
2854
|
+
this.enforcer.assertNotLocked();
|
|
2688
2855
|
const asset = "USDC";
|
|
2689
2856
|
const bal = await queryBalance(this.client, this._address);
|
|
2690
2857
|
const usdcBalance = bal.stables.USDC ?? 0;
|
|
@@ -2779,6 +2946,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
2779
2946
|
};
|
|
2780
2947
|
}
|
|
2781
2948
|
async withdraw(params) {
|
|
2949
|
+
this.enforcer.assertNotLocked();
|
|
2782
2950
|
if (params.amount === "all" && !params.protocol) {
|
|
2783
2951
|
return this.withdrawAllProtocols();
|
|
2784
2952
|
}
|
|
@@ -3016,6 +3184,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3016
3184
|
}
|
|
3017
3185
|
// -- Borrowing --
|
|
3018
3186
|
async borrow(params) {
|
|
3187
|
+
this.enforcer.assertNotLocked();
|
|
3019
3188
|
const asset = "USDC";
|
|
3020
3189
|
const adapter = await this.resolveLending(params.protocol, asset, "borrow");
|
|
3021
3190
|
const maxResult = await adapter.maxBorrow(this._address, asset);
|
|
@@ -3048,6 +3217,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3048
3217
|
};
|
|
3049
3218
|
}
|
|
3050
3219
|
async repay(params) {
|
|
3220
|
+
this.enforcer.assertNotLocked();
|
|
3051
3221
|
const allPositions = await this.registry.allPositions(this._address);
|
|
3052
3222
|
const borrows = [];
|
|
3053
3223
|
for (const pos of allPositions) {
|
|
@@ -3201,6 +3371,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3201
3371
|
}
|
|
3202
3372
|
// -- Exchange --
|
|
3203
3373
|
async exchange(params) {
|
|
3374
|
+
this.enforcer.assertNotLocked();
|
|
3204
3375
|
const fromAsset = params.from;
|
|
3205
3376
|
const toAsset = params.to;
|
|
3206
3377
|
if (!(fromAsset in SUPPORTED_ASSETS) || !(toAsset in SUPPORTED_ASSETS)) {
|
|
@@ -3301,6 +3472,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3301
3472
|
return this.registry.allRatesAcrossAssets();
|
|
3302
3473
|
}
|
|
3303
3474
|
async rebalance(opts = {}) {
|
|
3475
|
+
this.enforcer.assertNotLocked();
|
|
3304
3476
|
const dryRun = opts.dryRun ?? false;
|
|
3305
3477
|
const minYieldDiff = opts.minYieldDiff ?? 0.5;
|
|
3306
3478
|
const maxBreakEven = opts.maxBreakEven ?? 30;
|
|
@@ -3582,6 +3754,7 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
3582
3754
|
return getSentinelInfo(this.client, id);
|
|
3583
3755
|
}
|
|
3584
3756
|
async sentinelAttack(id, prompt, fee) {
|
|
3757
|
+
this.enforcer.check({ operation: "sentinel", amount: fee ? Number(fee) / 1e9 : 0.1 });
|
|
3585
3758
|
return attack(this.client, this.keypair, id, prompt, fee);
|
|
3586
3759
|
}
|
|
3587
3760
|
// -- Helpers --
|
|
@@ -3737,12 +3910,16 @@ exports.BPS_DENOMINATOR = BPS_DENOMINATOR;
|
|
|
3737
3910
|
exports.CLOCK_ID = CLOCK_ID;
|
|
3738
3911
|
exports.CetusAdapter = CetusAdapter;
|
|
3739
3912
|
exports.DEFAULT_NETWORK = DEFAULT_NETWORK;
|
|
3913
|
+
exports.DEFAULT_SAFEGUARD_CONFIG = DEFAULT_SAFEGUARD_CONFIG;
|
|
3740
3914
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
3741
3915
|
exports.NaviAdapter = NaviAdapter;
|
|
3916
|
+
exports.OUTBOUND_OPS = OUTBOUND_OPS;
|
|
3742
3917
|
exports.ProtocolRegistry = ProtocolRegistry;
|
|
3743
3918
|
exports.SENTINEL = SENTINEL;
|
|
3744
3919
|
exports.SUI_DECIMALS = SUI_DECIMALS;
|
|
3745
3920
|
exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
3921
|
+
exports.SafeguardEnforcer = SafeguardEnforcer;
|
|
3922
|
+
exports.SafeguardError = SafeguardError;
|
|
3746
3923
|
exports.SuilendAdapter = SuilendAdapter;
|
|
3747
3924
|
exports.T2000 = T2000;
|
|
3748
3925
|
exports.T2000Error = T2000Error;
|