shll-skills 6.0.3 → 6.0.5
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 +4 -4
- package/SKILL.md +90 -6
- package/dist/{chunk-TH3ENDDM.mjs → chunk-RUCWJDVB.mjs} +25 -22
- package/dist/index.js +28 -25
- package/dist/index.mjs +4 -4
- package/dist/mcp.js +28 -25
- package/dist/mcp.mjs +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# SHLL Skills — AI Agent DeFi Toolkit on BSC
|
|
2
2
|
|
|
3
3
|
[](https://shll.run) [](https://twitter.com/shllrun) [](https://www.npmjs.com/package/shll-skills) [](https://clawhub.ai/kledx/shll-skills)
|
|
4
4
|
|
|
@@ -85,7 +85,7 @@ The server communicates via **stdio** using JSON-RPC 2.0. Send `tools/list` to d
|
|
|
85
85
|
| `status` | Read | One-shot readiness overview with blockers, warnings, and next actions |
|
|
86
86
|
| `history` | Read | Recent transactions + policy rejections |
|
|
87
87
|
| `token_restriction` | Read | View token whitelist restriction status + whitelisted tokens |
|
|
88
|
-
| `listings` | Read | Available agent templates for
|
|
88
|
+
| `listings` | Read | Available agent templates for subscription |
|
|
89
89
|
| `four_info` | Read | Query Four.meme bonding curve token info |
|
|
90
90
|
| `swap` | Write | PancakeSwap V2/V3 auto-routing swap |
|
|
91
91
|
| `wrap` | Write | BNB → WBNB in vault |
|
|
@@ -180,13 +180,13 @@ AI Agent -> CLI/MCP -> PolicyClient.validate() -> PolicyGuard (on-chain) -> vaul
|
|
|
180
180
|
| | Owner Wallet | Operator Wallet (RUNNER_PRIVATE_KEY) |
|
|
181
181
|
|---|---|---|
|
|
182
182
|
| **Who holds it** | User (MetaMask/hardware) | AI agent |
|
|
183
|
-
| **Use it for** |
|
|
183
|
+
| **Use it for** | Subscribe or mint the agent, hold the Agent NFT, authorize operator | Pay gas and execute policy-limited actions |
|
|
184
184
|
| **Can trade** | — | ✅ Within PolicyGuard limits |
|
|
185
185
|
| **Can withdraw vault** | ✅ | ❌ |
|
|
186
186
|
| **Can transfer NFT** | ✅ | ❌ |
|
|
187
187
|
| **Risk if leaked** | 🚨 Full vault access | ⚠️ Limited to policy-allowed trades |
|
|
188
188
|
|
|
189
|
-
Do not use the operator wallet to mint or
|
|
189
|
+
Do not use the operator wallet to mint or subscribe to the agent. Do not hold the Agent NFT in the operator wallet. Keep only a small BNB balance there for gas.
|
|
190
190
|
|
|
191
191
|
After setup, run `status` first. It returns a machine-friendly readiness object with:
|
|
192
192
|
- `readiness.ready`
|
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: shll-run
|
|
3
3
|
description: Execute DeFi transactions on BSC via SHLL AgentNFA. The AI handles all commands and users only need to chat.
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.4
|
|
5
5
|
author: SHLL Team
|
|
6
6
|
website: https://shll.run
|
|
7
7
|
twitter: https://twitter.com/shllrun
|
|
@@ -31,6 +31,90 @@ credentials:
|
|
|
31
31
|
The operator wallet is NOT the owner wallet, NOT the vault, NOT the Agent NFT holder.
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
+
# SHLL — Contract-Enforced Safe Execution for AI Agents on BNB Chain
|
|
35
|
+
|
|
36
|
+
## What is SHLL?
|
|
37
|
+
|
|
38
|
+
SHLL is a DeFi execution layer for AI agents on BNB Chain with **on-chain safety enforcement**.
|
|
39
|
+
Unlike off-chain filters that can be bypassed, SHLL uses smart contracts to enforce
|
|
40
|
+
spending limits, trade intervals, protocol whitelists, and receiver restrictions.
|
|
41
|
+
Every AI agent action is validated by an immutable PolicyGuard contract before execution.
|
|
42
|
+
|
|
43
|
+
Key facts:
|
|
44
|
+
- Network: BSC mainnet
|
|
45
|
+
- 27 CLI + MCP tools for DeFi operations (swap, lend, meme trading, portfolio)
|
|
46
|
+
- Supports PancakeSwap V2/V3, Venus Protocol, Four.meme
|
|
47
|
+
- MCP Server compatible with Claude, Cursor, OpenClaw, and any MCP-compatible agent
|
|
48
|
+
- npm package: `shll-skills` | Website: https://shll.run
|
|
49
|
+
|
|
50
|
+
## Security Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
54
|
+
│ SHLL Architecture │
|
|
55
|
+
│ │
|
|
56
|
+
│ ┌──────────┐ ┌───────────────┐ ┌──────────────────────┐ │
|
|
57
|
+
│ │ User │ │ AI Agent │ │ On-Chain Contracts │ │
|
|
58
|
+
│ │ (Owner) │ │ (Operator) │ │ │ │
|
|
59
|
+
│ │ │ │ │ │ ┌────────────────┐ │ │
|
|
60
|
+
│ │ • Holds │ │ • Executes │ │ │ PolicyGuard │ │ │
|
|
61
|
+
│ │ Agent │ │ trades via │ │ │ (Validator) │ │ │
|
|
62
|
+
│ │ NFT │ │ restricted │ │ │ │ │ │
|
|
63
|
+
│ │ • Sets │ │ permissions │ │ │ 4 Policy │ │ │
|
|
64
|
+
│ │ policy │ │ │ │ │ Checks: │ │ │
|
|
65
|
+
│ │ rules │───▶│ SHLL Skills │───▶│ │ │ │ │
|
|
66
|
+
│ │ • Full │ │ (CLI / MCP) │ │ │ 1.Spending │ │ │
|
|
67
|
+
│ │ asset │ │ │ │ │ Limit │ │ │
|
|
68
|
+
│ │ control │ │ Cannot: │ │ │ 2.Cooldown │ │ │
|
|
69
|
+
│ │ │ │ • Withdraw │ │ │ 3.DeFi Guard │ │ │
|
|
70
|
+
│ │ │ │ vault funds │ │ │ 4.Receiver │ │ │
|
|
71
|
+
│ │ │ │ • Change │ │ │ Guard │ │ │
|
|
72
|
+
│ │ │ │ policies │ │ └───────┬────────┘ │ │
|
|
73
|
+
│ │ │ │ • Transfer │ │ │ │ │
|
|
74
|
+
│ │ │ │ NFT │ │ ┌─────▼──────┐ │ │
|
|
75
|
+
│ │ │ │ │ │ │ Vault │ │ │
|
|
76
|
+
│ │ │ │ │ │ │ (Agent │ │ │
|
|
77
|
+
│ │ │ │ │ │ │ Account) │ │ │
|
|
78
|
+
│ │ │ │ │ │ │ │ │ │
|
|
79
|
+
│ │ │ │ │ │ │ Holds funds │ │ │
|
|
80
|
+
│ └──────────┘ └───────────────┘ │ └─────────────┘ │ │
|
|
81
|
+
│ └──────────────────────┘ │
|
|
82
|
+
│ Dual-Wallet Isolation: │
|
|
83
|
+
│ • Owner wallet = asset control (human) │
|
|
84
|
+
│ • Operator wallet = restricted execution (AI) │
|
|
85
|
+
│ • Even if operator key leaks, PolicyGuard still limits actions │
|
|
86
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 4-Policy PolicyGuard Stack
|
|
90
|
+
|
|
91
|
+
All policies are enforced ON-CHAIN by smart contract. They cannot be bypassed by the AI.
|
|
92
|
+
|
|
93
|
+
| Policy | Contract | What It Does |
|
|
94
|
+
|--------|----------|-------------|
|
|
95
|
+
| SpendingLimitV2 | On-chain | Per-transaction and daily spending caps in BNB |
|
|
96
|
+
| CooldownPolicy | On-chain | Minimum time gap between consecutive trades |
|
|
97
|
+
| DeFiGuardV2 | On-chain | Whitelist of approved DeFi protocols and functions |
|
|
98
|
+
| ReceiverGuardV2 | On-chain | Only approved receiver addresses can receive funds |
|
|
99
|
+
|
|
100
|
+
When a policy rejects an action:
|
|
101
|
+
- The transaction is NOT executed
|
|
102
|
+
- The vault funds remain SAFE
|
|
103
|
+
- The rejection reason is returned from the smart contract
|
|
104
|
+
- The rejection is logged and auditable
|
|
105
|
+
- The `enforcement` field in the response is always `on-chain`
|
|
106
|
+
|
|
107
|
+
## Why On-Chain Enforcement Matters
|
|
108
|
+
|
|
109
|
+
Most AI agent platforms use off-chain safety filters:
|
|
110
|
+
- Off-chain: AI or backend decides → **can be bypassed** by prompt injection, API manipulation, or code bugs
|
|
111
|
+
- On-chain (SHLL): Smart contract decides → **cannot be bypassed** — the blockchain enforces the rules
|
|
112
|
+
|
|
113
|
+
PolicyGuard contract: `0x25d17eA0e3Bcb8CA08a2BFE917E817AFc05dbBB3`
|
|
114
|
+
Verify on BscScan: https://bscscan.com/address/0x25d17eA0e3Bcb8CA08a2BFE917E817AFc05dbBB3
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
34
118
|
# SHLL Skill Usage Guide
|
|
35
119
|
|
|
36
120
|
This file defines how an AI agent should use `shll-run` and `shll-mcp` safely.
|
|
@@ -68,7 +152,7 @@ On-chain guardrails:
|
|
|
68
152
|
- Spending limits, cooldowns, whitelist rules, and protocol rules are enforced on-chain.
|
|
69
153
|
- Raw calldata is blocked if the recipient cannot be decoded safely.
|
|
70
154
|
|
|
71
|
-
## Current Critical Constraints (v6.0.
|
|
155
|
+
## Current Critical Constraints (v6.0.4)
|
|
72
156
|
|
|
73
157
|
1. `init` command is disabled. Do not use it.
|
|
74
158
|
2. Raw calldata remains high risk; rely on strict recipient safety checks.
|
|
@@ -112,8 +196,8 @@ export SHLL_RPC="https://your-private-bsc-rpc.example.com"
|
|
|
112
196
|
- Recommend the listing with `recommended=true` by default unless the user explicitly wants a specialized template.
|
|
113
197
|
- Run `shll-run setup-guide -l <listingId> -d <days>`.
|
|
114
198
|
- Send `setupUrl` plus the wallet-role explanation.
|
|
115
|
-
- Explicitly warn: do not use the operator wallet to mint,
|
|
116
|
-
- Explicitly warn: use the owner wallet in the browser for
|
|
199
|
+
- Explicitly warn: do not use the operator wallet to mint, subscribe to, or hold the Agent NFT.
|
|
200
|
+
- Explicitly warn: use the owner wallet in the browser for subscription or mint and for operator authorization.
|
|
117
201
|
|
|
118
202
|
4. User returns with token ID:
|
|
119
203
|
- Run `shll-run status -k <tokenId>`.
|
|
@@ -230,7 +314,7 @@ When the user provides a token address:
|
|
|
230
314
|
2. `NOT authorized for token-id`
|
|
231
315
|
- Operator wallet is not authorized; use setup guide or set operator in console.
|
|
232
316
|
|
|
233
|
-
3. `
|
|
317
|
+
3. `subscription has EXPIRED` or `operator authorization has EXPIRED`
|
|
234
318
|
- Renew subscription or authorization first.
|
|
235
319
|
|
|
236
320
|
4. `status: error` with `errorCode: POLICY_REJECTED`
|
|
@@ -253,7 +337,7 @@ When the user provides a token address:
|
|
|
253
337
|
1. Never describe `generate-wallet` as if it were the user's main wallet.
|
|
254
338
|
2. Always call it the operator wallet or AI hot wallet.
|
|
255
339
|
3. Always explain the dual-wallet model the first time setup is discussed.
|
|
256
|
-
4. Always warn that the operator wallet must not be used to mint,
|
|
340
|
+
4. Always warn that the operator wallet must not be used to mint, subscribe to, or hold the Agent NFT.
|
|
257
341
|
5. Do not ask the user to manually set `RUNNER_PRIVATE_KEY` in OpenClaw; AI should do it.
|
|
258
342
|
6. After setup is complete and the user provides a token-id, run readiness checks automatically before asking the user what to do next.
|
|
259
343
|
7. When multiple listings are available, recommend one by default and explain why.
|
|
@@ -6,8 +6,8 @@ var MEV_PROTECTED_RPC = "https://bscrpc.pancakeswap.finance";
|
|
|
6
6
|
var DEFAULT_LISTING_MANAGER = "0x1f9CE85bD0FF75acc3D92eB79f1Eb472f0865071";
|
|
7
7
|
var DEFAULT_LISTING_ID = "0x64083b44e38db02749e6e16bf84ce6c19146cc42a108e53324e11f250b15a0b7";
|
|
8
8
|
var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
|
|
9
|
-
var SKILL_VERSION = "6.0.
|
|
10
|
-
var BINDINGS_UPDATED_AT = "2026-03-
|
|
9
|
+
var SKILL_VERSION = "6.0.4";
|
|
10
|
+
var BINDINGS_UPDATED_AT = "2026-03-07";
|
|
11
11
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
12
12
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
13
13
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -855,8 +855,8 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
855
855
|
if (now > userExpires) {
|
|
856
856
|
return {
|
|
857
857
|
blocked: true,
|
|
858
|
-
errorType: "
|
|
859
|
-
message: `Agent token-id ${tokenId}
|
|
858
|
+
errorType: "subscription_expired",
|
|
859
|
+
message: `Agent token-id ${tokenId} subscription has EXPIRED (expired at ${new Date(Number(userExpires) * 1e3).toISOString()}).`,
|
|
860
860
|
details: { expiredAt: new Date(Number(userExpires) * 1e3).toISOString(), action: "renew" }
|
|
861
861
|
};
|
|
862
862
|
}
|
|
@@ -885,7 +885,7 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
885
885
|
consoleUrl: agentConsoleUrl(tokenId),
|
|
886
886
|
howToFix: [
|
|
887
887
|
`1. Use 'setup_guide' command to generate an OperatorPermit for this wallet`,
|
|
888
|
-
`2.
|
|
888
|
+
`2. Subscriber (${renter}) can call setOperator(${tokenId}, ${account.address}, <expiry>) on AgentNFA`,
|
|
889
889
|
`3. Go to ${agentConsoleUrl(tokenId)} to set operator`,
|
|
890
890
|
`4. Use the correct RUNNER_PRIVATE_KEY for operator ${operator}`
|
|
891
891
|
]
|
|
@@ -1217,7 +1217,7 @@ async function ensureAccess(tokenId, rpcUrl, publicClient) {
|
|
|
1217
1217
|
"ACCESS_DENIED",
|
|
1218
1218
|
access.message || `Access denied for token_id ${tokenId.toString()}`,
|
|
1219
1219
|
access.details,
|
|
1220
|
-
"Check operator permissions and
|
|
1220
|
+
"Check operator permissions and subscription status"
|
|
1221
1221
|
);
|
|
1222
1222
|
}
|
|
1223
1223
|
}
|
|
@@ -1239,6 +1239,9 @@ async function validateActionsOrThrow(policyClient, tokenId, actions) {
|
|
|
1239
1239
|
"POLICY_REJECTED",
|
|
1240
1240
|
"Policy rejected transaction",
|
|
1241
1241
|
{
|
|
1242
|
+
enforcement: "on-chain",
|
|
1243
|
+
policyGuardContract: DEFAULT_GUARD,
|
|
1244
|
+
verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
|
|
1242
1245
|
failedActionIndex: index,
|
|
1243
1246
|
failedActionTarget: action.target,
|
|
1244
1247
|
failedActionSelector: getActionSelector(action),
|
|
@@ -1327,7 +1330,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1327
1330
|
]);
|
|
1328
1331
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1329
1332
|
let accessStatus = "Active";
|
|
1330
|
-
if (now > userExpires) accessStatus = "
|
|
1333
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1331
1334
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1332
1335
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1333
1336
|
return {
|
|
@@ -2099,14 +2102,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2099
2102
|
walletModel: {
|
|
2100
2103
|
type: "dual_wallet",
|
|
2101
2104
|
ownerWallet: {
|
|
2102
|
-
purpose: "
|
|
2103
|
-
useFor: ["
|
|
2105
|
+
purpose: "Subscribe or mint the agent, own the Agent NFT, authorize the operator, and hold primary assets.",
|
|
2106
|
+
useFor: ["subscribing to or minting the agent", "holding ownership", "authorizing the operator"]
|
|
2104
2107
|
},
|
|
2105
2108
|
operatorWallet: {
|
|
2106
2109
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2107
2110
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2108
2111
|
doNotUseFor: [
|
|
2109
|
-
"minting or
|
|
2112
|
+
"minting or subscribing to the agent",
|
|
2110
2113
|
"holding the Agent NFT",
|
|
2111
2114
|
"using as your main asset wallet"
|
|
2112
2115
|
],
|
|
@@ -2114,8 +2117,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2114
2117
|
}
|
|
2115
2118
|
},
|
|
2116
2119
|
criticalWarnings: [
|
|
2117
|
-
"Do not use the operator wallet to mint,
|
|
2118
|
-
"Use your owner wallet in the browser to complete
|
|
2120
|
+
"Do not use the operator wallet to mint, subscribe to, or hold the Agent NFT.",
|
|
2121
|
+
"Use your owner wallet in the browser to complete subscription and operator authorization.",
|
|
2119
2122
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2120
2123
|
],
|
|
2121
2124
|
listingSelection: {
|
|
@@ -2150,7 +2153,7 @@ function generateOperatorWallet() {
|
|
|
2150
2153
|
securityModel: "dual_wallet",
|
|
2151
2154
|
safeIfLeaked: "This is not the owner wallet. A leak does not grant unrestricted vault withdrawal because owner permissions stay on the owner wallet and PolicyGuard still limits operator actions.",
|
|
2152
2155
|
doNotUseFor: [
|
|
2153
|
-
"minting or
|
|
2156
|
+
"minting or subscribing to the agent",
|
|
2154
2157
|
"holding the Agent NFT",
|
|
2155
2158
|
"holding your main assets"
|
|
2156
2159
|
],
|
|
@@ -2296,7 +2299,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2296
2299
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2297
2300
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2298
2301
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2299
|
-
const
|
|
2302
|
+
const subscriptionActive = now <= userExpires;
|
|
2300
2303
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2301
2304
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2302
2305
|
const blockers = [];
|
|
@@ -2306,9 +2309,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2306
2309
|
blockers.push("Operator session key is not loaded.");
|
|
2307
2310
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2308
2311
|
}
|
|
2309
|
-
if (!
|
|
2310
|
-
blockers.push(`
|
|
2311
|
-
nextActions.push("Use the owner wallet on shll.run to renew the
|
|
2312
|
+
if (!subscriptionActive) {
|
|
2313
|
+
blockers.push(`Subscription expired at ${new Date(Number(userExpires) * 1e3).toISOString()}.`);
|
|
2314
|
+
nextActions.push("Use the owner wallet on shll.run to renew the subscription before trading.");
|
|
2312
2315
|
}
|
|
2313
2316
|
if (!operatorAuthorizationActive) {
|
|
2314
2317
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2332,7 +2335,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2332
2335
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2333
2336
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2334
2337
|
}
|
|
2335
|
-
const readinessStage = !runnerAccount ? "needs_session_key" : !
|
|
2338
|
+
const readinessStage = !runnerAccount ? "needs_session_key" : !subscriptionActive ? "needs_subscription" : !operatorAuthorizationActive || !runnerMatchesOperator ? "needs_operator_authorization" : opBalance !== null && opBalance < MIN_OPERATOR_GAS_WEI ? "needs_operator_gas" : bnbBalance === 0n ? "ready_but_unfunded" : "ready";
|
|
2336
2339
|
let activityStats = { available: false };
|
|
2337
2340
|
try {
|
|
2338
2341
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2359,10 +2362,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2359
2362
|
nextActions: dedupeStrings(nextActions)
|
|
2360
2363
|
},
|
|
2361
2364
|
walletModelReminder: {
|
|
2362
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2365
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2363
2366
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2364
2367
|
doNotUseOperatorWalletFor: [
|
|
2365
|
-
"minting or
|
|
2368
|
+
"minting or subscribing to the agent",
|
|
2366
2369
|
"holding the Agent NFT",
|
|
2367
2370
|
"storing primary funds"
|
|
2368
2371
|
]
|
|
@@ -2381,8 +2384,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2381
2384
|
recommendedMinGasBnb: "0.001"
|
|
2382
2385
|
},
|
|
2383
2386
|
access: {
|
|
2384
|
-
|
|
2385
|
-
|
|
2387
|
+
subscriptionActive,
|
|
2388
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2386
2389
|
operatorAuthorizationActive,
|
|
2387
2390
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2388
2391
|
runnerMatchesOperator,
|
package/dist/index.js
CHANGED
|
@@ -12,8 +12,8 @@ var MEV_PROTECTED_RPC = "https://bscrpc.pancakeswap.finance";
|
|
|
12
12
|
var DEFAULT_LISTING_MANAGER = "0x1f9CE85bD0FF75acc3D92eB79f1Eb472f0865071";
|
|
13
13
|
var DEFAULT_LISTING_ID = "0x64083b44e38db02749e6e16bf84ce6c19146cc42a108e53324e11f250b15a0b7";
|
|
14
14
|
var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
|
|
15
|
-
var SKILL_VERSION = "6.0.
|
|
16
|
-
var BINDINGS_UPDATED_AT = "2026-03-
|
|
15
|
+
var SKILL_VERSION = "6.0.4";
|
|
16
|
+
var BINDINGS_UPDATED_AT = "2026-03-07";
|
|
17
17
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
18
18
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
19
19
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -857,8 +857,8 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
857
857
|
if (now > userExpires) {
|
|
858
858
|
return {
|
|
859
859
|
blocked: true,
|
|
860
|
-
errorType: "
|
|
861
|
-
message: `Agent token-id ${tokenId}
|
|
860
|
+
errorType: "subscription_expired",
|
|
861
|
+
message: `Agent token-id ${tokenId} subscription has EXPIRED (expired at ${new Date(Number(userExpires) * 1e3).toISOString()}).`,
|
|
862
862
|
details: { expiredAt: new Date(Number(userExpires) * 1e3).toISOString(), action: "renew" }
|
|
863
863
|
};
|
|
864
864
|
}
|
|
@@ -887,7 +887,7 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
887
887
|
consoleUrl: agentConsoleUrl(tokenId),
|
|
888
888
|
howToFix: [
|
|
889
889
|
`1. Use 'setup_guide' command to generate an OperatorPermit for this wallet`,
|
|
890
|
-
`2.
|
|
890
|
+
`2. Subscriber (${renter}) can call setOperator(${tokenId}, ${account.address}, <expiry>) on AgentNFA`,
|
|
891
891
|
`3. Go to ${agentConsoleUrl(tokenId)} to set operator`,
|
|
892
892
|
`4. Use the correct RUNNER_PRIVATE_KEY for operator ${operator}`
|
|
893
893
|
]
|
|
@@ -1238,7 +1238,7 @@ async function ensureAccess(tokenId, rpcUrl, publicClient) {
|
|
|
1238
1238
|
"ACCESS_DENIED",
|
|
1239
1239
|
access.message || `Access denied for token_id ${tokenId.toString()}`,
|
|
1240
1240
|
access.details,
|
|
1241
|
-
"Check operator permissions and
|
|
1241
|
+
"Check operator permissions and subscription status"
|
|
1242
1242
|
);
|
|
1243
1243
|
}
|
|
1244
1244
|
}
|
|
@@ -1260,6 +1260,9 @@ async function validateActionsOrThrow(policyClient, tokenId, actions) {
|
|
|
1260
1260
|
"POLICY_REJECTED",
|
|
1261
1261
|
"Policy rejected transaction",
|
|
1262
1262
|
{
|
|
1263
|
+
enforcement: "on-chain",
|
|
1264
|
+
policyGuardContract: DEFAULT_GUARD,
|
|
1265
|
+
verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
|
|
1263
1266
|
failedActionIndex: index,
|
|
1264
1267
|
failedActionTarget: action.target,
|
|
1265
1268
|
failedActionSelector: getActionSelector(action),
|
|
@@ -1349,7 +1352,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1349
1352
|
]);
|
|
1350
1353
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1351
1354
|
let accessStatus = "Active";
|
|
1352
|
-
if (now > userExpires) accessStatus = "
|
|
1355
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1353
1356
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1354
1357
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1355
1358
|
return {
|
|
@@ -2072,14 +2075,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2072
2075
|
walletModel: {
|
|
2073
2076
|
type: "dual_wallet",
|
|
2074
2077
|
ownerWallet: {
|
|
2075
|
-
purpose: "
|
|
2076
|
-
useFor: ["
|
|
2078
|
+
purpose: "Subscribe or mint the agent, own the Agent NFT, authorize the operator, and hold primary assets.",
|
|
2079
|
+
useFor: ["subscribing to or minting the agent", "holding ownership", "authorizing the operator"]
|
|
2077
2080
|
},
|
|
2078
2081
|
operatorWallet: {
|
|
2079
2082
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2080
2083
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2081
2084
|
doNotUseFor: [
|
|
2082
|
-
"minting or
|
|
2085
|
+
"minting or subscribing to the agent",
|
|
2083
2086
|
"holding the Agent NFT",
|
|
2084
2087
|
"using as your main asset wallet"
|
|
2085
2088
|
],
|
|
@@ -2087,8 +2090,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2087
2090
|
}
|
|
2088
2091
|
},
|
|
2089
2092
|
criticalWarnings: [
|
|
2090
|
-
"Do not use the operator wallet to mint,
|
|
2091
|
-
"Use your owner wallet in the browser to complete
|
|
2093
|
+
"Do not use the operator wallet to mint, subscribe to, or hold the Agent NFT.",
|
|
2094
|
+
"Use your owner wallet in the browser to complete subscription and operator authorization.",
|
|
2092
2095
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2093
2096
|
],
|
|
2094
2097
|
listingSelection: {
|
|
@@ -2123,7 +2126,7 @@ function generateOperatorWallet() {
|
|
|
2123
2126
|
securityModel: "dual_wallet",
|
|
2124
2127
|
safeIfLeaked: "This is not the owner wallet. A leak does not grant unrestricted vault withdrawal because owner permissions stay on the owner wallet and PolicyGuard still limits operator actions.",
|
|
2125
2128
|
doNotUseFor: [
|
|
2126
|
-
"minting or
|
|
2129
|
+
"minting or subscribing to the agent",
|
|
2127
2130
|
"holding the Agent NFT",
|
|
2128
2131
|
"holding your main assets"
|
|
2129
2132
|
],
|
|
@@ -2239,7 +2242,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2239
2242
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2240
2243
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2241
2244
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2242
|
-
const
|
|
2245
|
+
const subscriptionActive = now <= userExpires;
|
|
2243
2246
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2244
2247
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2245
2248
|
const blockers = [];
|
|
@@ -2249,9 +2252,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2249
2252
|
blockers.push("Operator session key is not loaded.");
|
|
2250
2253
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2251
2254
|
}
|
|
2252
|
-
if (!
|
|
2253
|
-
blockers.push(`
|
|
2254
|
-
nextActions.push("Use the owner wallet on shll.run to renew the
|
|
2255
|
+
if (!subscriptionActive) {
|
|
2256
|
+
blockers.push(`Subscription expired at ${new Date(Number(userExpires) * 1e3).toISOString()}.`);
|
|
2257
|
+
nextActions.push("Use the owner wallet on shll.run to renew the subscription before trading.");
|
|
2255
2258
|
}
|
|
2256
2259
|
if (!operatorAuthorizationActive) {
|
|
2257
2260
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2275,7 +2278,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2275
2278
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2276
2279
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2277
2280
|
}
|
|
2278
|
-
const readinessStage = !runnerAccount ? "needs_session_key" : !
|
|
2281
|
+
const readinessStage = !runnerAccount ? "needs_session_key" : !subscriptionActive ? "needs_subscription" : !operatorAuthorizationActive || !runnerMatchesOperator ? "needs_operator_authorization" : opBalance !== null && opBalance < MIN_OPERATOR_GAS_WEI ? "needs_operator_gas" : bnbBalance === 0n ? "ready_but_unfunded" : "ready";
|
|
2279
2282
|
let activityStats = { available: false };
|
|
2280
2283
|
try {
|
|
2281
2284
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2302,10 +2305,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2302
2305
|
nextActions: dedupeStrings(nextActions)
|
|
2303
2306
|
},
|
|
2304
2307
|
walletModelReminder: {
|
|
2305
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2308
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2306
2309
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2307
2310
|
doNotUseOperatorWalletFor: [
|
|
2308
|
-
"minting or
|
|
2311
|
+
"minting or subscribing to the agent",
|
|
2309
2312
|
"holding the Agent NFT",
|
|
2310
2313
|
"storing primary funds"
|
|
2311
2314
|
]
|
|
@@ -2324,8 +2327,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2324
2327
|
recommendedMinGasBnb: "0.001"
|
|
2325
2328
|
},
|
|
2326
2329
|
access: {
|
|
2327
|
-
|
|
2328
|
-
|
|
2330
|
+
subscriptionActive,
|
|
2331
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2329
2332
|
operatorAuthorizationActive,
|
|
2330
2333
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2331
2334
|
runnerMatchesOperator,
|
|
@@ -2712,7 +2715,7 @@ function registerSetupCommands(program2) {
|
|
|
2712
2715
|
process.exit(1);
|
|
2713
2716
|
}
|
|
2714
2717
|
});
|
|
2715
|
-
const setupCmd = new import_commander7.Command("setup-guide").description("Print dual-wallet setup instructions for a specific template").option("-l, --listing <hex>", "Template listing ID").option("-d, --days <number>", "Number of days to
|
|
2718
|
+
const setupCmd = new import_commander7.Command("setup-guide").description("Print dual-wallet setup instructions for a specific template").option("-l, --listing <hex>", "Template listing ID").option("-d, --days <number>", "Number of days to subscribe", "7");
|
|
2716
2719
|
setupCmd.action(async (opts) => {
|
|
2717
2720
|
try {
|
|
2718
2721
|
const result = await buildSetupGuide(opts.listing, parseInt(opts.days, 10));
|
|
@@ -2720,8 +2723,8 @@ function registerSetupCommands(program2) {
|
|
|
2720
2723
|
...result,
|
|
2721
2724
|
steps: [
|
|
2722
2725
|
{ step: 1, action: `Open ${result.setupUrl}` },
|
|
2723
|
-
{ step: 2, action: "Use your owner wallet in the browser. Do not use the operator wallet for
|
|
2724
|
-
{ step: 3, action: "Confirm the
|
|
2726
|
+
{ step: 2, action: "Use your owner wallet in the browser. Do not use the operator wallet for subscription or mint." },
|
|
2727
|
+
{ step: 3, action: "Confirm the subscription or mint transaction in the owner wallet." },
|
|
2725
2728
|
{ step: 4, action: "Authorize the operator wallet for AI execution." },
|
|
2726
2729
|
{ step: 5, action: "Fund the vault with BNB or trading tokens. Do not use the operator wallet as the vault wallet." },
|
|
2727
2730
|
{ step: 6, action: "Send the token-id back to AI so it can automatically run readiness checks." }
|
package/dist/index.mjs
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
transferFromVault,
|
|
28
28
|
unwrapWbnb,
|
|
29
29
|
wrapBnb
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-RUCWJDVB.mjs";
|
|
31
31
|
|
|
32
32
|
// src/index.ts
|
|
33
33
|
import { Command as Command9 } from "commander";
|
|
@@ -359,7 +359,7 @@ function registerSetupCommands(program2) {
|
|
|
359
359
|
process.exit(1);
|
|
360
360
|
}
|
|
361
361
|
});
|
|
362
|
-
const setupCmd = new Command7("setup-guide").description("Print dual-wallet setup instructions for a specific template").option("-l, --listing <hex>", "Template listing ID").option("-d, --days <number>", "Number of days to
|
|
362
|
+
const setupCmd = new Command7("setup-guide").description("Print dual-wallet setup instructions for a specific template").option("-l, --listing <hex>", "Template listing ID").option("-d, --days <number>", "Number of days to subscribe", "7");
|
|
363
363
|
setupCmd.action(async (opts) => {
|
|
364
364
|
try {
|
|
365
365
|
const result = await buildSetupGuide(opts.listing, parseInt(opts.days, 10));
|
|
@@ -367,8 +367,8 @@ function registerSetupCommands(program2) {
|
|
|
367
367
|
...result,
|
|
368
368
|
steps: [
|
|
369
369
|
{ step: 1, action: `Open ${result.setupUrl}` },
|
|
370
|
-
{ step: 2, action: "Use your owner wallet in the browser. Do not use the operator wallet for
|
|
371
|
-
{ step: 3, action: "Confirm the
|
|
370
|
+
{ step: 2, action: "Use your owner wallet in the browser. Do not use the operator wallet for subscription or mint." },
|
|
371
|
+
{ step: 3, action: "Confirm the subscription or mint transaction in the owner wallet." },
|
|
372
372
|
{ step: 4, action: "Authorize the operator wallet for AI execution." },
|
|
373
373
|
{ step: 5, action: "Fund the vault with BNB or trading tokens. Do not use the operator wallet as the vault wallet." },
|
|
374
374
|
{ step: 6, action: "Send the token-id back to AI so it can automatically run readiness checks." }
|
package/dist/mcp.js
CHANGED
|
@@ -12,7 +12,7 @@ var MEV_PROTECTED_RPC = "https://bscrpc.pancakeswap.finance";
|
|
|
12
12
|
var DEFAULT_LISTING_MANAGER = "0x1f9CE85bD0FF75acc3D92eB79f1Eb472f0865071";
|
|
13
13
|
var DEFAULT_LISTING_ID = "0x64083b44e38db02749e6e16bf84ce6c19146cc42a108e53324e11f250b15a0b7";
|
|
14
14
|
var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
|
|
15
|
-
var SKILL_VERSION = "6.0.
|
|
15
|
+
var SKILL_VERSION = "6.0.4";
|
|
16
16
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
17
17
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
18
18
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -856,8 +856,8 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
856
856
|
if (now > userExpires) {
|
|
857
857
|
return {
|
|
858
858
|
blocked: true,
|
|
859
|
-
errorType: "
|
|
860
|
-
message: `Agent token-id ${tokenId}
|
|
859
|
+
errorType: "subscription_expired",
|
|
860
|
+
message: `Agent token-id ${tokenId} subscription has EXPIRED (expired at ${new Date(Number(userExpires) * 1e3).toISOString()}).`,
|
|
861
861
|
details: { expiredAt: new Date(Number(userExpires) * 1e3).toISOString(), action: "renew" }
|
|
862
862
|
};
|
|
863
863
|
}
|
|
@@ -886,7 +886,7 @@ async function checkAccess(rpcUrl, tokenId, existingPublicClient) {
|
|
|
886
886
|
consoleUrl: agentConsoleUrl(tokenId),
|
|
887
887
|
howToFix: [
|
|
888
888
|
`1. Use 'setup_guide' command to generate an OperatorPermit for this wallet`,
|
|
889
|
-
`2.
|
|
889
|
+
`2. Subscriber (${renter}) can call setOperator(${tokenId}, ${account.address}, <expiry>) on AgentNFA`,
|
|
890
890
|
`3. Go to ${agentConsoleUrl(tokenId)} to set operator`,
|
|
891
891
|
`4. Use the correct RUNNER_PRIVATE_KEY for operator ${operator}`
|
|
892
892
|
]
|
|
@@ -1218,7 +1218,7 @@ async function ensureAccess(tokenId, rpcUrl, publicClient) {
|
|
|
1218
1218
|
"ACCESS_DENIED",
|
|
1219
1219
|
access.message || `Access denied for token_id ${tokenId.toString()}`,
|
|
1220
1220
|
access.details,
|
|
1221
|
-
"Check operator permissions and
|
|
1221
|
+
"Check operator permissions and subscription status"
|
|
1222
1222
|
);
|
|
1223
1223
|
}
|
|
1224
1224
|
}
|
|
@@ -1240,6 +1240,9 @@ async function validateActionsOrThrow(policyClient, tokenId, actions) {
|
|
|
1240
1240
|
"POLICY_REJECTED",
|
|
1241
1241
|
"Policy rejected transaction",
|
|
1242
1242
|
{
|
|
1243
|
+
enforcement: "on-chain",
|
|
1244
|
+
policyGuardContract: DEFAULT_GUARD,
|
|
1245
|
+
verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
|
|
1243
1246
|
failedActionIndex: index,
|
|
1244
1247
|
failedActionTarget: action.target,
|
|
1245
1248
|
failedActionSelector: getActionSelector(action),
|
|
@@ -1329,7 +1332,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1329
1332
|
]);
|
|
1330
1333
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1331
1334
|
let accessStatus = "Active";
|
|
1332
|
-
if (now > userExpires) accessStatus = "
|
|
1335
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1333
1336
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1334
1337
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1335
1338
|
return {
|
|
@@ -2103,14 +2106,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2103
2106
|
walletModel: {
|
|
2104
2107
|
type: "dual_wallet",
|
|
2105
2108
|
ownerWallet: {
|
|
2106
|
-
purpose: "
|
|
2107
|
-
useFor: ["
|
|
2109
|
+
purpose: "Subscribe or mint the agent, own the Agent NFT, authorize the operator, and hold primary assets.",
|
|
2110
|
+
useFor: ["subscribing to or minting the agent", "holding ownership", "authorizing the operator"]
|
|
2108
2111
|
},
|
|
2109
2112
|
operatorWallet: {
|
|
2110
2113
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2111
2114
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2112
2115
|
doNotUseFor: [
|
|
2113
|
-
"minting or
|
|
2116
|
+
"minting or subscribing to the agent",
|
|
2114
2117
|
"holding the Agent NFT",
|
|
2115
2118
|
"using as your main asset wallet"
|
|
2116
2119
|
],
|
|
@@ -2118,8 +2121,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2118
2121
|
}
|
|
2119
2122
|
},
|
|
2120
2123
|
criticalWarnings: [
|
|
2121
|
-
"Do not use the operator wallet to mint,
|
|
2122
|
-
"Use your owner wallet in the browser to complete
|
|
2124
|
+
"Do not use the operator wallet to mint, subscribe to, or hold the Agent NFT.",
|
|
2125
|
+
"Use your owner wallet in the browser to complete subscription and operator authorization.",
|
|
2123
2126
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2124
2127
|
],
|
|
2125
2128
|
listingSelection: {
|
|
@@ -2154,7 +2157,7 @@ function generateOperatorWallet() {
|
|
|
2154
2157
|
securityModel: "dual_wallet",
|
|
2155
2158
|
safeIfLeaked: "This is not the owner wallet. A leak does not grant unrestricted vault withdrawal because owner permissions stay on the owner wallet and PolicyGuard still limits operator actions.",
|
|
2156
2159
|
doNotUseFor: [
|
|
2157
|
-
"minting or
|
|
2160
|
+
"minting or subscribing to the agent",
|
|
2158
2161
|
"holding the Agent NFT",
|
|
2159
2162
|
"holding your main assets"
|
|
2160
2163
|
],
|
|
@@ -2300,7 +2303,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2300
2303
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2301
2304
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2302
2305
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2303
|
-
const
|
|
2306
|
+
const subscriptionActive = now <= userExpires;
|
|
2304
2307
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2305
2308
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2306
2309
|
const blockers = [];
|
|
@@ -2310,9 +2313,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2310
2313
|
blockers.push("Operator session key is not loaded.");
|
|
2311
2314
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2312
2315
|
}
|
|
2313
|
-
if (!
|
|
2314
|
-
blockers.push(`
|
|
2315
|
-
nextActions.push("Use the owner wallet on shll.run to renew the
|
|
2316
|
+
if (!subscriptionActive) {
|
|
2317
|
+
blockers.push(`Subscription expired at ${new Date(Number(userExpires) * 1e3).toISOString()}.`);
|
|
2318
|
+
nextActions.push("Use the owner wallet on shll.run to renew the subscription before trading.");
|
|
2316
2319
|
}
|
|
2317
2320
|
if (!operatorAuthorizationActive) {
|
|
2318
2321
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2336,7 +2339,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2336
2339
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2337
2340
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2338
2341
|
}
|
|
2339
|
-
const readinessStage = !runnerAccount ? "needs_session_key" : !
|
|
2342
|
+
const readinessStage = !runnerAccount ? "needs_session_key" : !subscriptionActive ? "needs_subscription" : !operatorAuthorizationActive || !runnerMatchesOperator ? "needs_operator_authorization" : opBalance !== null && opBalance < MIN_OPERATOR_GAS_WEI ? "needs_operator_gas" : bnbBalance === 0n ? "ready_but_unfunded" : "ready";
|
|
2340
2343
|
let activityStats = { available: false };
|
|
2341
2344
|
try {
|
|
2342
2345
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2363,10 +2366,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2363
2366
|
nextActions: dedupeStrings(nextActions)
|
|
2364
2367
|
},
|
|
2365
2368
|
walletModelReminder: {
|
|
2366
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2369
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2367
2370
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2368
2371
|
doNotUseOperatorWalletFor: [
|
|
2369
|
-
"minting or
|
|
2372
|
+
"minting or subscribing to the agent",
|
|
2370
2373
|
"holding the Agent NFT",
|
|
2371
2374
|
"storing primary funds"
|
|
2372
2375
|
]
|
|
@@ -2385,8 +2388,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2385
2388
|
recommendedMinGasBnb: "0.001"
|
|
2386
2389
|
},
|
|
2387
2390
|
access: {
|
|
2388
|
-
|
|
2389
|
-
|
|
2391
|
+
subscriptionActive,
|
|
2392
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2390
2393
|
operatorAuthorizationActive,
|
|
2391
2394
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2392
2395
|
runnerMatchesOperator,
|
|
@@ -2833,7 +2836,7 @@ function asToolResult7(payload) {
|
|
|
2833
2836
|
function registerSetupTools(server2) {
|
|
2834
2837
|
server2.tool(
|
|
2835
2838
|
"listings",
|
|
2836
|
-
"List all available agent templates for
|
|
2839
|
+
"List all available agent templates for subscription",
|
|
2837
2840
|
{},
|
|
2838
2841
|
async () => {
|
|
2839
2842
|
try {
|
|
@@ -2851,10 +2854,10 @@ function registerSetupTools(server2) {
|
|
|
2851
2854
|
);
|
|
2852
2855
|
server2.tool(
|
|
2853
2856
|
"setup_guide",
|
|
2854
|
-
"Generate step-by-step dual-wallet onboarding instructions. Owner wallet completes
|
|
2857
|
+
"Generate step-by-step dual-wallet onboarding instructions. Owner wallet completes subscription or mint; operator wallet is AI-only.",
|
|
2855
2858
|
{
|
|
2856
2859
|
listing_id: CommonSchemas.listingId.optional(),
|
|
2857
|
-
days: import_zod7.z.number().int().min(7).default(7).describe("Number of days to
|
|
2860
|
+
days: import_zod7.z.number().int().min(7).default(7).describe("Number of days to subscribe")
|
|
2858
2861
|
},
|
|
2859
2862
|
async ({ listing_id, days }) => {
|
|
2860
2863
|
try {
|
|
@@ -2864,7 +2867,7 @@ function registerSetupTools(server2) {
|
|
|
2864
2867
|
steps: [
|
|
2865
2868
|
{ step: 1, title: "Open SHLL Setup Page", action: `Open ${result.setupUrl}` },
|
|
2866
2869
|
{ step: 2, title: "Use Owner Wallet", action: "Use your main owner wallet in the browser. Do not use the operator wallet for this step." },
|
|
2867
|
-
{ step: 3, title: "
|
|
2870
|
+
{ step: 3, title: "Subscribe or Mint Agent", action: "Confirm the subscription or mint transaction in the owner wallet." },
|
|
2868
2871
|
{ step: 4, title: "Authorize Operator", action: "Authorize the operator wallet for AI execution.", note: `Operator: ${result.operatorAddress}` },
|
|
2869
2872
|
{ step: 5, title: "Fund Vault", action: "Deposit BNB or tokens into the vault for trading. Do not store primary assets in the operator wallet." },
|
|
2870
2873
|
{ step: 6, title: "Return Token ID", action: "Send the token-id back to AI so it can automatically check operator gas, vault balance, and policy readiness." }
|
package/dist/mcp.mjs
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
transferFromVault,
|
|
27
27
|
unwrapWbnb,
|
|
28
28
|
wrapBnb
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-RUCWJDVB.mjs";
|
|
30
30
|
|
|
31
31
|
// src/mcp.ts
|
|
32
32
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -389,7 +389,7 @@ function asToolResult7(payload) {
|
|
|
389
389
|
function registerSetupTools(server2) {
|
|
390
390
|
server2.tool(
|
|
391
391
|
"listings",
|
|
392
|
-
"List all available agent templates for
|
|
392
|
+
"List all available agent templates for subscription",
|
|
393
393
|
{},
|
|
394
394
|
async () => {
|
|
395
395
|
try {
|
|
@@ -407,10 +407,10 @@ function registerSetupTools(server2) {
|
|
|
407
407
|
);
|
|
408
408
|
server2.tool(
|
|
409
409
|
"setup_guide",
|
|
410
|
-
"Generate step-by-step dual-wallet onboarding instructions. Owner wallet completes
|
|
410
|
+
"Generate step-by-step dual-wallet onboarding instructions. Owner wallet completes subscription or mint; operator wallet is AI-only.",
|
|
411
411
|
{
|
|
412
412
|
listing_id: CommonSchemas.listingId.optional(),
|
|
413
|
-
days: z6.number().int().min(7).default(7).describe("Number of days to
|
|
413
|
+
days: z6.number().int().min(7).default(7).describe("Number of days to subscribe")
|
|
414
414
|
},
|
|
415
415
|
async ({ listing_id, days }) => {
|
|
416
416
|
try {
|
|
@@ -420,7 +420,7 @@ function registerSetupTools(server2) {
|
|
|
420
420
|
steps: [
|
|
421
421
|
{ step: 1, title: "Open SHLL Setup Page", action: `Open ${result.setupUrl}` },
|
|
422
422
|
{ step: 2, title: "Use Owner Wallet", action: "Use your main owner wallet in the browser. Do not use the operator wallet for this step." },
|
|
423
|
-
{ step: 3, title: "
|
|
423
|
+
{ step: 3, title: "Subscribe or Mint Agent", action: "Confirm the subscription or mint transaction in the owner wallet." },
|
|
424
424
|
{ step: 4, title: "Authorize Operator", action: "Authorize the operator wallet for AI execution.", note: `Operator: ${result.operatorAddress}` },
|
|
425
425
|
{ step: 5, title: "Fund Vault", action: "Deposit BNB or tokens into the vault for trading. Do not store primary assets in the operator wallet." },
|
|
426
426
|
{ step: 6, title: "Return Token ID", action: "Send the token-id back to AI so it can automatically check operator gas, vault balance, and policy readiness." }
|