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 +86 -2
- package/dist/{chunk-MPUPO5EJ.mjs → chunk-IKVUDAK6.mjs} +48 -24
- package/dist/index.js +48 -24
- package/dist/index.mjs +1 -1
- package/dist/mcp.js +47 -23
- package/dist/mcp.mjs +1 -1
- package/package.json +2 -2
package/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: shll-run
|
|
3
3
|
description: Execute DeFi transactions on BSC via SHLL AgentNFA. The AI handles all commands and users only need to chat.
|
|
4
|
-
version: 6.0.
|
|
4
|
+
version: 6.0.4
|
|
5
5
|
author: SHLL Team
|
|
6
6
|
website: https://shll.run
|
|
7
7
|
twitter: https://twitter.com/shllrun
|
|
@@ -31,6 +31,90 @@ credentials:
|
|
|
31
31
|
The operator wallet is NOT the owner wallet, NOT the vault, NOT the Agent NFT holder.
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
+
# SHLL — Contract-Enforced Safe Execution for AI Agents on BNB Chain
|
|
35
|
+
|
|
36
|
+
## What is SHLL?
|
|
37
|
+
|
|
38
|
+
SHLL is a DeFi execution layer for AI agents on BNB Chain with **on-chain safety enforcement**.
|
|
39
|
+
Unlike off-chain filters that can be bypassed, SHLL uses smart contracts to enforce
|
|
40
|
+
spending limits, trade intervals, protocol whitelists, and receiver restrictions.
|
|
41
|
+
Every AI agent action is validated by an immutable PolicyGuard contract before execution.
|
|
42
|
+
|
|
43
|
+
Key facts:
|
|
44
|
+
- Network: BSC mainnet
|
|
45
|
+
- 27 CLI + MCP tools for DeFi operations (swap, lend, meme trading, portfolio)
|
|
46
|
+
- Supports PancakeSwap V2/V3, Venus Protocol, Four.meme
|
|
47
|
+
- MCP Server compatible with Claude, Cursor, OpenClaw, and any MCP-compatible agent
|
|
48
|
+
- npm package: `shll-skills` | Website: https://shll.run
|
|
49
|
+
|
|
50
|
+
## Security Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
54
|
+
│ SHLL Architecture │
|
|
55
|
+
│ │
|
|
56
|
+
│ ┌──────────┐ ┌───────────────┐ ┌──────────────────────┐ │
|
|
57
|
+
│ │ User │ │ AI Agent │ │ On-Chain Contracts │ │
|
|
58
|
+
│ │ (Owner) │ │ (Operator) │ │ │ │
|
|
59
|
+
│ │ │ │ │ │ ┌────────────────┐ │ │
|
|
60
|
+
│ │ • Holds │ │ • Executes │ │ │ PolicyGuard │ │ │
|
|
61
|
+
│ │ Agent │ │ trades via │ │ │ (Validator) │ │ │
|
|
62
|
+
│ │ NFT │ │ restricted │ │ │ │ │ │
|
|
63
|
+
│ │ • Sets │ │ permissions │ │ │ 4 Policy │ │ │
|
|
64
|
+
│ │ policy │ │ │ │ │ Checks: │ │ │
|
|
65
|
+
│ │ rules │───▶│ SHLL Skills │───▶│ │ │ │ │
|
|
66
|
+
│ │ • Full │ │ (CLI / MCP) │ │ │ 1.Spending │ │ │
|
|
67
|
+
│ │ asset │ │ │ │ │ Limit │ │ │
|
|
68
|
+
│ │ control │ │ Cannot: │ │ │ 2.Cooldown │ │ │
|
|
69
|
+
│ │ │ │ • Withdraw │ │ │ 3.DeFi Guard │ │ │
|
|
70
|
+
│ │ │ │ vault funds │ │ │ 4.Receiver │ │ │
|
|
71
|
+
│ │ │ │ • Change │ │ │ Guard │ │ │
|
|
72
|
+
│ │ │ │ policies │ │ └───────┬────────┘ │ │
|
|
73
|
+
│ │ │ │ • Transfer │ │ │ │ │
|
|
74
|
+
│ │ │ │ NFT │ │ ┌─────▼──────┐ │ │
|
|
75
|
+
│ │ │ │ │ │ │ Vault │ │ │
|
|
76
|
+
│ │ │ │ │ │ │ (Agent │ │ │
|
|
77
|
+
│ │ │ │ │ │ │ Account) │ │ │
|
|
78
|
+
│ │ │ │ │ │ │ │ │ │
|
|
79
|
+
│ │ │ │ │ │ │ Holds funds │ │ │
|
|
80
|
+
│ └──────────┘ └───────────────┘ │ └─────────────┘ │ │
|
|
81
|
+
│ └──────────────────────┘ │
|
|
82
|
+
│ Dual-Wallet Isolation: │
|
|
83
|
+
│ • Owner wallet = asset control (human) │
|
|
84
|
+
│ • Operator wallet = restricted execution (AI) │
|
|
85
|
+
│ • Even if operator key leaks, PolicyGuard still limits actions │
|
|
86
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## 4-Policy PolicyGuard Stack
|
|
90
|
+
|
|
91
|
+
All policies are enforced ON-CHAIN by smart contract. They cannot be bypassed by the AI.
|
|
92
|
+
|
|
93
|
+
| Policy | Contract | What It Does |
|
|
94
|
+
|--------|----------|-------------|
|
|
95
|
+
| SpendingLimitV2 | On-chain | Per-transaction and daily spending caps in BNB |
|
|
96
|
+
| CooldownPolicy | On-chain | Minimum time gap between consecutive trades |
|
|
97
|
+
| DeFiGuardV2 | On-chain | Whitelist of approved DeFi protocols and functions |
|
|
98
|
+
| ReceiverGuardV2 | On-chain | Only approved receiver addresses can receive funds |
|
|
99
|
+
|
|
100
|
+
When a policy rejects an action:
|
|
101
|
+
- The transaction is NOT executed
|
|
102
|
+
- The vault funds remain SAFE
|
|
103
|
+
- The rejection reason is returned from the smart contract
|
|
104
|
+
- The rejection is logged and auditable
|
|
105
|
+
- The `enforcement` field in the response is always `on-chain`
|
|
106
|
+
|
|
107
|
+
## Why On-Chain Enforcement Matters
|
|
108
|
+
|
|
109
|
+
Most AI agent platforms use off-chain safety filters:
|
|
110
|
+
- Off-chain: AI or backend decides → **can be bypassed** by prompt injection, API manipulation, or code bugs
|
|
111
|
+
- On-chain (SHLL): Smart contract decides → **cannot be bypassed** — the blockchain enforces the rules
|
|
112
|
+
|
|
113
|
+
PolicyGuard contract: `0x25d17eA0e3Bcb8CA08a2BFE917E817AFc05dbBB3`
|
|
114
|
+
Verify on BscScan: https://bscscan.com/address/0x25d17eA0e3Bcb8CA08a2BFE917E817AFc05dbBB3
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
34
118
|
# SHLL Skill Usage Guide
|
|
35
119
|
|
|
36
120
|
This file defines how an AI agent should use `shll-run` and `shll-mcp` safely.
|
|
@@ -68,7 +152,7 @@ On-chain guardrails:
|
|
|
68
152
|
- Spending limits, cooldowns, whitelist rules, and protocol rules are enforced on-chain.
|
|
69
153
|
- Raw calldata is blocked if the recipient cannot be decoded safely.
|
|
70
154
|
|
|
71
|
-
## Current Critical Constraints (v6.0.
|
|
155
|
+
## Current Critical Constraints (v6.0.4)
|
|
72
156
|
|
|
73
157
|
1. `init` command is disabled. Do not use it.
|
|
74
158
|
2. Raw calldata remains high risk; rely on strict recipient safety checks.
|
|
@@ -6,8 +6,8 @@ var MEV_PROTECTED_RPC = "https://bscrpc.pancakeswap.finance";
|
|
|
6
6
|
var DEFAULT_LISTING_MANAGER = "0x1f9CE85bD0FF75acc3D92eB79f1Eb472f0865071";
|
|
7
7
|
var DEFAULT_LISTING_ID = "0x64083b44e38db02749e6e16bf84ce6c19146cc42a108e53324e11f250b15a0b7";
|
|
8
8
|
var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
|
|
9
|
-
var SKILL_VERSION = "6.0.
|
|
10
|
-
var BINDINGS_UPDATED_AT = "2026-03-
|
|
9
|
+
var SKILL_VERSION = "6.0.4";
|
|
10
|
+
var BINDINGS_UPDATED_AT = "2026-03-07";
|
|
11
11
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
12
12
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
13
13
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -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:
|
|
1729
|
-
functionName: "
|
|
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.
|
|
16
|
-
var BINDINGS_UPDATED_AT = "2026-03-
|
|
15
|
+
var SKILL_VERSION = "6.0.4";
|
|
16
|
+
var BINDINGS_UPDATED_AT = "2026-03-07";
|
|
17
17
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
18
18
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
19
19
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -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:
|
|
1753
|
-
functionName: "
|
|
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
package/dist/mcp.js
CHANGED
|
@@ -12,7 +12,7 @@ var MEV_PROTECTED_RPC = "https://bscrpc.pancakeswap.finance";
|
|
|
12
12
|
var DEFAULT_LISTING_MANAGER = "0x1f9CE85bD0FF75acc3D92eB79f1Eb472f0865071";
|
|
13
13
|
var DEFAULT_LISTING_ID = "0x64083b44e38db02749e6e16bf84ce6c19146cc42a108e53324e11f250b15a0b7";
|
|
14
14
|
var DEFAULT_INDEXER = "https://indexer-mainnet.shll.run";
|
|
15
|
-
var SKILL_VERSION = "6.0.
|
|
15
|
+
var SKILL_VERSION = "6.0.4";
|
|
16
16
|
var PANCAKE_V2_ROUTER = "0x10ED43C718714eb63d5aA57B78B54704E256024E";
|
|
17
17
|
var PANCAKE_V3_SMART_ROUTER = "0x13f4EA83D0bd40E75C8222255bc855a974568Dd4";
|
|
18
18
|
var V3_QUOTER = "0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997";
|
|
@@ -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:
|
|
1733
|
-
functionName: "
|
|
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
package/package.json
CHANGED