@t2000/sdk 0.2.6 → 0.2.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/README.md +8 -0
- package/dist/index.cjs +214 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -2
- package/dist/index.d.ts +60 -2
- package/dist/index.js +208 -1
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/LICENSE +0 -21
package/README.md
CHANGED
|
@@ -111,6 +111,14 @@ const agent = T2000.fromPrivateKey('suiprivkey1q...');
|
|
|
111
111
|
| `agent.deposit()` | Wallet address + funding instructions | `DepositInfo` |
|
|
112
112
|
| `agent.history({ limit? })` | Transaction history (default: all) | `TransactionRecord[]` |
|
|
113
113
|
|
|
114
|
+
### Sentinel Methods
|
|
115
|
+
|
|
116
|
+
| Method | Description | Returns |
|
|
117
|
+
|--------|-------------|---------|
|
|
118
|
+
| `agent.sentinelList()` | List active sentinels with prize pools | `SentinelAgent[]` |
|
|
119
|
+
| `agent.sentinelInfo(id)` | Get sentinel details (from API or on-chain) | `SentinelAgent` |
|
|
120
|
+
| `agent.sentinelAttack(id, prompt, fee?)` | Full attack flow: request → TEE → settle | `SentinelAttackResult` |
|
|
121
|
+
|
|
114
122
|
### Key Management
|
|
115
123
|
|
|
116
124
|
```typescript
|
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var os = require('os');
|
|
|
12
12
|
var transactions = require('@mysten/sui/transactions');
|
|
13
13
|
var lending = require('@naviprotocol/lending');
|
|
14
14
|
var suiClmmSdk = require('@cetusprotocol/sui-clmm-sdk');
|
|
15
|
+
var bcs = require('@mysten/sui/bcs');
|
|
15
16
|
|
|
16
17
|
// src/t2000.ts
|
|
17
18
|
|
|
@@ -47,6 +48,18 @@ var DEFAULT_RPC_URL = "https://fullnode.mainnet.sui.io:443";
|
|
|
47
48
|
var DEFAULT_KEY_PATH = "~/.t2000/wallet.key";
|
|
48
49
|
var API_BASE_URL = process.env.T2000_API_URL ?? "https://api.t2000.ai";
|
|
49
50
|
var CETUS_USDC_SUI_POOL = "0x51e883ba7c0b566a26cbc8a94cd33eb0abd418a77cc1e60ad22fd9b1f29cd2ab";
|
|
51
|
+
var SENTINEL = {
|
|
52
|
+
PACKAGE: "0x88b83f36dafcd5f6dcdcf1d2cb5889b03f61264ab3cee9cae35db7aa940a21b7",
|
|
53
|
+
AGENT_REGISTRY: "0xc47564f5f14c12b31e0dfa1a3dc99a6380a1edf8929c28cb0eaa3359c8db36ac",
|
|
54
|
+
ENCLAVE: "0xfb1261aeb9583514cb1341a548a5ec12d1231bd96af22215f1792617a93e1213",
|
|
55
|
+
PROTOCOL_CONFIG: "0x2fa4fa4a1dd0498612304635ff9334e1b922e78af325000e9d9c0e88adea459f",
|
|
56
|
+
TEE_API: "https://app.suisentinel.xyz/api/consume-prompt",
|
|
57
|
+
SENTINELS_API: "https://api.suisentinel.xyz/agents/mainnet",
|
|
58
|
+
RANDOM: "0x8",
|
|
59
|
+
MIN_FEE_MIST: 100000000n,
|
|
60
|
+
// 0.1 SUI
|
|
61
|
+
MAX_PROMPT_TOKENS: 600
|
|
62
|
+
};
|
|
50
63
|
|
|
51
64
|
// src/errors.ts
|
|
52
65
|
var T2000Error = class extends Error {
|
|
@@ -701,6 +714,190 @@ async function getFundStatus(client, keypair) {
|
|
|
701
714
|
projectedMonthly: earnings.dailyEarning * 30
|
|
702
715
|
};
|
|
703
716
|
}
|
|
717
|
+
function mapAgent(raw) {
|
|
718
|
+
return {
|
|
719
|
+
id: raw.agent_id,
|
|
720
|
+
objectId: raw.agent_object_id,
|
|
721
|
+
name: raw.agent_name,
|
|
722
|
+
model: raw.model ?? "unknown",
|
|
723
|
+
systemPrompt: raw.prompt,
|
|
724
|
+
attackFee: BigInt(raw.cost_per_message),
|
|
725
|
+
prizePool: BigInt(raw.total_balance),
|
|
726
|
+
totalAttacks: raw.total_attacks,
|
|
727
|
+
successfulBreaches: raw.successful_breaches ?? 0,
|
|
728
|
+
state: raw.state
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
async function listSentinels() {
|
|
732
|
+
const res = await fetch(SENTINEL.SENTINELS_API);
|
|
733
|
+
if (!res.ok) {
|
|
734
|
+
throw new T2000Error("SENTINEL_API_ERROR", `Sentinel API returned ${res.status}`);
|
|
735
|
+
}
|
|
736
|
+
const data = await res.json();
|
|
737
|
+
if (!Array.isArray(data.agents)) {
|
|
738
|
+
throw new T2000Error("SENTINEL_API_ERROR", "Unexpected API response shape");
|
|
739
|
+
}
|
|
740
|
+
return data.agents.filter((a) => a.state === "active").map(mapAgent);
|
|
741
|
+
}
|
|
742
|
+
async function getSentinelInfo(client, sentinelObjectId) {
|
|
743
|
+
const agents = await listSentinels();
|
|
744
|
+
const match = agents.find((a) => a.objectId === sentinelObjectId || a.id === sentinelObjectId);
|
|
745
|
+
if (match) return match;
|
|
746
|
+
const obj = await client.getObject({
|
|
747
|
+
id: sentinelObjectId,
|
|
748
|
+
options: { showContent: true, showType: true }
|
|
749
|
+
});
|
|
750
|
+
if (!obj.data) {
|
|
751
|
+
throw new T2000Error("SENTINEL_NOT_FOUND", `Sentinel ${sentinelObjectId} not found on-chain`);
|
|
752
|
+
}
|
|
753
|
+
const content = obj.data.content;
|
|
754
|
+
if (!content || content.dataType !== "moveObject") {
|
|
755
|
+
throw new T2000Error("SENTINEL_NOT_FOUND", `Object ${sentinelObjectId} is not a Move object`);
|
|
756
|
+
}
|
|
757
|
+
const fields = content.fields;
|
|
758
|
+
return {
|
|
759
|
+
id: fields.id?.id ?? sentinelObjectId,
|
|
760
|
+
objectId: sentinelObjectId,
|
|
761
|
+
name: fields.name ?? "Unknown",
|
|
762
|
+
model: fields.model ?? "unknown",
|
|
763
|
+
systemPrompt: fields.system_prompt ?? "",
|
|
764
|
+
attackFee: BigInt(fields.cost_per_message ?? "0"),
|
|
765
|
+
prizePool: BigInt(fields.balance ?? "0"),
|
|
766
|
+
totalAttacks: Number(fields.total_attacks ?? "0"),
|
|
767
|
+
successfulBreaches: Number(fields.successful_breaches ?? "0"),
|
|
768
|
+
state: fields.state ?? "unknown"
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
async function requestAttack(client, signer, sentinelObjectId, feeMist) {
|
|
772
|
+
if (feeMist < SENTINEL.MIN_FEE_MIST) {
|
|
773
|
+
throw new T2000Error("INVALID_AMOUNT", `Attack fee must be at least 0.1 SUI (${SENTINEL.MIN_FEE_MIST} MIST)`);
|
|
774
|
+
}
|
|
775
|
+
const tx = new transactions.Transaction();
|
|
776
|
+
const [coin] = tx.splitCoins(tx.gas, [Number(feeMist)]);
|
|
777
|
+
const [attack2] = tx.moveCall({
|
|
778
|
+
target: `${SENTINEL.PACKAGE}::sentinel::request_attack`,
|
|
779
|
+
arguments: [
|
|
780
|
+
tx.object(SENTINEL.AGENT_REGISTRY),
|
|
781
|
+
tx.object(sentinelObjectId),
|
|
782
|
+
tx.object(SENTINEL.PROTOCOL_CONFIG),
|
|
783
|
+
coin,
|
|
784
|
+
tx.object(SENTINEL.RANDOM),
|
|
785
|
+
tx.object(CLOCK_ID)
|
|
786
|
+
]
|
|
787
|
+
});
|
|
788
|
+
const address = signer.toSuiAddress();
|
|
789
|
+
tx.transferObjects([attack2], address);
|
|
790
|
+
const result = await client.signAndExecuteTransaction({
|
|
791
|
+
signer,
|
|
792
|
+
transaction: tx,
|
|
793
|
+
options: { showObjectChanges: true, showEffects: true }
|
|
794
|
+
});
|
|
795
|
+
await client.waitForTransaction({ digest: result.digest });
|
|
796
|
+
const attackObj = result.objectChanges?.find(
|
|
797
|
+
(c) => c.type === "created" && c.objectType?.includes("::sentinel::Attack")
|
|
798
|
+
);
|
|
799
|
+
const attackObjectId = attackObj && "objectId" in attackObj ? attackObj.objectId : void 0;
|
|
800
|
+
if (!attackObjectId) {
|
|
801
|
+
throw new T2000Error("SENTINEL_TX_FAILED", "Attack object was not created \u2014 transaction may have failed");
|
|
802
|
+
}
|
|
803
|
+
return { attackObjectId, digest: result.digest };
|
|
804
|
+
}
|
|
805
|
+
async function submitPrompt(agentId, attackObjectId, prompt) {
|
|
806
|
+
const res = await fetch(SENTINEL.TEE_API, {
|
|
807
|
+
method: "POST",
|
|
808
|
+
headers: { "Content-Type": "application/json" },
|
|
809
|
+
body: JSON.stringify({
|
|
810
|
+
agent_id: agentId,
|
|
811
|
+
attack_object_id: attackObjectId,
|
|
812
|
+
message: prompt
|
|
813
|
+
})
|
|
814
|
+
});
|
|
815
|
+
if (!res.ok) {
|
|
816
|
+
const body = await res.text().catch(() => "");
|
|
817
|
+
throw new T2000Error("SENTINEL_TEE_ERROR", `TEE returned ${res.status}: ${body.slice(0, 200)}`);
|
|
818
|
+
}
|
|
819
|
+
const raw = await res.json();
|
|
820
|
+
const envelope = raw.response ?? raw;
|
|
821
|
+
const data = envelope.data ?? envelope;
|
|
822
|
+
const signature = raw.signature ?? data.signature;
|
|
823
|
+
const timestampMs = envelope.timestamp_ms ?? data.timestamp_ms;
|
|
824
|
+
if (typeof signature !== "string") {
|
|
825
|
+
throw new T2000Error("SENTINEL_TEE_ERROR", "TEE response missing signature");
|
|
826
|
+
}
|
|
827
|
+
return {
|
|
828
|
+
success: data.success ?? data.is_success,
|
|
829
|
+
score: data.score,
|
|
830
|
+
agentResponse: data.agent_response,
|
|
831
|
+
juryResponse: data.jury_response,
|
|
832
|
+
funResponse: data.fun_response ?? "",
|
|
833
|
+
signature,
|
|
834
|
+
timestampMs
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
async function settleAttack(client, signer, sentinelObjectId, attackObjectId, prompt, verdict) {
|
|
838
|
+
const sigBytes = Array.from(Buffer.from(verdict.signature.replace(/^0x/, ""), "hex"));
|
|
839
|
+
const tx = new transactions.Transaction();
|
|
840
|
+
tx.moveCall({
|
|
841
|
+
target: `${SENTINEL.PACKAGE}::sentinel::consume_prompt`,
|
|
842
|
+
arguments: [
|
|
843
|
+
tx.object(SENTINEL.AGENT_REGISTRY),
|
|
844
|
+
tx.object(SENTINEL.PROTOCOL_CONFIG),
|
|
845
|
+
tx.object(sentinelObjectId),
|
|
846
|
+
tx.pure.bool(verdict.success),
|
|
847
|
+
tx.pure.string(verdict.agentResponse),
|
|
848
|
+
tx.pure.string(verdict.juryResponse),
|
|
849
|
+
tx.pure.string(verdict.funResponse),
|
|
850
|
+
tx.pure.string(prompt),
|
|
851
|
+
tx.pure.u8(verdict.score),
|
|
852
|
+
tx.pure.u64(verdict.timestampMs),
|
|
853
|
+
tx.pure(bcs.bcs.vector(bcs.bcs.u8()).serialize(sigBytes)),
|
|
854
|
+
tx.object(SENTINEL.ENCLAVE),
|
|
855
|
+
tx.object(attackObjectId),
|
|
856
|
+
tx.object(CLOCK_ID)
|
|
857
|
+
]
|
|
858
|
+
});
|
|
859
|
+
const result = await client.signAndExecuteTransaction({
|
|
860
|
+
signer,
|
|
861
|
+
transaction: tx,
|
|
862
|
+
options: { showEffects: true }
|
|
863
|
+
});
|
|
864
|
+
await client.waitForTransaction({ digest: result.digest });
|
|
865
|
+
const txSuccess = result.effects?.status?.status === "success";
|
|
866
|
+
return { digest: result.digest, success: txSuccess };
|
|
867
|
+
}
|
|
868
|
+
async function attack(client, signer, sentinelId, prompt, feeMist) {
|
|
869
|
+
const sentinel = await getSentinelInfo(client, sentinelId);
|
|
870
|
+
const fee = feeMist ?? sentinel.attackFee;
|
|
871
|
+
if (fee < SENTINEL.MIN_FEE_MIST) {
|
|
872
|
+
throw new T2000Error("INVALID_AMOUNT", `Attack fee must be at least 0.1 SUI`);
|
|
873
|
+
}
|
|
874
|
+
const { attackObjectId, digest: requestTx } = await requestAttack(
|
|
875
|
+
client,
|
|
876
|
+
signer,
|
|
877
|
+
sentinel.objectId,
|
|
878
|
+
fee
|
|
879
|
+
);
|
|
880
|
+
const verdict = await submitPrompt(sentinel.id, attackObjectId, prompt);
|
|
881
|
+
const { digest: settleTx } = await settleAttack(
|
|
882
|
+
client,
|
|
883
|
+
signer,
|
|
884
|
+
sentinel.objectId,
|
|
885
|
+
attackObjectId,
|
|
886
|
+
prompt,
|
|
887
|
+
verdict
|
|
888
|
+
);
|
|
889
|
+
const won = verdict.success && verdict.score >= 70;
|
|
890
|
+
return {
|
|
891
|
+
attackObjectId,
|
|
892
|
+
sentinelId: sentinel.id,
|
|
893
|
+
prompt,
|
|
894
|
+
verdict,
|
|
895
|
+
requestTx,
|
|
896
|
+
settleTx,
|
|
897
|
+
won,
|
|
898
|
+
feePaid: Number(fee) / Number(MIST_PER_SUI)
|
|
899
|
+
};
|
|
900
|
+
}
|
|
704
901
|
function hasLeadingZeroBits(hash, bits) {
|
|
705
902
|
const fullBytes = Math.floor(bits / 8);
|
|
706
903
|
const remainingBits = bits % 8;
|
|
@@ -1318,6 +1515,16 @@ var T2000 = class _T2000 extends eventemitter3.EventEmitter {
|
|
|
1318
1515
|
async fundStatus() {
|
|
1319
1516
|
return getFundStatus(this.client, this.keypair);
|
|
1320
1517
|
}
|
|
1518
|
+
// -- Sentinel --
|
|
1519
|
+
async sentinelList() {
|
|
1520
|
+
return listSentinels();
|
|
1521
|
+
}
|
|
1522
|
+
async sentinelInfo(id) {
|
|
1523
|
+
return getSentinelInfo(this.client, id);
|
|
1524
|
+
}
|
|
1525
|
+
async sentinelAttack(id, prompt, fee) {
|
|
1526
|
+
return attack(this.client, this.keypair, id, prompt, fee);
|
|
1527
|
+
}
|
|
1321
1528
|
// -- Helpers --
|
|
1322
1529
|
emitBalanceChange(asset, amount, cause, tx) {
|
|
1323
1530
|
this.emit("balanceChange", { asset, previous: 0, current: 0, cause, tx });
|
|
@@ -1421,6 +1628,7 @@ exports.BPS_DENOMINATOR = BPS_DENOMINATOR;
|
|
|
1421
1628
|
exports.CLOCK_ID = CLOCK_ID;
|
|
1422
1629
|
exports.DEFAULT_NETWORK = DEFAULT_NETWORK;
|
|
1423
1630
|
exports.MIST_PER_SUI = MIST_PER_SUI;
|
|
1631
|
+
exports.SENTINEL = SENTINEL;
|
|
1424
1632
|
exports.SUI_DECIMALS = SUI_DECIMALS;
|
|
1425
1633
|
exports.SUPPORTED_ASSETS = SUPPORTED_ASSETS;
|
|
1426
1634
|
exports.T2000 = T2000;
|
|
@@ -1437,17 +1645,23 @@ exports.getAddress = getAddress;
|
|
|
1437
1645
|
exports.getGasStatus = getGasStatus;
|
|
1438
1646
|
exports.getPoolPrice = getPoolPrice;
|
|
1439
1647
|
exports.getRates = getRates;
|
|
1648
|
+
exports.getSentinelInfo = getSentinelInfo;
|
|
1440
1649
|
exports.getSwapQuote = getSwapQuote;
|
|
1441
1650
|
exports.keypairFromPrivateKey = keypairFromPrivateKey;
|
|
1651
|
+
exports.listSentinels = listSentinels;
|
|
1442
1652
|
exports.loadKey = loadKey;
|
|
1443
1653
|
exports.mapMoveAbortCode = mapMoveAbortCode;
|
|
1444
1654
|
exports.mapWalletError = mapWalletError;
|
|
1445
1655
|
exports.mistToSui = mistToSui;
|
|
1446
1656
|
exports.rawToUsdc = rawToUsdc;
|
|
1657
|
+
exports.requestAttack = requestAttack;
|
|
1447
1658
|
exports.saveKey = saveKey;
|
|
1659
|
+
exports.sentinelAttack = attack;
|
|
1660
|
+
exports.settleAttack = settleAttack;
|
|
1448
1661
|
exports.shouldAutoTopUp = shouldAutoTopUp;
|
|
1449
1662
|
exports.simulateTransaction = simulateTransaction;
|
|
1450
1663
|
exports.solveHashcash = solveHashcash;
|
|
1664
|
+
exports.submitPrompt = submitPrompt;
|
|
1451
1665
|
exports.suiToMist = suiToMist;
|
|
1452
1666
|
exports.throwIfSimulationFailed = throwIfSimulationFailed;
|
|
1453
1667
|
exports.truncateAddress = truncateAddress;
|