shll-skills 6.0.4 → 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 +4 -4
- package/dist/{chunk-IKVUDAK6.mjs → chunk-RUCWJDVB.mjs} +20 -20
- package/dist/index.js +23 -23
- package/dist/index.mjs +4 -4
- package/dist/mcp.js +24 -24
- 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
|
@@ -196,8 +196,8 @@ export SHLL_RPC="https://your-private-bsc-rpc.example.com"
|
|
|
196
196
|
- Recommend the listing with `recommended=true` by default unless the user explicitly wants a specialized template.
|
|
197
197
|
- Run `shll-run setup-guide -l <listingId> -d <days>`.
|
|
198
198
|
- Send `setupUrl` plus the wallet-role explanation.
|
|
199
|
-
- Explicitly warn: do not use the operator wallet to mint,
|
|
200
|
-
- 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.
|
|
201
201
|
|
|
202
202
|
4. User returns with token ID:
|
|
203
203
|
- Run `shll-run status -k <tokenId>`.
|
|
@@ -314,7 +314,7 @@ When the user provides a token address:
|
|
|
314
314
|
2. `NOT authorized for token-id`
|
|
315
315
|
- Operator wallet is not authorized; use setup guide or set operator in console.
|
|
316
316
|
|
|
317
|
-
3. `
|
|
317
|
+
3. `subscription has EXPIRED` or `operator authorization has EXPIRED`
|
|
318
318
|
- Renew subscription or authorization first.
|
|
319
319
|
|
|
320
320
|
4. `status: error` with `errorCode: POLICY_REJECTED`
|
|
@@ -337,7 +337,7 @@ When the user provides a token address:
|
|
|
337
337
|
1. Never describe `generate-wallet` as if it were the user's main wallet.
|
|
338
338
|
2. Always call it the operator wallet or AI hot wallet.
|
|
339
339
|
3. Always explain the dual-wallet model the first time setup is discussed.
|
|
340
|
-
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.
|
|
341
341
|
5. Do not ask the user to manually set `RUNNER_PRIVATE_KEY` in OpenClaw; AI should do it.
|
|
342
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.
|
|
343
343
|
7. When multiple listings are available, recommend one by default and explain why.
|
|
@@ -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
|
}
|
|
@@ -1330,7 +1330,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1330
1330
|
]);
|
|
1331
1331
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1332
1332
|
let accessStatus = "Active";
|
|
1333
|
-
if (now > userExpires) accessStatus = "
|
|
1333
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1334
1334
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1335
1335
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1336
1336
|
return {
|
|
@@ -2102,14 +2102,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2102
2102
|
walletModel: {
|
|
2103
2103
|
type: "dual_wallet",
|
|
2104
2104
|
ownerWallet: {
|
|
2105
|
-
purpose: "
|
|
2106
|
-
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"]
|
|
2107
2107
|
},
|
|
2108
2108
|
operatorWallet: {
|
|
2109
2109
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2110
2110
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2111
2111
|
doNotUseFor: [
|
|
2112
|
-
"minting or
|
|
2112
|
+
"minting or subscribing to the agent",
|
|
2113
2113
|
"holding the Agent NFT",
|
|
2114
2114
|
"using as your main asset wallet"
|
|
2115
2115
|
],
|
|
@@ -2117,8 +2117,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2117
2117
|
}
|
|
2118
2118
|
},
|
|
2119
2119
|
criticalWarnings: [
|
|
2120
|
-
"Do not use the operator wallet to mint,
|
|
2121
|
-
"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.",
|
|
2122
2122
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2123
2123
|
],
|
|
2124
2124
|
listingSelection: {
|
|
@@ -2153,7 +2153,7 @@ function generateOperatorWallet() {
|
|
|
2153
2153
|
securityModel: "dual_wallet",
|
|
2154
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.",
|
|
2155
2155
|
doNotUseFor: [
|
|
2156
|
-
"minting or
|
|
2156
|
+
"minting or subscribing to the agent",
|
|
2157
2157
|
"holding the Agent NFT",
|
|
2158
2158
|
"holding your main assets"
|
|
2159
2159
|
],
|
|
@@ -2299,7 +2299,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2299
2299
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2300
2300
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2301
2301
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2302
|
-
const
|
|
2302
|
+
const subscriptionActive = now <= userExpires;
|
|
2303
2303
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2304
2304
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2305
2305
|
const blockers = [];
|
|
@@ -2309,9 +2309,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2309
2309
|
blockers.push("Operator session key is not loaded.");
|
|
2310
2310
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2311
2311
|
}
|
|
2312
|
-
if (!
|
|
2313
|
-
blockers.push(`
|
|
2314
|
-
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.");
|
|
2315
2315
|
}
|
|
2316
2316
|
if (!operatorAuthorizationActive) {
|
|
2317
2317
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2335,7 +2335,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2335
2335
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2336
2336
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2337
2337
|
}
|
|
2338
|
-
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";
|
|
2339
2339
|
let activityStats = { available: false };
|
|
2340
2340
|
try {
|
|
2341
2341
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2362,10 +2362,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2362
2362
|
nextActions: dedupeStrings(nextActions)
|
|
2363
2363
|
},
|
|
2364
2364
|
walletModelReminder: {
|
|
2365
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2365
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2366
2366
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2367
2367
|
doNotUseOperatorWalletFor: [
|
|
2368
|
-
"minting or
|
|
2368
|
+
"minting or subscribing to the agent",
|
|
2369
2369
|
"holding the Agent NFT",
|
|
2370
2370
|
"storing primary funds"
|
|
2371
2371
|
]
|
|
@@ -2384,8 +2384,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2384
2384
|
recommendedMinGasBnb: "0.001"
|
|
2385
2385
|
},
|
|
2386
2386
|
access: {
|
|
2387
|
-
|
|
2388
|
-
|
|
2387
|
+
subscriptionActive,
|
|
2388
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2389
2389
|
operatorAuthorizationActive,
|
|
2390
2390
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2391
2391
|
runnerMatchesOperator,
|
package/dist/index.js
CHANGED
|
@@ -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
|
}
|
|
@@ -1352,7 +1352,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1352
1352
|
]);
|
|
1353
1353
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1354
1354
|
let accessStatus = "Active";
|
|
1355
|
-
if (now > userExpires) accessStatus = "
|
|
1355
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1356
1356
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1357
1357
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1358
1358
|
return {
|
|
@@ -2075,14 +2075,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2075
2075
|
walletModel: {
|
|
2076
2076
|
type: "dual_wallet",
|
|
2077
2077
|
ownerWallet: {
|
|
2078
|
-
purpose: "
|
|
2079
|
-
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"]
|
|
2080
2080
|
},
|
|
2081
2081
|
operatorWallet: {
|
|
2082
2082
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2083
2083
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2084
2084
|
doNotUseFor: [
|
|
2085
|
-
"minting or
|
|
2085
|
+
"minting or subscribing to the agent",
|
|
2086
2086
|
"holding the Agent NFT",
|
|
2087
2087
|
"using as your main asset wallet"
|
|
2088
2088
|
],
|
|
@@ -2090,8 +2090,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2090
2090
|
}
|
|
2091
2091
|
},
|
|
2092
2092
|
criticalWarnings: [
|
|
2093
|
-
"Do not use the operator wallet to mint,
|
|
2094
|
-
"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.",
|
|
2095
2095
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2096
2096
|
],
|
|
2097
2097
|
listingSelection: {
|
|
@@ -2126,7 +2126,7 @@ function generateOperatorWallet() {
|
|
|
2126
2126
|
securityModel: "dual_wallet",
|
|
2127
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.",
|
|
2128
2128
|
doNotUseFor: [
|
|
2129
|
-
"minting or
|
|
2129
|
+
"minting or subscribing to the agent",
|
|
2130
2130
|
"holding the Agent NFT",
|
|
2131
2131
|
"holding your main assets"
|
|
2132
2132
|
],
|
|
@@ -2242,7 +2242,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2242
2242
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2243
2243
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2244
2244
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2245
|
-
const
|
|
2245
|
+
const subscriptionActive = now <= userExpires;
|
|
2246
2246
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2247
2247
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2248
2248
|
const blockers = [];
|
|
@@ -2252,9 +2252,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2252
2252
|
blockers.push("Operator session key is not loaded.");
|
|
2253
2253
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2254
2254
|
}
|
|
2255
|
-
if (!
|
|
2256
|
-
blockers.push(`
|
|
2257
|
-
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.");
|
|
2258
2258
|
}
|
|
2259
2259
|
if (!operatorAuthorizationActive) {
|
|
2260
2260
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2278,7 +2278,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2278
2278
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2279
2279
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2280
2280
|
}
|
|
2281
|
-
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";
|
|
2282
2282
|
let activityStats = { available: false };
|
|
2283
2283
|
try {
|
|
2284
2284
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2305,10 +2305,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2305
2305
|
nextActions: dedupeStrings(nextActions)
|
|
2306
2306
|
},
|
|
2307
2307
|
walletModelReminder: {
|
|
2308
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2308
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2309
2309
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2310
2310
|
doNotUseOperatorWalletFor: [
|
|
2311
|
-
"minting or
|
|
2311
|
+
"minting or subscribing to the agent",
|
|
2312
2312
|
"holding the Agent NFT",
|
|
2313
2313
|
"storing primary funds"
|
|
2314
2314
|
]
|
|
@@ -2327,8 +2327,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2327
2327
|
recommendedMinGasBnb: "0.001"
|
|
2328
2328
|
},
|
|
2329
2329
|
access: {
|
|
2330
|
-
|
|
2331
|
-
|
|
2330
|
+
subscriptionActive,
|
|
2331
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2332
2332
|
operatorAuthorizationActive,
|
|
2333
2333
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2334
2334
|
runnerMatchesOperator,
|
|
@@ -2715,7 +2715,7 @@ function registerSetupCommands(program2) {
|
|
|
2715
2715
|
process.exit(1);
|
|
2716
2716
|
}
|
|
2717
2717
|
});
|
|
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
|
|
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");
|
|
2719
2719
|
setupCmd.action(async (opts) => {
|
|
2720
2720
|
try {
|
|
2721
2721
|
const result = await buildSetupGuide(opts.listing, parseInt(opts.days, 10));
|
|
@@ -2723,8 +2723,8 @@ function registerSetupCommands(program2) {
|
|
|
2723
2723
|
...result,
|
|
2724
2724
|
steps: [
|
|
2725
2725
|
{ step: 1, action: `Open ${result.setupUrl}` },
|
|
2726
|
-
{ step: 2, action: "Use your owner wallet in the browser. Do not use the operator wallet for
|
|
2727
|
-
{ 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." },
|
|
2728
2728
|
{ step: 4, action: "Authorize the operator wallet for AI execution." },
|
|
2729
2729
|
{ step: 5, action: "Fund the vault with BNB or trading tokens. Do not use the operator wallet as the vault wallet." },
|
|
2730
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
|
@@ -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
|
}
|
|
@@ -1332,7 +1332,7 @@ async function getPortfolio(tokenIdRaw, rpcUrl) {
|
|
|
1332
1332
|
]);
|
|
1333
1333
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
1334
1334
|
let accessStatus = "Active";
|
|
1335
|
-
if (now > userExpires) accessStatus = "
|
|
1335
|
+
if (now > userExpires) accessStatus = "Subscription Expired";
|
|
1336
1336
|
else if (now > operatorExpires) accessStatus = "Operator Auth Expired";
|
|
1337
1337
|
else if (operator.toLowerCase() !== account.address.toLowerCase()) accessStatus = "Operator Mismatch";
|
|
1338
1338
|
return {
|
|
@@ -2106,14 +2106,14 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2106
2106
|
walletModel: {
|
|
2107
2107
|
type: "dual_wallet",
|
|
2108
2108
|
ownerWallet: {
|
|
2109
|
-
purpose: "
|
|
2110
|
-
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"]
|
|
2111
2111
|
},
|
|
2112
2112
|
operatorWallet: {
|
|
2113
2113
|
purpose: "AI-only hot wallet used for gas and policy-limited execution.",
|
|
2114
2114
|
useFor: ["paying gas", "executing policy-limited trades"],
|
|
2115
2115
|
doNotUseFor: [
|
|
2116
|
-
"minting or
|
|
2116
|
+
"minting or subscribing to the agent",
|
|
2117
2117
|
"holding the Agent NFT",
|
|
2118
2118
|
"using as your main asset wallet"
|
|
2119
2119
|
],
|
|
@@ -2121,8 +2121,8 @@ async function buildSetupGuide(listingId, days = 7) {
|
|
|
2121
2121
|
}
|
|
2122
2122
|
},
|
|
2123
2123
|
criticalWarnings: [
|
|
2124
|
-
"Do not use the operator wallet to mint,
|
|
2125
|
-
"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.",
|
|
2126
2126
|
"Keep only a small BNB balance in the operator wallet for gas."
|
|
2127
2127
|
],
|
|
2128
2128
|
listingSelection: {
|
|
@@ -2157,7 +2157,7 @@ function generateOperatorWallet() {
|
|
|
2157
2157
|
securityModel: "dual_wallet",
|
|
2158
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.",
|
|
2159
2159
|
doNotUseFor: [
|
|
2160
|
-
"minting or
|
|
2160
|
+
"minting or subscribing to the agent",
|
|
2161
2161
|
"holding the Agent NFT",
|
|
2162
2162
|
"holding your main assets"
|
|
2163
2163
|
],
|
|
@@ -2303,7 +2303,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2303
2303
|
const opBalance = runnerAccount ? await publicClient.getBalance({ address: runnerAccount.address }) : null;
|
|
2304
2304
|
const access = await checkAccess(rpcUrl, tokenId, publicClient);
|
|
2305
2305
|
const now = BigInt(Math.floor(Date.now() / 1e3));
|
|
2306
|
-
const
|
|
2306
|
+
const subscriptionActive = now <= userExpires;
|
|
2307
2307
|
const operatorAuthorizationActive = now <= operatorExpires;
|
|
2308
2308
|
const runnerMatchesOperator = runnerAccount ? runnerAccount.address.toLowerCase() === operator.toLowerCase() : null;
|
|
2309
2309
|
const blockers = [];
|
|
@@ -2313,9 +2313,9 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2313
2313
|
blockers.push("Operator session key is not loaded.");
|
|
2314
2314
|
nextActions.push("In OpenClaw, have AI set RUNNER_PRIVATE_KEY for the current session automatically.");
|
|
2315
2315
|
}
|
|
2316
|
-
if (!
|
|
2317
|
-
blockers.push(`
|
|
2318
|
-
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.");
|
|
2319
2319
|
}
|
|
2320
2320
|
if (!operatorAuthorizationActive) {
|
|
2321
2321
|
blockers.push(`Operator authorization expired at ${new Date(Number(operatorExpires) * 1e3).toISOString()}.`);
|
|
@@ -2339,7 +2339,7 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2339
2339
|
if (blockers.length === 0 && bnbBalance > 0n) {
|
|
2340
2340
|
nextActions.push("Agent is ready. You can ask AI to trade, lend, transfer, or rebalance from this token-id.");
|
|
2341
2341
|
}
|
|
2342
|
-
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";
|
|
2343
2343
|
let activityStats = { available: false };
|
|
2344
2344
|
try {
|
|
2345
2345
|
const res = await fetch(`${DEFAULT_INDEXER}/api/agents/${tokenIdRaw}/summary`, { signal: AbortSignal.timeout(5e3) });
|
|
@@ -2366,10 +2366,10 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2366
2366
|
nextActions: dedupeStrings(nextActions)
|
|
2367
2367
|
},
|
|
2368
2368
|
walletModelReminder: {
|
|
2369
|
-
ownerWallet: "Use your owner wallet to mint,
|
|
2369
|
+
ownerWallet: "Use your owner wallet to mint, subscribe, renew, and authorize the operator.",
|
|
2370
2370
|
operatorWallet: "Use RUNNER_PRIVATE_KEY only as the AI hot wallet for gas and policy-limited execution.",
|
|
2371
2371
|
doNotUseOperatorWalletFor: [
|
|
2372
|
-
"minting or
|
|
2372
|
+
"minting or subscribing to the agent",
|
|
2373
2373
|
"holding the Agent NFT",
|
|
2374
2374
|
"storing primary funds"
|
|
2375
2375
|
]
|
|
@@ -2388,8 +2388,8 @@ async function getStatusOverview(tokenIdRaw, rpcUrl) {
|
|
|
2388
2388
|
recommendedMinGasBnb: "0.001"
|
|
2389
2389
|
},
|
|
2390
2390
|
access: {
|
|
2391
|
-
|
|
2392
|
-
|
|
2391
|
+
subscriptionActive,
|
|
2392
|
+
subscriptionExpiresAt: new Date(Number(userExpires) * 1e3).toISOString(),
|
|
2393
2393
|
operatorAuthorizationActive,
|
|
2394
2394
|
operatorAuthorizationExpiresAt: new Date(Number(operatorExpires) * 1e3).toISOString(),
|
|
2395
2395
|
runnerMatchesOperator,
|
|
@@ -2836,7 +2836,7 @@ function asToolResult7(payload) {
|
|
|
2836
2836
|
function registerSetupTools(server2) {
|
|
2837
2837
|
server2.tool(
|
|
2838
2838
|
"listings",
|
|
2839
|
-
"List all available agent templates for
|
|
2839
|
+
"List all available agent templates for subscription",
|
|
2840
2840
|
{},
|
|
2841
2841
|
async () => {
|
|
2842
2842
|
try {
|
|
@@ -2854,10 +2854,10 @@ function registerSetupTools(server2) {
|
|
|
2854
2854
|
);
|
|
2855
2855
|
server2.tool(
|
|
2856
2856
|
"setup_guide",
|
|
2857
|
-
"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.",
|
|
2858
2858
|
{
|
|
2859
2859
|
listing_id: CommonSchemas.listingId.optional(),
|
|
2860
|
-
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")
|
|
2861
2861
|
},
|
|
2862
2862
|
async ({ listing_id, days }) => {
|
|
2863
2863
|
try {
|
|
@@ -2867,7 +2867,7 @@ function registerSetupTools(server2) {
|
|
|
2867
2867
|
steps: [
|
|
2868
2868
|
{ step: 1, title: "Open SHLL Setup Page", action: `Open ${result.setupUrl}` },
|
|
2869
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." },
|
|
2870
|
-
{ step: 3, title: "
|
|
2870
|
+
{ step: 3, title: "Subscribe or Mint Agent", action: "Confirm the subscription or mint transaction in the owner wallet." },
|
|
2871
2871
|
{ step: 4, title: "Authorize Operator", action: "Authorize the operator wallet for AI execution.", note: `Operator: ${result.operatorAddress}` },
|
|
2872
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." },
|
|
2873
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." }
|