shll-skills 6.0.1 → 6.0.3

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/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.1
4
+ version: 6.0.2
5
5
  author: SHLL Team
6
6
  website: https://shll.run
7
7
  twitter: https://twitter.com/shllrun
@@ -68,7 +68,7 @@ On-chain guardrails:
68
68
  - Spending limits, cooldowns, whitelist rules, and protocol rules are enforced on-chain.
69
69
  - Raw calldata is blocked if the recipient cannot be decoded safely.
70
70
 
71
- ## Current Critical Constraints (v6.0.0)
71
+ ## Current Critical Constraints (v6.0.2)
72
72
 
73
73
  1. `init` command is disabled. Do not use it.
74
74
  2. Raw calldata remains high risk; rely on strict recipient safety checks.
@@ -146,11 +146,10 @@ Write commands include:
146
146
  - `raw`
147
147
  - `lend`
148
148
  - `redeem`
149
- - `config`
150
149
  - `four_buy`
151
150
  - `four_sell`
152
151
 
153
- Read-only commands do not require confirmation.
152
+ Read-only commands (no confirmation needed): `config`, `policies`, `status`, `history`, `portfolio`, `price`, `tokens`, `search`, `balance`, `four_info`.
154
153
 
155
154
  ## CLI Commands
156
155
 
@@ -187,6 +186,7 @@ If `-l/--listing` is omitted, `setup-guide` auto-selects an active listing from
187
186
 
188
187
  ### Read-only and audit
189
188
 
189
+ - `shll-run config -k <tokenId>` (view-only; modify via web console)
190
190
  - `shll-run portfolio -k <tokenId>`
191
191
  - `shll-run price --token <symbolOrAddress>`
192
192
  - `shll-run search --query <text>`
@@ -6,7 +6,7 @@ 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.1";
9
+ var SKILL_VERSION = "6.0.2";
10
10
  var BINDINGS_UPDATED_AT = "2026-03-06";
11
11
  var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
12
12
  var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
@@ -170,16 +170,11 @@ var LISTING_MANAGER_ABI = [
170
170
  }
171
171
  ];
172
172
  var SPENDING_LIMIT_ABI = [
173
- { type: "function", name: "setLimits", inputs: [{ name: "instanceId", type: "uint256" }, { name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
174
173
  { type: "function", name: "instanceLimits", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], stateMutability: "view" },
175
174
  { type: "function", name: "tokenRestrictionEnabled", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "bool" }], stateMutability: "view" },
176
- { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" },
177
- { type: "function", name: "addToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
178
- { type: "function", name: "removeToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
179
- { type: "function", name: "setTokenRestriction", inputs: [{ name: "instanceId", type: "uint256" }, { name: "enabled", type: "bool" }], outputs: [], stateMutability: "nonpayable" }
175
+ { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" }
180
176
  ];
181
177
  var COOLDOWN_ABI = [
182
- { type: "function", name: "setCooldown", inputs: [{ name: "instanceId", type: "uint256" }, { name: "seconds_", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
183
178
  { type: "function", name: "cooldownSeconds", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }
184
179
  ];
185
180
  var FOUR_MEME_HELPER_ABI = [
@@ -293,7 +288,7 @@ async function resolveTokenAsync(publicClient, input) {
293
288
  }
294
289
 
295
290
  // src/shared/clients.ts
296
- import { createPublicClient as createPublicClient2, createWalletClient as createWalletClient2, http as http2 } from "viem";
291
+ import { createPublicClient as createPublicClient2, http as http2 } from "viem";
297
292
  import { privateKeyToAccount as privateKeyToAccount2, generatePrivateKey } from "viem/accounts";
298
293
  import { bsc as bsc2 } from "viem/chains";
299
294
 
@@ -823,14 +818,6 @@ function createClients(rpcUrl) {
823
818
  });
824
819
  return { account, publicClient, policyClient, rpc: writeRpc };
825
820
  }
826
- function createWallet(rpcUrl) {
827
- const privateKey = process.env.RUNNER_PRIVATE_KEY;
828
- if (!privateKey) throw new Error("RUNNER_PRIVATE_KEY environment variable is required");
829
- const rpc = rpcUrl || DEFAULT_RPC;
830
- const account = privateKeyToAccount2(toHex(privateKey));
831
- const walletClient = createWalletClient2({ account, chain: bsc2, transport: http2(rpc) });
832
- return { account, walletClient };
833
- }
834
821
  function createReadOnlyClient(rpcUrl) {
835
822
  const rpc = rpcUrl || process.env.SHLL_RPC || DEFAULT_RPC;
836
823
  return createPublicClient2({
@@ -990,10 +977,14 @@ function checkActionRecipientSafety(action, vault) {
990
977
  function policyRejectionHelp(reason, tokenId) {
991
978
  const consoleUrl = agentConsoleUrl(tokenId);
992
979
  const r = reason ?? "";
980
+ if (r.includes("Function not allowed"))
981
+ return { explanation: "The contract method selector is not enabled by the active DeFi policy configuration.", action: "Enable the required protocol pack or selector in Console > Safety, or use a supported transaction path.", consoleUrl };
993
982
  if (r.includes("Approve spender not allowed"))
994
983
  return { explanation: "The DEX router address is not in the approved spender whitelist.", action: "Contact the Agent owner to approve this router, or use a different DEX.", consoleUrl };
995
984
  if (r.includes("Target not allowed"))
996
985
  return { explanation: "The contract address is not in the DeFi target whitelist.", action: "Enable the corresponding DeFi Pack in Console > Safety, or contact the Agent owner.", consoleUrl };
986
+ if (r.includes("Receiver must be vault"))
987
+ return { explanation: "Swap output recipient must be the agent vault address enforced by ReceiverGuard.", action: "Retry with recipient/to set to the vault address, or use a supported flow that routes proceeds back to the vault.", consoleUrl };
997
988
  if (r.includes("Token not in whitelist"))
998
989
  return { explanation: "Token restriction is ON and this token is not whitelisted.", action: `Add the token to the whitelist or disable token restriction at: ${consoleUrl}`, consoleUrl };
999
990
  if (r.includes("Exceeds per-tx limit"))
@@ -1241,13 +1232,18 @@ function ensureRecipientSafe(result) {
1241
1232
  }
1242
1233
  }
1243
1234
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1244
- for (const action of actions) {
1235
+ for (const [index, action] of actions.entries()) {
1245
1236
  const sim = await policyClient.validate(tokenId, action);
1246
1237
  if (!sim.ok) {
1247
1238
  throw new SkillError(
1248
1239
  "POLICY_REJECTED",
1249
1240
  "Policy rejected transaction",
1250
1241
  {
1242
+ failedActionIndex: index,
1243
+ failedActionTarget: action.target,
1244
+ failedActionSelector: getActionSelector(action),
1245
+ failedActionFunction: getActionFunctionName(action),
1246
+ failedActionValue: action.value.toString(),
1251
1247
  reason: sim.reason,
1252
1248
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1253
1249
  },
@@ -1267,6 +1263,37 @@ async function executeActions(policyClient, tokenId, actions) {
1267
1263
  const result = await policyClient.executeBatch(tokenId, actions, true);
1268
1264
  return { hash: result.hash };
1269
1265
  }
1266
+ function getActionSelector(action) {
1267
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1268
+ }
1269
+ function getActionFunctionName(action) {
1270
+ if (action.data === "0x") {
1271
+ return "nativeTransfer";
1272
+ }
1273
+ const candidates = [
1274
+ ERC20_ABI,
1275
+ WBNB_ABI,
1276
+ VTOKEN_ABI,
1277
+ VBNB_MINT_ABI,
1278
+ SWAP_EXACT_ETH_ABI,
1279
+ SWAP_EXACT_TOKENS_ABI,
1280
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1281
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1282
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1283
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1284
+ V3_EXACT_INPUT_SINGLE_ABI,
1285
+ V3_EXACT_INPUT_ABI,
1286
+ FOUR_MEME_V1_ABI,
1287
+ FOUR_MEME_V2_ABI
1288
+ ];
1289
+ for (const abi of candidates) {
1290
+ const decoded = tryDecodeCalldata(abi, action.data);
1291
+ if (decoded?.functionName) {
1292
+ return decoded.functionName;
1293
+ }
1294
+ }
1295
+ return "unknown";
1296
+ }
1270
1297
 
1271
1298
  // src/services/info.ts
1272
1299
  var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
@@ -1705,25 +1732,6 @@ async function executeSwap(input) {
1705
1732
  args: [minOut, path, vault, deadline]
1706
1733
  })
1707
1734
  });
1708
- } else if (isNativeOut) {
1709
- actions.push({
1710
- target: tokenIn.address,
1711
- value: 0n,
1712
- data: encodeFunctionData2({
1713
- abi: ERC20_ABI,
1714
- functionName: "approve",
1715
- args: [v2Router, amountIn]
1716
- })
1717
- });
1718
- actions.push({
1719
- target: v2Router,
1720
- value: 0n,
1721
- data: encodeFunctionData2({
1722
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1723
- functionName: "swapExactTokensForETH",
1724
- args: [amountIn, minOut, path, vault, deadline]
1725
- })
1726
- });
1727
1735
  } else {
1728
1736
  actions.push({
1729
1737
  target: tokenIn.address,
@@ -1738,8 +1746,8 @@ async function executeSwap(input) {
1738
1746
  target: v2Router,
1739
1747
  value: 0n,
1740
1748
  data: encodeFunctionData2({
1741
- abi: SWAP_EXACT_TOKENS_ABI,
1742
- functionName: "swapExactTokensForTokens",
1749
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1750
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1743
1751
  args: [amountIn, minOut, path, vault, deadline]
1744
1752
  })
1745
1753
  });
@@ -2417,59 +2425,48 @@ async function getHistory(tokenIdRaw, limit) {
2417
2425
  recentPolicyRejections: rejections.length
2418
2426
  };
2419
2427
  }
2420
- async function updateRiskConfig(tokenIdRaw, options) {
2421
- if (!options.txLimit && !options.dailyLimit && !options.cooldown) {
2422
- throw new SkillError("INVALID_INPUT", "Must specify at least one policy config option");
2423
- }
2428
+ async function getPolicyConfigGuidance(tokenIdRaw, rpcUrl) {
2424
2429
  const tokenId = parseTokenId(tokenIdRaw);
2425
- const { publicClient, policyClient, rpc } = createClients(options.rpcUrl);
2426
- await ensureAccess(tokenId, rpc, publicClient);
2427
- const { walletClient } = createWallet(rpc);
2430
+ const { publicClient, policyClient } = createClients(rpcUrl);
2428
2431
  const policies = await policyClient.getPolicies(tokenId);
2429
- const results = [];
2430
- if (options.txLimit || options.dailyLimit) {
2431
- const spendingPolicy = policies.find((policy) => policy.policyTypeName === "spending_limit");
2432
- if (!spendingPolicy) {
2433
- throw new SkillError("NOT_FOUND", "No SpendingLimitPolicy found");
2432
+ const consoleUrl = agentConsoleUrl(tokenId);
2433
+ const currentConfig = {};
2434
+ const spendingPolicy = policies.find((p) => p.policyTypeName === "spending_limit");
2435
+ if (spendingPolicy) {
2436
+ try {
2437
+ const [maxPerTx, maxPerDay, maxSlippageBps] = await publicClient.readContract({
2438
+ address: spendingPolicy.address,
2439
+ abi: SPENDING_LIMIT_ABI,
2440
+ functionName: "instanceLimits",
2441
+ args: [tokenId]
2442
+ });
2443
+ currentConfig.spendingLimit = {
2444
+ maxPerTx: (Number(maxPerTx) / 1e18).toFixed(4) + " BNB",
2445
+ maxPerDay: (Number(maxPerDay) / 1e18).toFixed(4) + " BNB",
2446
+ slippageBps: maxSlippageBps.toString()
2447
+ };
2448
+ } catch {
2434
2449
  }
2435
- const current = await publicClient.readContract({
2436
- address: spendingPolicy.address,
2437
- abi: SPENDING_LIMIT_ABI,
2438
- functionName: "instanceLimits",
2439
- args: [tokenId]
2440
- });
2441
- const [curMaxPerTx, curMaxPerDay, curSlippage] = current;
2442
- const hash = await walletClient.writeContract({
2443
- address: spendingPolicy.address,
2444
- abi: SPENDING_LIMIT_ABI,
2445
- functionName: "setLimits",
2446
- args: [
2447
- tokenId,
2448
- options.txLimit ? parseAmount(options.txLimit, 18) : curMaxPerTx,
2449
- options.dailyLimit ? parseAmount(options.dailyLimit, 18) : curMaxPerDay,
2450
- curSlippage
2451
- ]
2452
- });
2453
- await publicClient.waitForTransactionReceipt({ hash });
2454
- results.push(`SpendingLimit updated: ${hash}`);
2455
2450
  }
2456
- if (options.cooldown) {
2457
- const cooldownPolicy = policies.find((policy) => policy.policyTypeName === "cooldown");
2458
- if (!cooldownPolicy) {
2459
- throw new SkillError("NOT_FOUND", "No CooldownPolicy found");
2451
+ const cooldownPolicy = policies.find((p) => p.policyTypeName === "cooldown");
2452
+ if (cooldownPolicy) {
2453
+ try {
2454
+ const cooldown = await publicClient.readContract({
2455
+ address: cooldownPolicy.address,
2456
+ abi: COOLDOWN_ABI,
2457
+ functionName: "cooldownSeconds",
2458
+ args: [tokenId]
2459
+ });
2460
+ currentConfig.cooldown = { seconds: Number(cooldown) };
2461
+ } catch {
2460
2462
  }
2461
- const hash = await walletClient.writeContract({
2462
- address: cooldownPolicy.address,
2463
- abi: COOLDOWN_ABI,
2464
- functionName: "setCooldown",
2465
- args: [tokenId, BigInt(options.cooldown)]
2466
- });
2467
- await publicClient.waitForTransactionReceipt({ hash });
2468
- results.push(`Cooldown updated: ${hash}`);
2469
2463
  }
2470
2464
  return {
2471
- status: "success",
2472
- details: results
2465
+ status: "read_only",
2466
+ tokenId: tokenIdRaw,
2467
+ currentConfig,
2468
+ message: "Policy modification via Skills is disabled. Please use the web console to adjust your security settings.",
2469
+ consoleUrl
2473
2470
  };
2474
2471
  }
2475
2472
  function dedupeStrings(values) {
@@ -2507,5 +2504,5 @@ export {
2507
2504
  readTokenRestriction,
2508
2505
  getStatusOverview,
2509
2506
  getHistory,
2510
- updateRiskConfig
2507
+ getPolicyConfigGuidance
2511
2508
  };
package/dist/index.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.1";
15
+ var SKILL_VERSION = "6.0.2";
16
16
  var BINDINGS_UPDATED_AT = "2026-03-06";
17
17
  var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
18
18
  var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
@@ -176,16 +176,11 @@ var LISTING_MANAGER_ABI = [
176
176
  }
177
177
  ];
178
178
  var SPENDING_LIMIT_ABI = [
179
- { type: "function", name: "setLimits", inputs: [{ name: "instanceId", type: "uint256" }, { name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
180
179
  { type: "function", name: "instanceLimits", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], stateMutability: "view" },
181
180
  { type: "function", name: "tokenRestrictionEnabled", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "bool" }], stateMutability: "view" },
182
- { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" },
183
- { type: "function", name: "addToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
184
- { type: "function", name: "removeToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
185
- { type: "function", name: "setTokenRestriction", inputs: [{ name: "instanceId", type: "uint256" }, { name: "enabled", type: "bool" }], outputs: [], stateMutability: "nonpayable" }
181
+ { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" }
186
182
  ];
187
183
  var COOLDOWN_ABI = [
188
- { type: "function", name: "setCooldown", inputs: [{ name: "instanceId", type: "uint256" }, { name: "seconds_", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
189
184
  { type: "function", name: "cooldownSeconds", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }
190
185
  ];
191
186
  var FOUR_MEME_HELPER_ABI = [
@@ -825,14 +820,6 @@ function createClients(rpcUrl) {
825
820
  });
826
821
  return { account, publicClient, policyClient, rpc: writeRpc };
827
822
  }
828
- function createWallet(rpcUrl) {
829
- const privateKey = process.env.RUNNER_PRIVATE_KEY;
830
- if (!privateKey) throw new Error("RUNNER_PRIVATE_KEY environment variable is required");
831
- const rpc = rpcUrl || DEFAULT_RPC;
832
- const account = (0, import_accounts2.privateKeyToAccount)(toHex(privateKey));
833
- const walletClient = (0, import_viem2.createWalletClient)({ account, chain: import_chains2.bsc, transport: (0, import_viem2.http)(rpc) });
834
- return { account, walletClient };
835
- }
836
823
  function createReadOnlyClient(rpcUrl) {
837
824
  const rpc = rpcUrl || process.env.SHLL_RPC || DEFAULT_RPC;
838
825
  return (0, import_viem2.createPublicClient)({
@@ -992,10 +979,14 @@ function checkActionRecipientSafety(action, vault) {
992
979
  function policyRejectionHelp(reason, tokenId) {
993
980
  const consoleUrl = agentConsoleUrl(tokenId);
994
981
  const r = reason ?? "";
982
+ if (r.includes("Function not allowed"))
983
+ return { explanation: "The contract method selector is not enabled by the active DeFi policy configuration.", action: "Enable the required protocol pack or selector in Console > Safety, or use a supported transaction path.", consoleUrl };
995
984
  if (r.includes("Approve spender not allowed"))
996
985
  return { explanation: "The DEX router address is not in the approved spender whitelist.", action: "Contact the Agent owner to approve this router, or use a different DEX.", consoleUrl };
997
986
  if (r.includes("Target not allowed"))
998
987
  return { explanation: "The contract address is not in the DeFi target whitelist.", action: "Enable the corresponding DeFi Pack in Console > Safety, or contact the Agent owner.", consoleUrl };
988
+ if (r.includes("Receiver must be vault"))
989
+ return { explanation: "Swap output recipient must be the agent vault address enforced by ReceiverGuard.", action: "Retry with recipient/to set to the vault address, or use a supported flow that routes proceeds back to the vault.", consoleUrl };
999
990
  if (r.includes("Token not in whitelist"))
1000
991
  return { explanation: "Token restriction is ON and this token is not whitelisted.", action: `Add the token to the whitelist or disable token restriction at: ${consoleUrl}`, consoleUrl };
1001
992
  if (r.includes("Exceeds per-tx limit"))
@@ -1262,13 +1253,18 @@ function ensureRecipientSafe(result) {
1262
1253
  }
1263
1254
  }
1264
1255
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1265
- for (const action of actions) {
1256
+ for (const [index, action] of actions.entries()) {
1266
1257
  const sim = await policyClient.validate(tokenId, action);
1267
1258
  if (!sim.ok) {
1268
1259
  throw new SkillError(
1269
1260
  "POLICY_REJECTED",
1270
1261
  "Policy rejected transaction",
1271
1262
  {
1263
+ failedActionIndex: index,
1264
+ failedActionTarget: action.target,
1265
+ failedActionSelector: getActionSelector(action),
1266
+ failedActionFunction: getActionFunctionName(action),
1267
+ failedActionValue: action.value.toString(),
1272
1268
  reason: sim.reason,
1273
1269
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1274
1270
  },
@@ -1288,6 +1284,37 @@ async function executeActions(policyClient, tokenId, actions) {
1288
1284
  const result = await policyClient.executeBatch(tokenId, actions, true);
1289
1285
  return { hash: result.hash };
1290
1286
  }
1287
+ function getActionSelector(action) {
1288
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1289
+ }
1290
+ function getActionFunctionName(action) {
1291
+ if (action.data === "0x") {
1292
+ return "nativeTransfer";
1293
+ }
1294
+ const candidates = [
1295
+ ERC20_ABI,
1296
+ WBNB_ABI,
1297
+ VTOKEN_ABI,
1298
+ VBNB_MINT_ABI,
1299
+ SWAP_EXACT_ETH_ABI,
1300
+ SWAP_EXACT_TOKENS_ABI,
1301
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1302
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1303
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1304
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1305
+ V3_EXACT_INPUT_SINGLE_ABI,
1306
+ V3_EXACT_INPUT_ABI,
1307
+ FOUR_MEME_V1_ABI,
1308
+ FOUR_MEME_V2_ABI
1309
+ ];
1310
+ for (const abi of candidates) {
1311
+ const decoded = tryDecodeCalldata(abi, action.data);
1312
+ if (decoded?.functionName) {
1313
+ return decoded.functionName;
1314
+ }
1315
+ }
1316
+ return "unknown";
1317
+ }
1291
1318
 
1292
1319
  // src/services/info.ts
1293
1320
  var import_viem5 = require("viem");
@@ -1729,25 +1756,6 @@ async function executeSwap(input) {
1729
1756
  args: [minOut, path, vault, deadline]
1730
1757
  })
1731
1758
  });
1732
- } else if (isNativeOut) {
1733
- actions.push({
1734
- target: tokenIn.address,
1735
- value: 0n,
1736
- data: (0, import_viem7.encodeFunctionData)({
1737
- abi: ERC20_ABI,
1738
- functionName: "approve",
1739
- args: [v2Router, amountIn]
1740
- })
1741
- });
1742
- actions.push({
1743
- target: v2Router,
1744
- value: 0n,
1745
- data: (0, import_viem7.encodeFunctionData)({
1746
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1747
- functionName: "swapExactTokensForETH",
1748
- args: [amountIn, minOut, path, vault, deadline]
1749
- })
1750
- });
1751
1759
  } else {
1752
1760
  actions.push({
1753
1761
  target: tokenIn.address,
@@ -1762,8 +1770,8 @@ async function executeSwap(input) {
1762
1770
  target: v2Router,
1763
1771
  value: 0n,
1764
1772
  data: (0, import_viem7.encodeFunctionData)({
1765
- abi: SWAP_EXACT_TOKENS_ABI,
1766
- functionName: "swapExactTokensForTokens",
1773
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1774
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1767
1775
  args: [amountIn, minOut, path, vault, deadline]
1768
1776
  })
1769
1777
  });
@@ -2360,59 +2368,48 @@ async function getHistory(tokenIdRaw, limit) {
2360
2368
  recentPolicyRejections: rejections.length
2361
2369
  };
2362
2370
  }
2363
- async function updateRiskConfig(tokenIdRaw, options) {
2364
- if (!options.txLimit && !options.dailyLimit && !options.cooldown) {
2365
- throw new SkillError("INVALID_INPUT", "Must specify at least one policy config option");
2366
- }
2371
+ async function getPolicyConfigGuidance(tokenIdRaw, rpcUrl) {
2367
2372
  const tokenId = parseTokenId(tokenIdRaw);
2368
- const { publicClient, policyClient, rpc } = createClients(options.rpcUrl);
2369
- await ensureAccess(tokenId, rpc, publicClient);
2370
- const { walletClient } = createWallet(rpc);
2373
+ const { publicClient, policyClient } = createClients(rpcUrl);
2371
2374
  const policies = await policyClient.getPolicies(tokenId);
2372
- const results = [];
2373
- if (options.txLimit || options.dailyLimit) {
2374
- const spendingPolicy = policies.find((policy) => policy.policyTypeName === "spending_limit");
2375
- if (!spendingPolicy) {
2376
- throw new SkillError("NOT_FOUND", "No SpendingLimitPolicy found");
2375
+ const consoleUrl = agentConsoleUrl(tokenId);
2376
+ const currentConfig = {};
2377
+ const spendingPolicy = policies.find((p) => p.policyTypeName === "spending_limit");
2378
+ if (spendingPolicy) {
2379
+ try {
2380
+ const [maxPerTx, maxPerDay, maxSlippageBps] = await publicClient.readContract({
2381
+ address: spendingPolicy.address,
2382
+ abi: SPENDING_LIMIT_ABI,
2383
+ functionName: "instanceLimits",
2384
+ args: [tokenId]
2385
+ });
2386
+ currentConfig.spendingLimit = {
2387
+ maxPerTx: (Number(maxPerTx) / 1e18).toFixed(4) + " BNB",
2388
+ maxPerDay: (Number(maxPerDay) / 1e18).toFixed(4) + " BNB",
2389
+ slippageBps: maxSlippageBps.toString()
2390
+ };
2391
+ } catch {
2377
2392
  }
2378
- const current = await publicClient.readContract({
2379
- address: spendingPolicy.address,
2380
- abi: SPENDING_LIMIT_ABI,
2381
- functionName: "instanceLimits",
2382
- args: [tokenId]
2383
- });
2384
- const [curMaxPerTx, curMaxPerDay, curSlippage] = current;
2385
- const hash = await walletClient.writeContract({
2386
- address: spendingPolicy.address,
2387
- abi: SPENDING_LIMIT_ABI,
2388
- functionName: "setLimits",
2389
- args: [
2390
- tokenId,
2391
- options.txLimit ? parseAmount(options.txLimit, 18) : curMaxPerTx,
2392
- options.dailyLimit ? parseAmount(options.dailyLimit, 18) : curMaxPerDay,
2393
- curSlippage
2394
- ]
2395
- });
2396
- await publicClient.waitForTransactionReceipt({ hash });
2397
- results.push(`SpendingLimit updated: ${hash}`);
2398
2393
  }
2399
- if (options.cooldown) {
2400
- const cooldownPolicy = policies.find((policy) => policy.policyTypeName === "cooldown");
2401
- if (!cooldownPolicy) {
2402
- throw new SkillError("NOT_FOUND", "No CooldownPolicy found");
2394
+ const cooldownPolicy = policies.find((p) => p.policyTypeName === "cooldown");
2395
+ if (cooldownPolicy) {
2396
+ try {
2397
+ const cooldown = await publicClient.readContract({
2398
+ address: cooldownPolicy.address,
2399
+ abi: COOLDOWN_ABI,
2400
+ functionName: "cooldownSeconds",
2401
+ args: [tokenId]
2402
+ });
2403
+ currentConfig.cooldown = { seconds: Number(cooldown) };
2404
+ } catch {
2403
2405
  }
2404
- const hash = await walletClient.writeContract({
2405
- address: cooldownPolicy.address,
2406
- abi: COOLDOWN_ABI,
2407
- functionName: "setCooldown",
2408
- args: [tokenId, BigInt(options.cooldown)]
2409
- });
2410
- await publicClient.waitForTransactionReceipt({ hash });
2411
- results.push(`Cooldown updated: ${hash}`);
2412
2406
  }
2413
2407
  return {
2414
- status: "success",
2415
- details: results
2408
+ status: "read_only",
2409
+ tokenId: tokenIdRaw,
2410
+ currentConfig,
2411
+ message: "Policy modification via Skills is disabled. Please use the web console to adjust your security settings.",
2412
+ consoleUrl
2416
2413
  };
2417
2414
  }
2418
2415
  function dedupeStrings(values) {
@@ -2582,15 +2579,10 @@ function registerAgentCommands(program2) {
2582
2579
  process.exit(1);
2583
2580
  }
2584
2581
  });
2585
- const configCmd = new import_commander5.Command("config").description("Configure agent risk parameters (Requires RENTER status!)").option("--tx-limit <amount>", "Max BNB per tx").option("--daily-limit <amount>", "Max BNB per day").option("--cooldown <seconds>", "Seconds between tx");
2582
+ const configCmd = new import_commander5.Command("config").description("View current risk parameters (modify via web console)");
2586
2583
  addSharedOptions(configCmd).action(async (opts) => {
2587
2584
  try {
2588
- output(await updateRiskConfig(opts.tokenId, {
2589
- txLimit: opts.txLimit,
2590
- dailyLimit: opts.dailyLimit,
2591
- cooldown: opts.cooldown,
2592
- rpcUrl: opts.rpc
2593
- }));
2585
+ output(await getPolicyConfigGuidance(opts.tokenId, opts.rpc));
2594
2586
  } catch (error) {
2595
2587
  outputError(error);
2596
2588
  process.exit(1);
package/dist/index.mjs CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  getBalance,
12
12
  getFourMemeInfo,
13
13
  getHistory,
14
+ getPolicyConfigGuidance,
14
15
  getPolicySummary,
15
16
  getPortfolio,
16
17
  getPrice,
@@ -25,9 +26,8 @@ import {
25
26
  toErrorPayload,
26
27
  transferFromVault,
27
28
  unwrapWbnb,
28
- updateRiskConfig,
29
29
  wrapBnb
30
- } from "./chunk-5GV6AGSA.mjs";
30
+ } from "./chunk-TH3ENDDM.mjs";
31
31
 
32
32
  // src/index.ts
33
33
  import { Command as Command9 } from "commander";
@@ -226,15 +226,10 @@ function registerAgentCommands(program2) {
226
226
  process.exit(1);
227
227
  }
228
228
  });
229
- const configCmd = new Command5("config").description("Configure agent risk parameters (Requires RENTER status!)").option("--tx-limit <amount>", "Max BNB per tx").option("--daily-limit <amount>", "Max BNB per day").option("--cooldown <seconds>", "Seconds between tx");
229
+ const configCmd = new Command5("config").description("View current risk parameters (modify via web console)");
230
230
  addSharedOptions(configCmd).action(async (opts) => {
231
231
  try {
232
- output(await updateRiskConfig(opts.tokenId, {
233
- txLimit: opts.txLimit,
234
- dailyLimit: opts.dailyLimit,
235
- cooldown: opts.cooldown,
236
- rpcUrl: opts.rpc
237
- }));
232
+ output(await getPolicyConfigGuidance(opts.tokenId, opts.rpc));
238
233
  } catch (error) {
239
234
  outputError(error);
240
235
  process.exit(1);
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.1";
15
+ var SKILL_VERSION = "6.0.2";
16
16
  var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
17
17
  var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
18
18
  var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
@@ -175,16 +175,11 @@ var LISTING_MANAGER_ABI = [
175
175
  }
176
176
  ];
177
177
  var SPENDING_LIMIT_ABI = [
178
- { type: "function", name: "setLimits", inputs: [{ name: "instanceId", type: "uint256" }, { name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
179
178
  { type: "function", name: "instanceLimits", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "maxPerTx", type: "uint256" }, { name: "maxPerDay", type: "uint256" }, { name: "maxSlippageBps", type: "uint256" }], stateMutability: "view" },
180
179
  { type: "function", name: "tokenRestrictionEnabled", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "bool" }], stateMutability: "view" },
181
- { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" },
182
- { type: "function", name: "addToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
183
- { type: "function", name: "removeToken", inputs: [{ name: "instanceId", type: "uint256" }, { name: "token", type: "address" }], outputs: [], stateMutability: "nonpayable" },
184
- { type: "function", name: "setTokenRestriction", inputs: [{ name: "instanceId", type: "uint256" }, { name: "enabled", type: "bool" }], outputs: [], stateMutability: "nonpayable" }
180
+ { type: "function", name: "getTokenList", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "address[]" }], stateMutability: "view" }
185
181
  ];
186
182
  var COOLDOWN_ABI = [
187
- { type: "function", name: "setCooldown", inputs: [{ name: "instanceId", type: "uint256" }, { name: "seconds_", type: "uint256" }], outputs: [], stateMutability: "nonpayable" },
188
183
  { type: "function", name: "cooldownSeconds", inputs: [{ name: "instanceId", type: "uint256" }], outputs: [{ name: "", type: "uint256" }], stateMutability: "view" }
189
184
  ];
190
185
  var FOUR_MEME_HELPER_ABI = [
@@ -824,14 +819,6 @@ function createClients(rpcUrl) {
824
819
  });
825
820
  return { account, publicClient, policyClient, rpc: writeRpc };
826
821
  }
827
- function createWallet(rpcUrl) {
828
- const privateKey = process.env.RUNNER_PRIVATE_KEY;
829
- if (!privateKey) throw new Error("RUNNER_PRIVATE_KEY environment variable is required");
830
- const rpc = rpcUrl || DEFAULT_RPC;
831
- const account = (0, import_accounts2.privateKeyToAccount)(toHex(privateKey));
832
- const walletClient = (0, import_viem2.createWalletClient)({ account, chain: import_chains2.bsc, transport: (0, import_viem2.http)(rpc) });
833
- return { account, walletClient };
834
- }
835
822
  function createReadOnlyClient(rpcUrl) {
836
823
  const rpc = rpcUrl || process.env.SHLL_RPC || DEFAULT_RPC;
837
824
  return (0, import_viem2.createPublicClient)({
@@ -991,10 +978,14 @@ function checkActionRecipientSafety(action, vault) {
991
978
  function policyRejectionHelp(reason, tokenId) {
992
979
  const consoleUrl = agentConsoleUrl(tokenId);
993
980
  const r = reason ?? "";
981
+ if (r.includes("Function not allowed"))
982
+ return { explanation: "The contract method selector is not enabled by the active DeFi policy configuration.", action: "Enable the required protocol pack or selector in Console > Safety, or use a supported transaction path.", consoleUrl };
994
983
  if (r.includes("Approve spender not allowed"))
995
984
  return { explanation: "The DEX router address is not in the approved spender whitelist.", action: "Contact the Agent owner to approve this router, or use a different DEX.", consoleUrl };
996
985
  if (r.includes("Target not allowed"))
997
986
  return { explanation: "The contract address is not in the DeFi target whitelist.", action: "Enable the corresponding DeFi Pack in Console > Safety, or contact the Agent owner.", consoleUrl };
987
+ if (r.includes("Receiver must be vault"))
988
+ return { explanation: "Swap output recipient must be the agent vault address enforced by ReceiverGuard.", action: "Retry with recipient/to set to the vault address, or use a supported flow that routes proceeds back to the vault.", consoleUrl };
998
989
  if (r.includes("Token not in whitelist"))
999
990
  return { explanation: "Token restriction is ON and this token is not whitelisted.", action: `Add the token to the whitelist or disable token restriction at: ${consoleUrl}`, consoleUrl };
1000
991
  if (r.includes("Exceeds per-tx limit"))
@@ -1242,13 +1233,18 @@ function ensureRecipientSafe(result) {
1242
1233
  }
1243
1234
  }
1244
1235
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1245
- for (const action of actions) {
1236
+ for (const [index, action] of actions.entries()) {
1246
1237
  const sim = await policyClient.validate(tokenId, action);
1247
1238
  if (!sim.ok) {
1248
1239
  throw new SkillError(
1249
1240
  "POLICY_REJECTED",
1250
1241
  "Policy rejected transaction",
1251
1242
  {
1243
+ failedActionIndex: index,
1244
+ failedActionTarget: action.target,
1245
+ failedActionSelector: getActionSelector(action),
1246
+ failedActionFunction: getActionFunctionName(action),
1247
+ failedActionValue: action.value.toString(),
1252
1248
  reason: sim.reason,
1253
1249
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1254
1250
  },
@@ -1268,6 +1264,37 @@ async function executeActions(policyClient, tokenId, actions) {
1268
1264
  const result = await policyClient.executeBatch(tokenId, actions, true);
1269
1265
  return { hash: result.hash };
1270
1266
  }
1267
+ function getActionSelector(action) {
1268
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1269
+ }
1270
+ function getActionFunctionName(action) {
1271
+ if (action.data === "0x") {
1272
+ return "nativeTransfer";
1273
+ }
1274
+ const candidates = [
1275
+ ERC20_ABI,
1276
+ WBNB_ABI,
1277
+ VTOKEN_ABI,
1278
+ VBNB_MINT_ABI,
1279
+ SWAP_EXACT_ETH_ABI,
1280
+ SWAP_EXACT_TOKENS_ABI,
1281
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1282
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1283
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1284
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1285
+ V3_EXACT_INPUT_SINGLE_ABI,
1286
+ V3_EXACT_INPUT_ABI,
1287
+ FOUR_MEME_V1_ABI,
1288
+ FOUR_MEME_V2_ABI
1289
+ ];
1290
+ for (const abi of candidates) {
1291
+ const decoded = tryDecodeCalldata(abi, action.data);
1292
+ if (decoded?.functionName) {
1293
+ return decoded.functionName;
1294
+ }
1295
+ }
1296
+ return "unknown";
1297
+ }
1271
1298
 
1272
1299
  // src/services/info.ts
1273
1300
  var import_viem5 = require("viem");
@@ -1709,25 +1736,6 @@ async function executeSwap(input) {
1709
1736
  args: [minOut, path, vault, deadline]
1710
1737
  })
1711
1738
  });
1712
- } else if (isNativeOut) {
1713
- actions.push({
1714
- target: tokenIn.address,
1715
- value: 0n,
1716
- data: (0, import_viem7.encodeFunctionData)({
1717
- abi: ERC20_ABI,
1718
- functionName: "approve",
1719
- args: [v2Router, amountIn]
1720
- })
1721
- });
1722
- actions.push({
1723
- target: v2Router,
1724
- value: 0n,
1725
- data: (0, import_viem7.encodeFunctionData)({
1726
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1727
- functionName: "swapExactTokensForETH",
1728
- args: [amountIn, minOut, path, vault, deadline]
1729
- })
1730
- });
1731
1739
  } else {
1732
1740
  actions.push({
1733
1741
  target: tokenIn.address,
@@ -1742,8 +1750,8 @@ async function executeSwap(input) {
1742
1750
  target: v2Router,
1743
1751
  value: 0n,
1744
1752
  data: (0, import_viem7.encodeFunctionData)({
1745
- abi: SWAP_EXACT_TOKENS_ABI,
1746
- functionName: "swapExactTokensForTokens",
1753
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1754
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1747
1755
  args: [amountIn, minOut, path, vault, deadline]
1748
1756
  })
1749
1757
  });
@@ -2421,59 +2429,48 @@ async function getHistory(tokenIdRaw, limit) {
2421
2429
  recentPolicyRejections: rejections.length
2422
2430
  };
2423
2431
  }
2424
- async function updateRiskConfig(tokenIdRaw, options) {
2425
- if (!options.txLimit && !options.dailyLimit && !options.cooldown) {
2426
- throw new SkillError("INVALID_INPUT", "Must specify at least one policy config option");
2427
- }
2432
+ async function getPolicyConfigGuidance(tokenIdRaw, rpcUrl) {
2428
2433
  const tokenId = parseTokenId(tokenIdRaw);
2429
- const { publicClient, policyClient, rpc } = createClients(options.rpcUrl);
2430
- await ensureAccess(tokenId, rpc, publicClient);
2431
- const { walletClient } = createWallet(rpc);
2434
+ const { publicClient, policyClient } = createClients(rpcUrl);
2432
2435
  const policies = await policyClient.getPolicies(tokenId);
2433
- const results = [];
2434
- if (options.txLimit || options.dailyLimit) {
2435
- const spendingPolicy = policies.find((policy) => policy.policyTypeName === "spending_limit");
2436
- if (!spendingPolicy) {
2437
- throw new SkillError("NOT_FOUND", "No SpendingLimitPolicy found");
2436
+ const consoleUrl = agentConsoleUrl(tokenId);
2437
+ const currentConfig = {};
2438
+ const spendingPolicy = policies.find((p) => p.policyTypeName === "spending_limit");
2439
+ if (spendingPolicy) {
2440
+ try {
2441
+ const [maxPerTx, maxPerDay, maxSlippageBps] = await publicClient.readContract({
2442
+ address: spendingPolicy.address,
2443
+ abi: SPENDING_LIMIT_ABI,
2444
+ functionName: "instanceLimits",
2445
+ args: [tokenId]
2446
+ });
2447
+ currentConfig.spendingLimit = {
2448
+ maxPerTx: (Number(maxPerTx) / 1e18).toFixed(4) + " BNB",
2449
+ maxPerDay: (Number(maxPerDay) / 1e18).toFixed(4) + " BNB",
2450
+ slippageBps: maxSlippageBps.toString()
2451
+ };
2452
+ } catch {
2438
2453
  }
2439
- const current = await publicClient.readContract({
2440
- address: spendingPolicy.address,
2441
- abi: SPENDING_LIMIT_ABI,
2442
- functionName: "instanceLimits",
2443
- args: [tokenId]
2444
- });
2445
- const [curMaxPerTx, curMaxPerDay, curSlippage] = current;
2446
- const hash = await walletClient.writeContract({
2447
- address: spendingPolicy.address,
2448
- abi: SPENDING_LIMIT_ABI,
2449
- functionName: "setLimits",
2450
- args: [
2451
- tokenId,
2452
- options.txLimit ? parseAmount(options.txLimit, 18) : curMaxPerTx,
2453
- options.dailyLimit ? parseAmount(options.dailyLimit, 18) : curMaxPerDay,
2454
- curSlippage
2455
- ]
2456
- });
2457
- await publicClient.waitForTransactionReceipt({ hash });
2458
- results.push(`SpendingLimit updated: ${hash}`);
2459
2454
  }
2460
- if (options.cooldown) {
2461
- const cooldownPolicy = policies.find((policy) => policy.policyTypeName === "cooldown");
2462
- if (!cooldownPolicy) {
2463
- throw new SkillError("NOT_FOUND", "No CooldownPolicy found");
2455
+ const cooldownPolicy = policies.find((p) => p.policyTypeName === "cooldown");
2456
+ if (cooldownPolicy) {
2457
+ try {
2458
+ const cooldown = await publicClient.readContract({
2459
+ address: cooldownPolicy.address,
2460
+ abi: COOLDOWN_ABI,
2461
+ functionName: "cooldownSeconds",
2462
+ args: [tokenId]
2463
+ });
2464
+ currentConfig.cooldown = { seconds: Number(cooldown) };
2465
+ } catch {
2464
2466
  }
2465
- const hash = await walletClient.writeContract({
2466
- address: cooldownPolicy.address,
2467
- abi: COOLDOWN_ABI,
2468
- functionName: "setCooldown",
2469
- args: [tokenId, BigInt(options.cooldown)]
2470
- });
2471
- await publicClient.waitForTransactionReceipt({ hash });
2472
- results.push(`Cooldown updated: ${hash}`);
2473
2467
  }
2474
2468
  return {
2475
- status: "success",
2476
- details: results
2469
+ status: "read_only",
2470
+ tokenId: tokenIdRaw,
2471
+ currentConfig,
2472
+ message: "Policy modification via Skills is disabled. Please use the web console to adjust your security settings.",
2473
+ consoleUrl
2477
2474
  };
2478
2475
  }
2479
2476
  function dedupeStrings(values) {
@@ -2750,20 +2747,13 @@ function registerAgentTools(server2) {
2750
2747
  );
2751
2748
  server2.tool(
2752
2749
  "config",
2753
- "Configure risk parameters",
2750
+ "View current risk parameters and get a link to the web console for modifications",
2754
2751
  {
2755
- token_id: CommonSchemas.tokenId.describe("Agent Token ID"),
2756
- tx_limit: import_zod5.z.string().optional().describe("Max BNB per tx"),
2757
- daily_limit: import_zod5.z.string().optional().describe("Max BNB per day"),
2758
- cooldown: import_zod5.z.string().optional().describe("Seconds between tx")
2752
+ token_id: CommonSchemas.tokenId.describe("Agent Token ID")
2759
2753
  },
2760
- async ({ token_id, tx_limit, daily_limit, cooldown }) => {
2754
+ async ({ token_id }) => {
2761
2755
  try {
2762
- return asToolResult5(await updateRiskConfig(token_id, {
2763
- txLimit: tx_limit,
2764
- dailyLimit: daily_limit,
2765
- cooldown
2766
- }));
2756
+ return asToolResult5(await getPolicyConfigGuidance(token_id));
2767
2757
  } catch (error) {
2768
2758
  return formatMcpError(error);
2769
2759
  }
package/dist/mcp.mjs CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  getBalance,
12
12
  getFourMemeInfo,
13
13
  getHistory,
14
+ getPolicyConfigGuidance,
14
15
  getPolicySummary,
15
16
  getPortfolio,
16
17
  getPrice,
@@ -24,9 +25,8 @@ import {
24
25
  sellFourMeme,
25
26
  transferFromVault,
26
27
  unwrapWbnb,
27
- updateRiskConfig,
28
28
  wrapBnb
29
- } from "./chunk-5GV6AGSA.mjs";
29
+ } from "./chunk-TH3ENDDM.mjs";
30
30
 
31
31
  // src/mcp.ts
32
32
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -303,20 +303,13 @@ function registerAgentTools(server2) {
303
303
  );
304
304
  server2.tool(
305
305
  "config",
306
- "Configure risk parameters",
306
+ "View current risk parameters and get a link to the web console for modifications",
307
307
  {
308
- token_id: CommonSchemas.tokenId.describe("Agent Token ID"),
309
- tx_limit: z4.string().optional().describe("Max BNB per tx"),
310
- daily_limit: z4.string().optional().describe("Max BNB per day"),
311
- cooldown: z4.string().optional().describe("Seconds between tx")
308
+ token_id: CommonSchemas.tokenId.describe("Agent Token ID")
312
309
  },
313
- async ({ token_id, tx_limit, daily_limit, cooldown }) => {
310
+ async ({ token_id }) => {
314
311
  try {
315
- return asToolResult5(await updateRiskConfig(token_id, {
316
- txLimit: tx_limit,
317
- dailyLimit: daily_limit,
318
- cooldown
319
- }));
312
+ return asToolResult5(await getPolicyConfigGuidance(token_id));
320
313
  } catch (error) {
321
314
  return formatMcpError(error);
322
315
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shll-skills",
3
- "version": "6.0.1",
3
+ "version": "6.0.3",
4
4
  "description": "SHLL DeFi Agent - CLI + MCP Server for BSC",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -35,4 +35,4 @@
35
35
  "SKILL.md"
36
36
  ],
37
37
  "license": "MIT"
38
- }
38
+ }