@pnllabs/plugin-pnllabs 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +101 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# @pnllabs/plugin-pnllabs
|
|
2
|
+
|
|
3
|
+
**Trust & risk verdicts for AI trading agents on Solana** — [PnL Labs](https://pnllabs.com)
|
|
4
|
+
as an ElizaOS plugin. Give your agent the truth before it copies a wallet or buys a token.
|
|
5
|
+
|
|
6
|
+
> Every "smart money" score ranks wallets by *peak* gains. Peaks lie. We audited 30
|
|
7
|
+
> tracked "smart money" wallets — **half are genuinely losing money on-chain.** This
|
|
8
|
+
> plugin recomputes *realized* PnL and returns a conservative verdict.
|
|
9
|
+
|
|
10
|
+
## What your agent gets
|
|
11
|
+
|
|
12
|
+
| Action | Question | Verdicts |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| `CHECK_WALLET_TRUST` | Is this wallet worth copying? (real realized PnL) | TRUSTED · NEUTRAL · UNTRUSTED · UNVERIFIABLE |
|
|
15
|
+
| `CHECK_WALLET_FORENSICS` | Where did its money come from? (cluster/Sybil links) | CEX_FUNDED · WALLET_FUNDED · … |
|
|
16
|
+
| `CHECK_TOKEN_SAFETY` | Is this token structurally safe? | LOW_RISK … CRITICAL |
|
|
17
|
+
| `CHECK_TRADE_COST` | What will this trade really cost? (real slippage) | ACCEPTABLE_COST … UNTRADEABLE |
|
|
18
|
+
|
|
19
|
+
Conservative by design: when numbers can't be reconstructed reliably, it returns
|
|
20
|
+
`UNVERIFIABLE` instead of guessing.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
elizaos plugins add @pnllabs/plugin-pnllabs
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Then add it to your character's plugins:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"name": "MyTradingAgent",
|
|
33
|
+
"plugins": ["@pnllabs/plugin-pnllabs"]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
No API key needed to start — a **daily free tier** lets your agent try every check.
|
|
38
|
+
Beyond that, calls are paid per request via **x402** (USDC on Solana, no signup).
|
|
39
|
+
|
|
40
|
+
## Config (optional)
|
|
41
|
+
|
|
42
|
+
| Env | Default | Purpose |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `PNLLABS_API_BASE` | `https://api.pnllabs.com` | override API base |
|
|
45
|
+
|
|
46
|
+
## Example
|
|
47
|
+
|
|
48
|
+
> **User:** should I copy 57hECCDVNmP7jCY6XX6FxP31DQuKiwQhv2g3nxGPLPmV?
|
|
49
|
+
> **Agent:** *(CHECK_WALLET_TRUST)* → `UNTRUSTED`: genuinely −47 SOL realized, only 27% of coins profitable.
|
|
50
|
+
|
|
51
|
+
## Links
|
|
52
|
+
|
|
53
|
+
- Site: https://pnllabs.com · API docs: https://api.pnllabs.com/docs
|
|
54
|
+
- MCP server (for non-Eliza agents): https://github.com/PnLlabs/pnllabs-mcp
|
|
55
|
+
|
|
56
|
+
MIT © PnL Labs
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Plugin } from '@elizaos/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @pnllabs/plugin-pnllabs — Trust & risk verdicts for AI trading agents on Solana.
|
|
5
|
+
*
|
|
6
|
+
* Gives any ElizaOS agent four checks against the hosted PnL Labs API
|
|
7
|
+
* (https://api.pnllabs.com), paid per call via x402 (free tier to try):
|
|
8
|
+
* CHECK_WALLET_TRUST — proof of real realized PnL (not peak scores)
|
|
9
|
+
* CHECK_WALLET_FORENSICS — funding origin & cluster links
|
|
10
|
+
* CHECK_TOKEN_SAFETY — structural token risk
|
|
11
|
+
* CHECK_TRADE_COST — real expected slippage for a size
|
|
12
|
+
*
|
|
13
|
+
* No API key needed to try (daily free tier). Behavior-first: verify a wallet
|
|
14
|
+
* before your agent copies it, a token before it buys.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare const pnllabsPlugin: Plugin;
|
|
18
|
+
|
|
19
|
+
export { pnllabsPlugin as default, pnllabsPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var API_BASE = process.env.PNLLABS_API_BASE || "https://api.pnllabs.com";
|
|
3
|
+
var B58 = /[1-9A-HJ-NP-Za-km-z]{32,44}/;
|
|
4
|
+
async function callApi(path) {
|
|
5
|
+
try {
|
|
6
|
+
const res = await fetch(API_BASE + path, {
|
|
7
|
+
headers: { Accept: "application/json" }
|
|
8
|
+
});
|
|
9
|
+
if (res.status === 402) {
|
|
10
|
+
return "This PnL Labs check requires payment via x402 (USDC on Solana). Your daily free tier is used up \u2014 pay-per-call with any x402 client.";
|
|
11
|
+
}
|
|
12
|
+
const data = await res.json();
|
|
13
|
+
return JSON.stringify(data);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
return `PnL Labs API error: ${e.message}`;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function firstAddress(text) {
|
|
19
|
+
const m = (text || "").match(B58);
|
|
20
|
+
return m ? m[0] : null;
|
|
21
|
+
}
|
|
22
|
+
var checkWalletTrust = {
|
|
23
|
+
name: "CHECK_WALLET_TRUST",
|
|
24
|
+
similes: ["WALLET_TRUST", "IS_THIS_WALLET_REAL", "PROOF_OF_PNL", "SHOULD_I_COPY_WALLET"],
|
|
25
|
+
description: "Check whether a Solana wallet is worth copying: recompute REAL realized on-chain PnL (not peak/paper scores) and return a trust verdict. Use before copy-trading or trusting any wallet.",
|
|
26
|
+
validate: async (_runtime, message) => !!firstAddress(message?.content?.text || ""),
|
|
27
|
+
handler: async (_runtime, message, _state, _options, callback) => {
|
|
28
|
+
const addr = firstAddress(message?.content?.text || "");
|
|
29
|
+
if (!addr) return { success: false, text: "No Solana wallet address found in the message." };
|
|
30
|
+
const out = await callApi(`/check/wallet/${addr}`);
|
|
31
|
+
if (callback) await callback({ text: out, source: "pnllabs" });
|
|
32
|
+
return { success: true, text: out };
|
|
33
|
+
},
|
|
34
|
+
examples: [[
|
|
35
|
+
{ name: "user", content: { text: "Should I copy 57hECCDVNmP7jCY6XX6FxP31DQuKiwQhv2g3nxGPLPmV?" } },
|
|
36
|
+
{ name: "agent", content: { text: "Checking realized PnL...", actions: ["CHECK_WALLET_TRUST"] } }
|
|
37
|
+
]]
|
|
38
|
+
};
|
|
39
|
+
var checkWalletForensics = {
|
|
40
|
+
name: "CHECK_WALLET_FORENSICS",
|
|
41
|
+
similes: ["WALLET_FORENSICS", "WALLET_ORIGIN", "IS_WALLET_FRESH", "FUNDING_SOURCE"],
|
|
42
|
+
description: "Trace a Solana wallet's funding origin and freshness: CEX-funded (real user), wallet-funded (possible cluster/Sybil), or fresh (insider/bundle risk).",
|
|
43
|
+
validate: async (_runtime, message) => !!firstAddress(message?.content?.text || ""),
|
|
44
|
+
handler: async (_runtime, message, _state, _options, callback) => {
|
|
45
|
+
const addr = firstAddress(message?.content?.text || "");
|
|
46
|
+
if (!addr) return { success: false, text: "No Solana wallet address found in the message." };
|
|
47
|
+
const out = await callApi(`/check/funder/${addr}`);
|
|
48
|
+
if (callback) await callback({ text: out, source: "pnllabs" });
|
|
49
|
+
return { success: true, text: out };
|
|
50
|
+
},
|
|
51
|
+
examples: [[
|
|
52
|
+
{ name: "user", content: { text: "Where did wallet 57hECC... get its money?" } },
|
|
53
|
+
{ name: "agent", content: { text: "Tracing funding origin...", actions: ["CHECK_WALLET_FORENSICS"] } }
|
|
54
|
+
]]
|
|
55
|
+
};
|
|
56
|
+
var checkTokenSafety = {
|
|
57
|
+
name: "CHECK_TOKEN_SAFETY",
|
|
58
|
+
similes: ["TOKEN_SAFETY", "IS_TOKEN_SAFE", "RUG_CHECK", "TOKEN_RISK"],
|
|
59
|
+
description: "Structural risk check for a Solana token: real-holder concentration, sniper bots among early buyers, honeypot. Returns LOW_RISK\u2026CRITICAL.",
|
|
60
|
+
validate: async (_runtime, message) => !!firstAddress(message?.content?.text || ""),
|
|
61
|
+
handler: async (_runtime, message, _state, _options, callback) => {
|
|
62
|
+
const mint = firstAddress(message?.content?.text || "");
|
|
63
|
+
if (!mint) return { success: false, text: "No Solana token mint found in the message." };
|
|
64
|
+
const out = await callApi(`/check/token/${mint}`);
|
|
65
|
+
if (callback) await callback({ text: out, source: "pnllabs" });
|
|
66
|
+
return { success: true, text: out };
|
|
67
|
+
},
|
|
68
|
+
examples: [[
|
|
69
|
+
{ name: "user", content: { text: "Is token So11111111111111111111111111111111111111112 safe?" } },
|
|
70
|
+
{ name: "agent", content: { text: "Running token safety check...", actions: ["CHECK_TOKEN_SAFETY"] } }
|
|
71
|
+
]]
|
|
72
|
+
};
|
|
73
|
+
var checkTradeCost = {
|
|
74
|
+
name: "CHECK_TRADE_COST",
|
|
75
|
+
similes: ["TRADE_COST", "EXPECTED_SLIPPAGE", "WHAT_WILL_THIS_TRADE_COST"],
|
|
76
|
+
description: "Execution cost oracle: expected slippage for a given size in the token's main pool, calibrated with real-world execution overhead, plus a recommended max size.",
|
|
77
|
+
validate: async (_runtime, message) => !!firstAddress(message?.content?.text || ""),
|
|
78
|
+
handler: async (_runtime, message, _state, _options, callback) => {
|
|
79
|
+
const mint = firstAddress(message?.content?.text || "");
|
|
80
|
+
if (!mint) return { success: false, text: "No Solana token mint found in the message." };
|
|
81
|
+
const m = (message?.content?.text || "").match(/([\d.]+)\s*sol/i);
|
|
82
|
+
const size = m ? m[1] : "0.5";
|
|
83
|
+
const out = await callApi(`/check/trade/${mint}?size_sol=${size}`);
|
|
84
|
+
if (callback) await callback({ text: out, source: "pnllabs" });
|
|
85
|
+
return { success: true, text: out };
|
|
86
|
+
},
|
|
87
|
+
examples: [[
|
|
88
|
+
{ name: "user", content: { text: "What will 2 SOL into So111...112 cost me?" } },
|
|
89
|
+
{ name: "agent", content: { text: "Estimating real trade cost...", actions: ["CHECK_TRADE_COST"] } }
|
|
90
|
+
]]
|
|
91
|
+
};
|
|
92
|
+
var pnllabsPlugin = {
|
|
93
|
+
name: "pnllabs",
|
|
94
|
+
description: "Trust & risk verdicts for AI trading agents on Solana \u2014 realized-PnL wallet trust (not peak scores), wallet funding forensics, token safety, and trade cost. Pay-per-call via x402, free tier to try.",
|
|
95
|
+
actions: [checkWalletTrust, checkWalletForensics, checkTokenSafety, checkTradeCost]
|
|
96
|
+
};
|
|
97
|
+
var index_default = pnllabsPlugin;
|
|
98
|
+
export {
|
|
99
|
+
index_default as default,
|
|
100
|
+
pnllabsPlugin
|
|
101
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pnllabs/plugin-pnllabs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Trust & risk verdicts for AI trading agents on Solana: realized-PnL wallet trust (not peak scores), wallet funding forensics, token safety, and trade cost. Pay-per-call via x402, free tier to try.",
|
|
5
|
+
"keywords": ["plugin", "elizaos", "solana", "x402", "trading", "defi", "wallet", "trust", "risk"],
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist", "README.md", "images"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup src/index.ts --format esm --dts --clean"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@elizaos/core": "*"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@elizaos/core": "^1.0.0",
|
|
25
|
+
"@types/node": "^20.0.0",
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.4.0"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"homepage": "https://pnllabs.com",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "github:PnLlabs/plugin-pnllabs"
|
|
34
|
+
},
|
|
35
|
+
"agentConfig": {
|
|
36
|
+
"pluginType": "elizaos:plugin:1.0.0",
|
|
37
|
+
"pluginParameters": {
|
|
38
|
+
"PNLLABS_API_BASE": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "PnL Labs API base URL (default https://api.pnllabs.com)",
|
|
41
|
+
"required": false
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|