shll-skills 6.0.2 → 6.0.4

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.2
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.2)
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.
@@ -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.2";
10
- var BINDINGS_UPDATED_AT = "2026-03-06";
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";
@@ -977,10 +977,14 @@ function checkActionRecipientSafety(action, vault) {
977
977
  function policyRejectionHelp(reason, tokenId) {
978
978
  const consoleUrl = agentConsoleUrl(tokenId);
979
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 };
980
982
  if (r.includes("Approve spender not allowed"))
981
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 };
982
984
  if (r.includes("Target not allowed"))
983
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 };
984
988
  if (r.includes("Token not in whitelist"))
985
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 };
986
990
  if (r.includes("Exceeds per-tx limit"))
@@ -1228,13 +1232,21 @@ function ensureRecipientSafe(result) {
1228
1232
  }
1229
1233
  }
1230
1234
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1231
- for (const action of actions) {
1235
+ for (const [index, action] of actions.entries()) {
1232
1236
  const sim = await policyClient.validate(tokenId, action);
1233
1237
  if (!sim.ok) {
1234
1238
  throw new SkillError(
1235
1239
  "POLICY_REJECTED",
1236
1240
  "Policy rejected transaction",
1237
1241
  {
1242
+ enforcement: "on-chain",
1243
+ policyGuardContract: DEFAULT_GUARD,
1244
+ verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
1245
+ failedActionIndex: index,
1246
+ failedActionTarget: action.target,
1247
+ failedActionSelector: getActionSelector(action),
1248
+ failedActionFunction: getActionFunctionName(action),
1249
+ failedActionValue: action.value.toString(),
1238
1250
  reason: sim.reason,
1239
1251
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1240
1252
  },
@@ -1254,6 +1266,37 @@ async function executeActions(policyClient, tokenId, actions) {
1254
1266
  const result = await policyClient.executeBatch(tokenId, actions, true);
1255
1267
  return { hash: result.hash };
1256
1268
  }
1269
+ function getActionSelector(action) {
1270
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1271
+ }
1272
+ function getActionFunctionName(action) {
1273
+ if (action.data === "0x") {
1274
+ return "nativeTransfer";
1275
+ }
1276
+ const candidates = [
1277
+ ERC20_ABI,
1278
+ WBNB_ABI,
1279
+ VTOKEN_ABI,
1280
+ VBNB_MINT_ABI,
1281
+ SWAP_EXACT_ETH_ABI,
1282
+ SWAP_EXACT_TOKENS_ABI,
1283
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1284
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1285
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1286
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1287
+ V3_EXACT_INPUT_SINGLE_ABI,
1288
+ V3_EXACT_INPUT_ABI,
1289
+ FOUR_MEME_V1_ABI,
1290
+ FOUR_MEME_V2_ABI
1291
+ ];
1292
+ for (const abi of candidates) {
1293
+ const decoded = tryDecodeCalldata(abi, action.data);
1294
+ if (decoded?.functionName) {
1295
+ return decoded.functionName;
1296
+ }
1297
+ }
1298
+ return "unknown";
1299
+ }
1257
1300
 
1258
1301
  // src/services/info.ts
1259
1302
  var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
@@ -1692,25 +1735,6 @@ async function executeSwap(input) {
1692
1735
  args: [minOut, path, vault, deadline]
1693
1736
  })
1694
1737
  });
1695
- } else if (isNativeOut) {
1696
- actions.push({
1697
- target: tokenIn.address,
1698
- value: 0n,
1699
- data: encodeFunctionData2({
1700
- abi: ERC20_ABI,
1701
- functionName: "approve",
1702
- args: [v2Router, amountIn]
1703
- })
1704
- });
1705
- actions.push({
1706
- target: v2Router,
1707
- value: 0n,
1708
- data: encodeFunctionData2({
1709
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1710
- functionName: "swapExactTokensForETH",
1711
- args: [amountIn, minOut, path, vault, deadline]
1712
- })
1713
- });
1714
1738
  } else {
1715
1739
  actions.push({
1716
1740
  target: tokenIn.address,
@@ -1725,8 +1749,8 @@ async function executeSwap(input) {
1725
1749
  target: v2Router,
1726
1750
  value: 0n,
1727
1751
  data: encodeFunctionData2({
1728
- abi: SWAP_EXACT_TOKENS_ABI,
1729
- functionName: "swapExactTokensForTokens",
1752
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1753
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1730
1754
  args: [amountIn, minOut, path, vault, deadline]
1731
1755
  })
1732
1756
  });
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.2";
16
- var BINDINGS_UPDATED_AT = "2026-03-06";
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";
@@ -979,10 +979,14 @@ function checkActionRecipientSafety(action, vault) {
979
979
  function policyRejectionHelp(reason, tokenId) {
980
980
  const consoleUrl = agentConsoleUrl(tokenId);
981
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 };
982
984
  if (r.includes("Approve spender not allowed"))
983
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 };
984
986
  if (r.includes("Target not allowed"))
985
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 };
986
990
  if (r.includes("Token not in whitelist"))
987
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 };
988
992
  if (r.includes("Exceeds per-tx limit"))
@@ -1249,13 +1253,21 @@ function ensureRecipientSafe(result) {
1249
1253
  }
1250
1254
  }
1251
1255
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1252
- for (const action of actions) {
1256
+ for (const [index, action] of actions.entries()) {
1253
1257
  const sim = await policyClient.validate(tokenId, action);
1254
1258
  if (!sim.ok) {
1255
1259
  throw new SkillError(
1256
1260
  "POLICY_REJECTED",
1257
1261
  "Policy rejected transaction",
1258
1262
  {
1263
+ enforcement: "on-chain",
1264
+ policyGuardContract: DEFAULT_GUARD,
1265
+ verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
1266
+ failedActionIndex: index,
1267
+ failedActionTarget: action.target,
1268
+ failedActionSelector: getActionSelector(action),
1269
+ failedActionFunction: getActionFunctionName(action),
1270
+ failedActionValue: action.value.toString(),
1259
1271
  reason: sim.reason,
1260
1272
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1261
1273
  },
@@ -1275,6 +1287,37 @@ async function executeActions(policyClient, tokenId, actions) {
1275
1287
  const result = await policyClient.executeBatch(tokenId, actions, true);
1276
1288
  return { hash: result.hash };
1277
1289
  }
1290
+ function getActionSelector(action) {
1291
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1292
+ }
1293
+ function getActionFunctionName(action) {
1294
+ if (action.data === "0x") {
1295
+ return "nativeTransfer";
1296
+ }
1297
+ const candidates = [
1298
+ ERC20_ABI,
1299
+ WBNB_ABI,
1300
+ VTOKEN_ABI,
1301
+ VBNB_MINT_ABI,
1302
+ SWAP_EXACT_ETH_ABI,
1303
+ SWAP_EXACT_TOKENS_ABI,
1304
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1305
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1306
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1307
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1308
+ V3_EXACT_INPUT_SINGLE_ABI,
1309
+ V3_EXACT_INPUT_ABI,
1310
+ FOUR_MEME_V1_ABI,
1311
+ FOUR_MEME_V2_ABI
1312
+ ];
1313
+ for (const abi of candidates) {
1314
+ const decoded = tryDecodeCalldata(abi, action.data);
1315
+ if (decoded?.functionName) {
1316
+ return decoded.functionName;
1317
+ }
1318
+ }
1319
+ return "unknown";
1320
+ }
1278
1321
 
1279
1322
  // src/services/info.ts
1280
1323
  var import_viem5 = require("viem");
@@ -1716,25 +1759,6 @@ async function executeSwap(input) {
1716
1759
  args: [minOut, path, vault, deadline]
1717
1760
  })
1718
1761
  });
1719
- } else if (isNativeOut) {
1720
- actions.push({
1721
- target: tokenIn.address,
1722
- value: 0n,
1723
- data: (0, import_viem7.encodeFunctionData)({
1724
- abi: ERC20_ABI,
1725
- functionName: "approve",
1726
- args: [v2Router, amountIn]
1727
- })
1728
- });
1729
- actions.push({
1730
- target: v2Router,
1731
- value: 0n,
1732
- data: (0, import_viem7.encodeFunctionData)({
1733
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1734
- functionName: "swapExactTokensForETH",
1735
- args: [amountIn, minOut, path, vault, deadline]
1736
- })
1737
- });
1738
1762
  } else {
1739
1763
  actions.push({
1740
1764
  target: tokenIn.address,
@@ -1749,8 +1773,8 @@ async function executeSwap(input) {
1749
1773
  target: v2Router,
1750
1774
  value: 0n,
1751
1775
  data: (0, import_viem7.encodeFunctionData)({
1752
- abi: SWAP_EXACT_TOKENS_ABI,
1753
- functionName: "swapExactTokensForTokens",
1776
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1777
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1754
1778
  args: [amountIn, minOut, path, vault, deadline]
1755
1779
  })
1756
1780
  });
package/dist/index.mjs CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  transferFromVault,
28
28
  unwrapWbnb,
29
29
  wrapBnb
30
- } from "./chunk-MPUPO5EJ.mjs";
30
+ } from "./chunk-IKVUDAK6.mjs";
31
31
 
32
32
  // src/index.ts
33
33
  import { Command as Command9 } from "commander";
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.2";
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";
@@ -978,10 +978,14 @@ function checkActionRecipientSafety(action, vault) {
978
978
  function policyRejectionHelp(reason, tokenId) {
979
979
  const consoleUrl = agentConsoleUrl(tokenId);
980
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 };
981
983
  if (r.includes("Approve spender not allowed"))
982
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 };
983
985
  if (r.includes("Target not allowed"))
984
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 };
985
989
  if (r.includes("Token not in whitelist"))
986
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 };
987
991
  if (r.includes("Exceeds per-tx limit"))
@@ -1229,13 +1233,21 @@ function ensureRecipientSafe(result) {
1229
1233
  }
1230
1234
  }
1231
1235
  async function validateActionsOrThrow(policyClient, tokenId, actions) {
1232
- for (const action of actions) {
1236
+ for (const [index, action] of actions.entries()) {
1233
1237
  const sim = await policyClient.validate(tokenId, action);
1234
1238
  if (!sim.ok) {
1235
1239
  throw new SkillError(
1236
1240
  "POLICY_REJECTED",
1237
1241
  "Policy rejected transaction",
1238
1242
  {
1243
+ enforcement: "on-chain",
1244
+ policyGuardContract: DEFAULT_GUARD,
1245
+ verifyOnChain: `https://bscscan.com/address/${DEFAULT_GUARD}`,
1246
+ failedActionIndex: index,
1247
+ failedActionTarget: action.target,
1248
+ failedActionSelector: getActionSelector(action),
1249
+ failedActionFunction: getActionFunctionName(action),
1250
+ failedActionValue: action.value.toString(),
1239
1251
  reason: sim.reason,
1240
1252
  ...policyRejectionHelp(sim.reason, tokenId.toString())
1241
1253
  },
@@ -1255,6 +1267,37 @@ async function executeActions(policyClient, tokenId, actions) {
1255
1267
  const result = await policyClient.executeBatch(tokenId, actions, true);
1256
1268
  return { hash: result.hash };
1257
1269
  }
1270
+ function getActionSelector(action) {
1271
+ return action.data && action.data.length >= 10 ? action.data.slice(0, 10) : "0x";
1272
+ }
1273
+ function getActionFunctionName(action) {
1274
+ if (action.data === "0x") {
1275
+ return "nativeTransfer";
1276
+ }
1277
+ const candidates = [
1278
+ ERC20_ABI,
1279
+ WBNB_ABI,
1280
+ VTOKEN_ABI,
1281
+ VBNB_MINT_ABI,
1282
+ SWAP_EXACT_ETH_ABI,
1283
+ SWAP_EXACT_TOKENS_ABI,
1284
+ SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1285
+ SWAP_EXACT_ETH_FOR_TOKENS_FEE_ABI,
1286
+ SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1287
+ SWAP_EXACT_TOKENS_FOR_ETH_FEE_ABI,
1288
+ V3_EXACT_INPUT_SINGLE_ABI,
1289
+ V3_EXACT_INPUT_ABI,
1290
+ FOUR_MEME_V1_ABI,
1291
+ FOUR_MEME_V2_ABI
1292
+ ];
1293
+ for (const abi of candidates) {
1294
+ const decoded = tryDecodeCalldata(abi, action.data);
1295
+ if (decoded?.functionName) {
1296
+ return decoded.functionName;
1297
+ }
1298
+ }
1299
+ return "unknown";
1300
+ }
1258
1301
 
1259
1302
  // src/services/info.ts
1260
1303
  var import_viem5 = require("viem");
@@ -1696,25 +1739,6 @@ async function executeSwap(input) {
1696
1739
  args: [minOut, path, vault, deadline]
1697
1740
  })
1698
1741
  });
1699
- } else if (isNativeOut) {
1700
- actions.push({
1701
- target: tokenIn.address,
1702
- value: 0n,
1703
- data: (0, import_viem7.encodeFunctionData)({
1704
- abi: ERC20_ABI,
1705
- functionName: "approve",
1706
- args: [v2Router, amountIn]
1707
- })
1708
- });
1709
- actions.push({
1710
- target: v2Router,
1711
- value: 0n,
1712
- data: (0, import_viem7.encodeFunctionData)({
1713
- abi: SWAP_EXACT_TOKENS_FOR_ETH_ABI,
1714
- functionName: "swapExactTokensForETH",
1715
- args: [amountIn, minOut, path, vault, deadline]
1716
- })
1717
- });
1718
1742
  } else {
1719
1743
  actions.push({
1720
1744
  target: tokenIn.address,
@@ -1729,8 +1753,8 @@ async function executeSwap(input) {
1729
1753
  target: v2Router,
1730
1754
  value: 0n,
1731
1755
  data: (0, import_viem7.encodeFunctionData)({
1732
- abi: SWAP_EXACT_TOKENS_ABI,
1733
- functionName: "swapExactTokensForTokens",
1756
+ abi: SWAP_EXACT_TOKENS_FOR_TOKENS_FEE_ABI,
1757
+ functionName: "swapExactTokensForTokensSupportingFeeOnTransferTokens",
1734
1758
  args: [amountIn, minOut, path, vault, deadline]
1735
1759
  })
1736
1760
  });
package/dist/mcp.mjs CHANGED
@@ -26,7 +26,7 @@ import {
26
26
  transferFromVault,
27
27
  unwrapWbnb,
28
28
  wrapBnb
29
- } from "./chunk-MPUPO5EJ.mjs";
29
+ } from "./chunk-IKVUDAK6.mjs";
30
30
 
31
31
  // src/mcp.ts
32
32
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shll-skills",
3
- "version": "6.0.2",
3
+ "version": "6.0.4",
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
+ }