@kurox_real/plugin-rugshield-402 1.0.1 → 1.0.2
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/dist/index.d.ts +2 -2
- package/dist/index.js +107 -31
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export interface ElizaAction {
|
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
10
|
* ElizaOS Action: PRE_SWAP_RISK_CHECK
|
|
11
|
-
* Automatically intercepts swap requests and calls RugShield 402
|
|
12
|
-
*
|
|
11
|
+
* Automatically intercepts swap requests and calls RugShield 402 (Base or Solana)
|
|
12
|
+
* using @x402/fetch auto-signing when X402_PRIVATE_KEY is available, or free preview otherwise.
|
|
13
13
|
*/
|
|
14
14
|
export declare const preSwapRiskCheckAction: ElizaAction;
|
|
15
15
|
export declare const rugshieldPlugin: {
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,55 @@
|
|
|
1
|
+
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
|
|
2
|
+
import { ExactEvmScheme } from "@x402/evm/exact/client";
|
|
3
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
4
|
+
const EXPECTED_MERCHANT = "0x80e0ae84679b7f11be171daadd492fbecf628cd6";
|
|
5
|
+
const BASE_USDC = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
|
|
6
|
+
const MAX_PER_CALL_MICRO_USDC = 50000n;
|
|
7
|
+
function readSetting(runtime, keys) {
|
|
8
|
+
for (const key of keys) {
|
|
9
|
+
const rt = typeof runtime?.getSetting === "function" ? runtime.getSetting(key) : undefined;
|
|
10
|
+
if (typeof rt === "string" && rt.trim())
|
|
11
|
+
return rt.trim();
|
|
12
|
+
const env = typeof process !== "undefined" ? process.env?.[key] : undefined;
|
|
13
|
+
if (typeof env === "string" && env.trim())
|
|
14
|
+
return env.trim();
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
function resolvePrivateKey(runtime, explicitKey) {
|
|
19
|
+
const candidates = [
|
|
20
|
+
explicitKey,
|
|
21
|
+
readSetting(runtime, ["X402_PRIVATE_KEY", "RUGSHIELD_PRIVATE_KEY", "EVM_PRIVATE_KEY", "BASE_PRIVATE_KEY"]),
|
|
22
|
+
];
|
|
23
|
+
for (const raw of candidates) {
|
|
24
|
+
if (typeof raw !== "string")
|
|
25
|
+
continue;
|
|
26
|
+
const cleaned = raw.trim().replace(/^0x/i, "");
|
|
27
|
+
if (/^[a-fA-F0-9]{64}$/.test(cleaned))
|
|
28
|
+
return `0x${cleaned}`;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
function createPayingFetch(privateKey, baseFetch = fetch) {
|
|
33
|
+
const account = privateKeyToAccount(privateKey);
|
|
34
|
+
const client = new x402Client();
|
|
35
|
+
client.register("eip155:8453", new ExactEvmScheme(account));
|
|
36
|
+
client.onBeforePaymentCreation(async (context) => {
|
|
37
|
+
const req = context.selectedRequirements;
|
|
38
|
+
if (req.network !== "eip155:8453")
|
|
39
|
+
throw new Error(`Rejected network ${req.network}`);
|
|
40
|
+
if (req.asset.toLowerCase() !== BASE_USDC)
|
|
41
|
+
throw new Error(`Rejected asset ${req.asset}`);
|
|
42
|
+
if (req.payTo.toLowerCase() !== EXPECTED_MERCHANT)
|
|
43
|
+
throw new Error(`Rejected payTo ${req.payTo}`);
|
|
44
|
+
if (BigInt(req.amount) > MAX_PER_CALL_MICRO_USDC)
|
|
45
|
+
throw new Error(`Rejected amount ${req.amount}`);
|
|
46
|
+
});
|
|
47
|
+
return wrapFetchWithPayment(baseFetch, client);
|
|
48
|
+
}
|
|
1
49
|
/**
|
|
2
50
|
* ElizaOS Action: PRE_SWAP_RISK_CHECK
|
|
3
|
-
* Automatically intercepts swap requests and calls RugShield 402
|
|
4
|
-
*
|
|
51
|
+
* Automatically intercepts swap requests and calls RugShield 402 (Base or Solana)
|
|
52
|
+
* using @x402/fetch auto-signing when X402_PRIVATE_KEY is available, or free preview otherwise.
|
|
5
53
|
*/
|
|
6
54
|
export const preSwapRiskCheckAction = {
|
|
7
55
|
name: "PRE_SWAP_RISK_CHECK",
|
|
@@ -10,39 +58,56 @@ export const preSwapRiskCheckAction = {
|
|
|
10
58
|
"VERIFY_TOKEN_SAFETY",
|
|
11
59
|
"SIMULATE_TOKEN_TAX",
|
|
12
60
|
"AUDIT_BASE_TOKEN",
|
|
13
|
-
"RUGSHIELD_CHECK"
|
|
61
|
+
"RUGSHIELD_CHECK",
|
|
14
62
|
],
|
|
15
|
-
description: "MANDATORY check before executing DEX swaps on Base.
|
|
63
|
+
description: "MANDATORY check before executing DEX swaps on Base or Solana. Uses @x402/fetch when X402_PRIVATE_KEY is configured ($0.010 USDC/call) to detect honeypots, buy/sell taxes, and drained liquidity.",
|
|
16
64
|
validate: async (_runtime, message) => {
|
|
17
65
|
const text = message.content?.text || "";
|
|
18
|
-
|
|
19
|
-
return /0x[a-fA-F0-9]{40}/i.test(text);
|
|
66
|
+
return /0x[a-fA-F0-9]{40}|[1-9A-HJ-NP-Za-km-z]{32,44}/i.test(text);
|
|
20
67
|
},
|
|
21
|
-
handler: async (runtime, message, _state,
|
|
68
|
+
handler: async (runtime, message, _state, options, callback) => {
|
|
22
69
|
const text = message.content?.text || "";
|
|
23
|
-
const
|
|
24
|
-
|
|
70
|
+
const evmMatch = text.match(/0x[a-fA-F0-9]{40}/i);
|
|
71
|
+
const solMatch = !evmMatch ? text.match(/\b[1-9A-HJ-NP-Za-km-z]{32,44}\b/) : null;
|
|
72
|
+
const tokenAddress = options?.tokenAddress || evmMatch?.[0] || solMatch?.[0];
|
|
73
|
+
if (!tokenAddress)
|
|
25
74
|
return false;
|
|
26
|
-
const
|
|
27
|
-
const endpoint =
|
|
75
|
+
const chain = tokenAddress.startsWith("0x") ? "base" : "solana";
|
|
76
|
+
const endpoint = (options?.hostUrl ||
|
|
77
|
+
readSetting(runtime, ["RUGSHIELD_URL"]) ||
|
|
78
|
+
"https://rugshield-402.onrender.com").replace(/\/$/, "");
|
|
79
|
+
const baseFetch = options?.customFetch ?? fetch;
|
|
80
|
+
const privateKey = resolvePrivateKey(runtime, options?.privateKey);
|
|
81
|
+
const paymentHeader = options?.paymentHeader || readSetting(runtime, ["RUGSHIELD_PAYMENT_HEADER", "PAYMENT_SIGNATURE"]);
|
|
82
|
+
const usePreview = !privateKey && !paymentHeader && options?.useFreePreview !== false;
|
|
28
83
|
try {
|
|
29
|
-
const
|
|
84
|
+
const headers = { "Content-Type": "application/json" };
|
|
85
|
+
if (paymentHeader && !privateKey && !usePreview) {
|
|
86
|
+
headers["PAYMENT-SIGNATURE"] = paymentHeader;
|
|
87
|
+
headers["X-PAYMENT"] = paymentHeader;
|
|
88
|
+
}
|
|
89
|
+
const caller = privateKey && !usePreview ? createPayingFetch(privateKey, baseFetch) : baseFetch;
|
|
90
|
+
const targetUrl = `${endpoint}${usePreview ? "/v1/scan/preview" : "/v1/scan"}`;
|
|
91
|
+
const response = await caller(targetUrl, {
|
|
30
92
|
method: "POST",
|
|
31
|
-
headers
|
|
93
|
+
headers,
|
|
32
94
|
body: JSON.stringify({
|
|
33
95
|
token_address: tokenAddress,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
96
|
+
chain,
|
|
97
|
+
chain_id: chain === "base" ? 8453 : undefined,
|
|
98
|
+
simulate_sell: true,
|
|
99
|
+
}),
|
|
37
100
|
});
|
|
38
101
|
if (response.status === 402) {
|
|
39
|
-
const challenge = await response.json();
|
|
40
|
-
const payTo = challenge?.accepts?.[0]?.payTo ||
|
|
102
|
+
const challenge = await response.json().catch(() => ({}));
|
|
103
|
+
const payTo = challenge?.accepts?.[0]?.payTo ||
|
|
104
|
+
challenge?.payTo ||
|
|
105
|
+
"0x80E0Ae84679b7f11bE171DaADd492FBECf628cd6";
|
|
41
106
|
if (callback) {
|
|
42
107
|
callback({
|
|
43
|
-
text: `RugShield 402 payment required ($0.010 USDC on Base). PayTo: ${payTo}`,
|
|
108
|
+
text: `RugShield 402 payment required ($0.010 USDC on Base). Set X402_PRIVATE_KEY (Base USDC, 0 ETH gas) for automatic x402 signing. PayTo: ${payTo}`,
|
|
44
109
|
action: "X402_PAYMENT_REQUIRED",
|
|
45
|
-
challenge
|
|
110
|
+
challenge,
|
|
46
111
|
});
|
|
47
112
|
}
|
|
48
113
|
return false;
|
|
@@ -53,15 +118,20 @@ export const preSwapRiskCheckAction = {
|
|
|
53
118
|
const report = await response.json();
|
|
54
119
|
const isSafe = report.recommendation === "SAFE_TO_SWAP" && report.is_honeypot === false;
|
|
55
120
|
if (callback) {
|
|
121
|
+
const modeNote = usePreview
|
|
122
|
+
? `\n• Mode: Free Preview (set X402_PRIVATE_KEY for full swap simulation)`
|
|
123
|
+
: `\n• Mode: Paid x402 Verification`;
|
|
56
124
|
callback({
|
|
57
125
|
text: `RugShield Security Report for ${report.symbol ?? tokenAddress} (${tokenAddress}):\n` +
|
|
126
|
+
`• Chain: ${chain}\n` +
|
|
58
127
|
`• Recommendation: ${report.recommendation ?? "UNVERIFIED"}\n` +
|
|
59
|
-
`• Honeypot: ${report.is_honeypot === true ? "YES (DO NOT BUY)" : report.is_honeypot === false ? "NO" : "UNVERIFIED"}\n` +
|
|
60
|
-
`• Buy Tax: ${typeof report.buy_tax_bps === "number" ?
|
|
61
|
-
`• Sell Tax: ${typeof report.sell_tax_bps === "number" ?
|
|
128
|
+
`• Honeypot: ${report.is_honeypot === true ? "YES (DO NOT BUY)" : report.is_honeypot === false ? "NO" : "UNVERIFIED (paid /v1/scan required)"}\n` +
|
|
129
|
+
`• Buy Tax: ${typeof report.buy_tax_bps === "number" ? report.buy_tax_bps / 100 + "%" : "UNVERIFIED"}\n` +
|
|
130
|
+
`• Sell Tax: ${typeof report.sell_tax_bps === "number" ? report.sell_tax_bps / 100 + "%" : "UNVERIFIED"}\n` +
|
|
62
131
|
`• Pool Liquidity: ${typeof report.liquidity_usd === "number" ? "$" + report.liquidity_usd.toLocaleString() : "Unavailable"}\n` +
|
|
63
|
-
`• Risk Score: ${report.risk_score ?? "N/A"}
|
|
64
|
-
|
|
132
|
+
`• Risk Score: ${report.risk_score ?? "N/A"}` +
|
|
133
|
+
modeNote,
|
|
134
|
+
report,
|
|
65
135
|
});
|
|
66
136
|
}
|
|
67
137
|
return isSafe;
|
|
@@ -75,14 +145,20 @@ export const preSwapRiskCheckAction = {
|
|
|
75
145
|
},
|
|
76
146
|
examples: [
|
|
77
147
|
[
|
|
78
|
-
{
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
148
|
+
{
|
|
149
|
+
user: "{{user1}}",
|
|
150
|
+
content: { text: "Swap 0.05 ETH for 0x4ed4E862860beD51a9570b96d89aF5E1B0Efefed on Base" },
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
user: "{{agent}}",
|
|
154
|
+
content: { text: "Running pre-swap risk check via RugShield 402...", action: "PRE_SWAP_RISK_CHECK" },
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
],
|
|
82
158
|
};
|
|
83
159
|
export const rugshieldPlugin = {
|
|
84
160
|
name: "plugin-rugshield-402",
|
|
85
|
-
description: "RugShield 402 DEX Honeypot & Tax Protection Plugin for ElizaOS Agents
|
|
86
|
-
actions: [preSwapRiskCheckAction]
|
|
161
|
+
description: "RugShield 402 DEX Honeypot & Tax Protection Plugin for ElizaOS Agents (Base & Solana)",
|
|
162
|
+
actions: [preSwapRiskCheckAction],
|
|
87
163
|
};
|
|
88
164
|
export default rugshieldPlugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kurox_real/plugin-rugshield-402",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "RugShield 402 DEX honeypot detection, buy/sell tax simulation, and pool liquidity verification action for ElizaOS agents on Base (x402 gated).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -43,7 +43,11 @@
|
|
|
43
43
|
"url": "https://github.com/ak10082247-max/rugshield-402.git",
|
|
44
44
|
"directory": "plugins/eliza-rugshield"
|
|
45
45
|
},
|
|
46
|
-
"dependencies": {
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@x402/evm": "^2.31.0",
|
|
48
|
+
"@x402/fetch": "^2.31.0",
|
|
49
|
+
"viem": "^2.57.4"
|
|
50
|
+
},
|
|
47
51
|
"devDependencies": {
|
|
48
52
|
"typescript": "^5.7.2"
|
|
49
53
|
}
|