@madeonsol/plugin-madeonsol 0.1.0 → 0.2.1
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 +13 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.js +39 -0
- package/dist/index.js +6 -0
- package/package.json +2 -3
- package/src/actions/deployer-alerts.ts +67 -0
- package/src/actions/kol-coordination.ts +64 -0
- package/src/actions/kol-feed.ts +65 -0
- package/src/actions/kol-leaderboard.ts +64 -0
- package/src/client.ts +114 -0
- package/src/index.ts +69 -0
- package/tsconfig.json +14 -0
- package/LICENSE +0 -1
package/README.md
CHANGED
|
@@ -48,6 +48,10 @@ Your agent can then respond to queries like:
|
|
|
48
48
|
|
|
49
49
|
Without `SVM_PRIVATE_KEY`, the plugin runs in read-only mode and returns payment requirement info instead of data.
|
|
50
50
|
|
|
51
|
+
### RapidAPI Features (optional)
|
|
52
|
+
|
|
53
|
+
With `RAPIDAPI_KEY` set, the plugin also provides webhook management and WebSocket streaming tokens. Ultra subscribers get access to the **DEX Trade Stream** — a real-time feed of every Solana DEX trade via `wss://madeonsol.com/ws/v1/dex-stream`.
|
|
54
|
+
|
|
51
55
|
## Wallet requirements
|
|
52
56
|
|
|
53
57
|
The wallet needs:
|
|
@@ -62,6 +66,15 @@ GET https://madeonsol.com/api/x402
|
|
|
62
66
|
|
|
63
67
|
Returns all available endpoints, prices, and parameter docs. No payment required.
|
|
64
68
|
|
|
69
|
+
## Also Available
|
|
70
|
+
|
|
71
|
+
| Platform | Package |
|
|
72
|
+
|---|---|
|
|
73
|
+
| TypeScript SDK | [`madeonsol-x402`](https://www.npmjs.com/package/madeonsol-x402) |
|
|
74
|
+
| Python (LangChain, CrewAI) | [`madeonsol-x402`](https://github.com/LamboPoewert/madeonsol-python) on PyPI |
|
|
75
|
+
| MCP Server (Claude, Cursor) | [`mcp-server-madeonsol`](https://www.npmjs.com/package/mcp-server-madeonsol) |
|
|
76
|
+
| Solana Agent Kit | [`solana-agent-kit-plugin-madeonsol`](https://www.npmjs.com/package/solana-agent-kit-plugin-madeonsol) |
|
|
77
|
+
|
|
65
78
|
## License
|
|
66
79
|
|
|
67
80
|
MIT
|
package/dist/client.d.ts
CHANGED
|
@@ -55,4 +55,36 @@ export declare class MadeOnSolClient {
|
|
|
55
55
|
error?: string;
|
|
56
56
|
status: number;
|
|
57
57
|
}>;
|
|
58
|
+
private rapidApiKey?;
|
|
59
|
+
setRapidApiKey(key: string): void;
|
|
60
|
+
private restRequest;
|
|
61
|
+
createWebhook(params: {
|
|
62
|
+
url: string;
|
|
63
|
+
events: string[];
|
|
64
|
+
filters?: Record<string, unknown>;
|
|
65
|
+
}): Promise<{
|
|
66
|
+
data?: unknown;
|
|
67
|
+
error?: string;
|
|
68
|
+
status: number;
|
|
69
|
+
}>;
|
|
70
|
+
listWebhooks(): Promise<{
|
|
71
|
+
data?: unknown;
|
|
72
|
+
error?: string;
|
|
73
|
+
status: number;
|
|
74
|
+
}>;
|
|
75
|
+
deleteWebhook(id: number): Promise<{
|
|
76
|
+
data?: unknown;
|
|
77
|
+
error?: string;
|
|
78
|
+
status: number;
|
|
79
|
+
}>;
|
|
80
|
+
testWebhook(webhookId: number): Promise<{
|
|
81
|
+
data?: unknown;
|
|
82
|
+
error?: string;
|
|
83
|
+
status: number;
|
|
84
|
+
}>;
|
|
85
|
+
getStreamToken(): Promise<{
|
|
86
|
+
data?: unknown;
|
|
87
|
+
error?: string;
|
|
88
|
+
status: number;
|
|
89
|
+
}>;
|
|
58
90
|
}
|
package/dist/client.js
CHANGED
|
@@ -42,4 +42,43 @@ export class MadeOnSolClient {
|
|
|
42
42
|
getDeployerAlerts(params) {
|
|
43
43
|
return this.query("/api/x402/deployer-hunter/alerts", params);
|
|
44
44
|
}
|
|
45
|
+
// ── Webhook management (requires RAPIDAPI_KEY) ──
|
|
46
|
+
rapidApiKey;
|
|
47
|
+
setRapidApiKey(key) {
|
|
48
|
+
this.rapidApiKey = key;
|
|
49
|
+
}
|
|
50
|
+
async restRequest(method, path, body) {
|
|
51
|
+
if (!this.rapidApiKey) {
|
|
52
|
+
return { error: "RAPIDAPI_KEY required for webhook/streaming features", status: 401 };
|
|
53
|
+
}
|
|
54
|
+
const res = await this.fetchFn(`${this.baseUrl}/api/v1${path}`, {
|
|
55
|
+
method,
|
|
56
|
+
headers: {
|
|
57
|
+
"Content-Type": "application/json",
|
|
58
|
+
"x-rapidapi-key": this.rapidApiKey,
|
|
59
|
+
"x-rapidapi-host": "madeonsol-solana-kol-tracker-tools-api.p.rapidapi.com",
|
|
60
|
+
},
|
|
61
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
62
|
+
});
|
|
63
|
+
if (!res.ok) {
|
|
64
|
+
const text = await res.text().catch(() => "Unknown error");
|
|
65
|
+
return { error: text, status: res.status };
|
|
66
|
+
}
|
|
67
|
+
return { data: await res.json(), status: res.status };
|
|
68
|
+
}
|
|
69
|
+
createWebhook(params) {
|
|
70
|
+
return this.restRequest("POST", "/webhooks", params);
|
|
71
|
+
}
|
|
72
|
+
listWebhooks() {
|
|
73
|
+
return this.restRequest("GET", "/webhooks");
|
|
74
|
+
}
|
|
75
|
+
deleteWebhook(id) {
|
|
76
|
+
return this.restRequest("DELETE", `/webhooks/${id}`);
|
|
77
|
+
}
|
|
78
|
+
testWebhook(webhookId) {
|
|
79
|
+
return this.restRequest("POST", "/webhooks/test", { webhook_id: webhookId });
|
|
80
|
+
}
|
|
81
|
+
getStreamToken() {
|
|
82
|
+
return this.restRequest("POST", "/stream/token");
|
|
83
|
+
}
|
|
45
84
|
}
|
package/dist/index.js
CHANGED
|
@@ -44,6 +44,12 @@ export const madeOnSolPlugin = {
|
|
|
44
44
|
console.log("[madeonsol] No SVM_PRIVATE_KEY — running in read-only mode (402 info only)");
|
|
45
45
|
}
|
|
46
46
|
const madeOnSolClient = new MadeOnSolClient({ baseUrl, fetchFn });
|
|
47
|
+
// Enable webhook/streaming features if RAPIDAPI_KEY is provided
|
|
48
|
+
const rapidApiKey = runtime.getSetting?.("RAPIDAPI_KEY");
|
|
49
|
+
if (rapidApiKey) {
|
|
50
|
+
madeOnSolClient.setRapidApiKey(rapidApiKey);
|
|
51
|
+
console.log("[madeonsol] Webhook & streaming features enabled (RAPIDAPI_KEY set)");
|
|
52
|
+
}
|
|
47
53
|
runtime[MADEONSOL_CLIENT_KEY] = madeOnSolClient;
|
|
48
54
|
},
|
|
49
55
|
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@madeonsol/plugin-madeonsol",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "ElizaOS plugin for MadeOnSol — Solana KOL intelligence and deployer analytics via x402 micropayments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
|
-
"files": ["dist", "README.md"],
|
|
9
8
|
"scripts": {
|
|
10
9
|
"build": "tsc",
|
|
11
|
-
"
|
|
10
|
+
"dev": "tsc --watch"
|
|
12
11
|
},
|
|
13
12
|
"peerDependencies": {
|
|
14
13
|
"@elizaos/core": ">=1.0.0",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Action, IAgentRuntime, Memory, State, HandlerCallback } from "@elizaos/core";
|
|
2
|
+
import { MadeOnSolClient } from "../client.js";
|
|
3
|
+
import { MADEONSOL_CLIENT_KEY } from "../index.js";
|
|
4
|
+
|
|
5
|
+
function getClient(runtime: IAgentRuntime): MadeOnSolClient {
|
|
6
|
+
return ((runtime as unknown as Record<string, unknown>)[MADEONSOL_CLIENT_KEY] as MadeOnSolClient) ?? new MadeOnSolClient();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const deployerAlertsAction: Action = {
|
|
10
|
+
name: "GET_DEPLOYER_ALERTS",
|
|
11
|
+
description:
|
|
12
|
+
"Get real-time Pump.fun deployer alerts from MadeOnSol. Shows new token launches from tracked elite/good deployers with stats, market cap, and KOL buy enrichment.",
|
|
13
|
+
similes: [
|
|
14
|
+
"deployer alerts",
|
|
15
|
+
"pump fun launches",
|
|
16
|
+
"new token alerts",
|
|
17
|
+
"deployer tracker",
|
|
18
|
+
"elite deployer tokens",
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
validate: async (_runtime: IAgentRuntime, message: Memory): Promise<boolean> => {
|
|
22
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
23
|
+
return /\b(deployer|pump\.?fun|launch|new token)/i.test(text) && /\b(alert|track|monitor|latest|recent)/i.test(text);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
handler: async (
|
|
27
|
+
runtime: IAgentRuntime,
|
|
28
|
+
message: Memory,
|
|
29
|
+
_state?: State,
|
|
30
|
+
_options?: unknown,
|
|
31
|
+
callback?: HandlerCallback,
|
|
32
|
+
) => {
|
|
33
|
+
const client = getClient(runtime);
|
|
34
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
35
|
+
const limit = text.match(/\b(\d+)\s*(alert|token|launch)/)?.[1] || "10";
|
|
36
|
+
|
|
37
|
+
const result = await client.getDeployerAlerts({ limit });
|
|
38
|
+
|
|
39
|
+
if (result.error) {
|
|
40
|
+
callback?.({ text: result.status === 402
|
|
41
|
+
? "x402 payment required but no wallet configured. Set SVM_PRIVATE_KEY to enable automatic USDC payments."
|
|
42
|
+
: `Error: ${result.error}` });
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const data = result.data as { alerts: Array<{ title: string; token_symbol: string; priority: string; market_cap_at_alert: number | null; deployers: { tier: string; bonding_rate: number | null }; kol_buys: { count: number; kols: string[] } | null }> };
|
|
47
|
+
const lines = (data.alerts || []).slice(0, 10).map((a) => {
|
|
48
|
+
const deployer = a.deployers as unknown as { tier: string; bonding_rate: number | null };
|
|
49
|
+
const mc = a.market_cap_at_alert ? `$${(a.market_cap_at_alert / 1000).toFixed(1)}k` : "?";
|
|
50
|
+
const kols = a.kol_buys ? `${a.kol_buys.count} KOLs buying` : "";
|
|
51
|
+
return `[${deployer?.tier}] ${a.token_symbol || "?"} — MC: ${mc}${kols ? ` | ${kols}` : ""}`;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
callback?.({
|
|
55
|
+
text: `Deployer Alerts:\n${lines.join("\n") || "No recent alerts."}`,
|
|
56
|
+
content: data,
|
|
57
|
+
});
|
|
58
|
+
return undefined;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
examples: [
|
|
62
|
+
[
|
|
63
|
+
{ name: "user1", content: { text: "Show me the latest deployer alerts from Pump.fun" } },
|
|
64
|
+
{ name: "assistant", content: { text: "Here are the latest deployer alerts..." } },
|
|
65
|
+
],
|
|
66
|
+
] as Action["examples"],
|
|
67
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Action, IAgentRuntime, Memory, State, HandlerCallback } from "@elizaos/core";
|
|
2
|
+
import { MadeOnSolClient } from "../client.js";
|
|
3
|
+
import { MADEONSOL_CLIENT_KEY } from "../index.js";
|
|
4
|
+
|
|
5
|
+
function getClient(runtime: IAgentRuntime): MadeOnSolClient {
|
|
6
|
+
return ((runtime as unknown as Record<string, unknown>)[MADEONSOL_CLIENT_KEY] as MadeOnSolClient) ?? new MadeOnSolClient();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const kolCoordinationAction: Action = {
|
|
10
|
+
name: "GET_KOL_COORDINATION",
|
|
11
|
+
description:
|
|
12
|
+
"Get KOL convergence signals from MadeOnSol — tokens being accumulated by multiple KOLs simultaneously. Shows which tokens smart money is converging on.",
|
|
13
|
+
similes: [
|
|
14
|
+
"kol convergence",
|
|
15
|
+
"what tokens are kols accumulating",
|
|
16
|
+
"kol coordination",
|
|
17
|
+
"smart money convergence",
|
|
18
|
+
"multiple kols buying",
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
validate: async (_runtime: IAgentRuntime, message: Memory): Promise<boolean> => {
|
|
22
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
23
|
+
return /\b(kol|smart money)\b/.test(text) && /\b(converg|coordinat|accumul|same token|multiple)/i.test(text);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
handler: async (
|
|
27
|
+
runtime: IAgentRuntime,
|
|
28
|
+
message: Memory,
|
|
29
|
+
_state?: State,
|
|
30
|
+
_options?: unknown,
|
|
31
|
+
callback?: HandlerCallback,
|
|
32
|
+
) => {
|
|
33
|
+
const client = getClient(runtime);
|
|
34
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
35
|
+
const period = text.includes("1h") ? "1h" : text.includes("7d") ? "7d" : text.includes("6h") ? "6h" : "24h";
|
|
36
|
+
|
|
37
|
+
const result = await client.getKolCoordination({ period, limit: "10" });
|
|
38
|
+
|
|
39
|
+
if (result.error) {
|
|
40
|
+
callback?.({ text: result.status === 402
|
|
41
|
+
? "x402 payment required but no wallet configured. Set SVM_PRIVATE_KEY to enable automatic USDC payments."
|
|
42
|
+
: `Error: ${result.error}` });
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const data = result.data as { coordination: Array<{ token_symbol: string; kol_count: number; signal: string; net_sol_flow: number }> };
|
|
47
|
+
const lines = (data.coordination || []).map(
|
|
48
|
+
(t) => `${t.token_symbol}: ${t.kol_count} KOLs ${t.signal} (${t.net_sol_flow > 0 ? "+" : ""}${t.net_sol_flow.toFixed(2)} SOL net)`
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
callback?.({
|
|
52
|
+
text: `KOL convergence signals (${period}):\n${lines.join("\n") || "No coordination signals found."}`,
|
|
53
|
+
content: data,
|
|
54
|
+
});
|
|
55
|
+
return undefined;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
examples: [
|
|
59
|
+
[
|
|
60
|
+
{ name: "user1", content: { text: "What tokens are multiple KOLs accumulating?" } },
|
|
61
|
+
{ name: "assistant", content: { text: "Here are the KOL convergence signals..." } },
|
|
62
|
+
],
|
|
63
|
+
] as Action["examples"],
|
|
64
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Action, IAgentRuntime, Memory, State, HandlerCallback } from "@elizaos/core";
|
|
2
|
+
import { MadeOnSolClient } from "../client.js";
|
|
3
|
+
import { MADEONSOL_CLIENT_KEY } from "../index.js";
|
|
4
|
+
|
|
5
|
+
function getClient(runtime: IAgentRuntime): MadeOnSolClient {
|
|
6
|
+
return ((runtime as unknown as Record<string, unknown>)[MADEONSOL_CLIENT_KEY] as MadeOnSolClient) ?? new MadeOnSolClient();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const kolFeedAction: Action = {
|
|
10
|
+
name: "GET_KOL_FEED",
|
|
11
|
+
description:
|
|
12
|
+
"Get the real-time Solana KOL trade feed from MadeOnSol. Shows latest buys and sells from 946 tracked KOL wallets with deployer enrichment.",
|
|
13
|
+
similes: [
|
|
14
|
+
"kol trades",
|
|
15
|
+
"what are kols buying",
|
|
16
|
+
"solana kol feed",
|
|
17
|
+
"kol activity",
|
|
18
|
+
"smart money trades",
|
|
19
|
+
"what did kols trade",
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
validate: async (_runtime: IAgentRuntime, message: Memory): Promise<boolean> => {
|
|
23
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
24
|
+
return /\b(kol|smart money)\b/.test(text) && /\b(feed|trade|buy|sell|activit)/i.test(text);
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
handler: async (
|
|
28
|
+
runtime: IAgentRuntime,
|
|
29
|
+
message: Memory,
|
|
30
|
+
_state?: State,
|
|
31
|
+
_options?: unknown,
|
|
32
|
+
callback?: HandlerCallback,
|
|
33
|
+
) => {
|
|
34
|
+
const client = getClient(runtime);
|
|
35
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
36
|
+
const action = text.includes("buy") ? "buy" : text.includes("sell") ? "sell" : undefined;
|
|
37
|
+
|
|
38
|
+
const result = await client.getKolFeed({ limit: "10", ...(action ? { action } : {}) });
|
|
39
|
+
|
|
40
|
+
if (result.error) {
|
|
41
|
+
callback?.({ text: result.status === 402
|
|
42
|
+
? "x402 payment required but no wallet configured. Set SVM_PRIVATE_KEY to enable automatic USDC payments."
|
|
43
|
+
: `Error: ${result.error}` });
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const data = result.data as { trades: Array<{ kol_name: string; token_symbol: string; action: string; sol_amount: number; traded_at: string }> };
|
|
48
|
+
const lines = (data.trades || []).slice(0, 10).map(
|
|
49
|
+
(t) => `${t.kol_name || "Unknown"} ${t.action === "buy" ? "bought" : "sold"} ${t.token_symbol || "?"} for ${Number(t.sol_amount).toFixed(2)} SOL`
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
callback?.({
|
|
53
|
+
text: `Latest KOL trades:\n${lines.join("\n")}`,
|
|
54
|
+
content: data,
|
|
55
|
+
});
|
|
56
|
+
return undefined;
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
examples: [
|
|
60
|
+
[
|
|
61
|
+
{ name: "user1", content: { text: "What are the latest KOL trades on Solana?" } },
|
|
62
|
+
{ name: "assistant", content: { text: "Here are the latest KOL trades from MadeOnSol..." } },
|
|
63
|
+
],
|
|
64
|
+
] as Action["examples"],
|
|
65
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Action, IAgentRuntime, Memory, State, HandlerCallback } from "@elizaos/core";
|
|
2
|
+
import { MadeOnSolClient } from "../client.js";
|
|
3
|
+
import { MADEONSOL_CLIENT_KEY } from "../index.js";
|
|
4
|
+
|
|
5
|
+
function getClient(runtime: IAgentRuntime): MadeOnSolClient {
|
|
6
|
+
return ((runtime as unknown as Record<string, unknown>)[MADEONSOL_CLIENT_KEY] as MadeOnSolClient) ?? new MadeOnSolClient();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const kolLeaderboardAction: Action = {
|
|
10
|
+
name: "GET_KOL_LEADERBOARD",
|
|
11
|
+
description:
|
|
12
|
+
"Get KOL performance rankings from MadeOnSol — top Solana KOLs ranked by PnL, volume, and win rate.",
|
|
13
|
+
similes: [
|
|
14
|
+
"kol leaderboard",
|
|
15
|
+
"best performing kols",
|
|
16
|
+
"top kol traders",
|
|
17
|
+
"kol rankings",
|
|
18
|
+
"who is the best kol",
|
|
19
|
+
],
|
|
20
|
+
|
|
21
|
+
validate: async (_runtime: IAgentRuntime, message: Memory): Promise<boolean> => {
|
|
22
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
23
|
+
return /\b(kol|smart money)\b/.test(text) && /\b(leaderboard|ranking|top|best|perform|pnl|win rate)/i.test(text);
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
handler: async (
|
|
27
|
+
runtime: IAgentRuntime,
|
|
28
|
+
message: Memory,
|
|
29
|
+
_state?: State,
|
|
30
|
+
_options?: unknown,
|
|
31
|
+
callback?: HandlerCallback,
|
|
32
|
+
) => {
|
|
33
|
+
const client = getClient(runtime);
|
|
34
|
+
const text = (message.content?.text || "").toLowerCase();
|
|
35
|
+
const period = text.includes("today") ? "today" : text.includes("30d") || text.includes("month") ? "30d" : "7d";
|
|
36
|
+
|
|
37
|
+
const result = await client.getKolLeaderboard({ period, limit: "10" });
|
|
38
|
+
|
|
39
|
+
if (result.error) {
|
|
40
|
+
callback?.({ text: result.status === 402
|
|
41
|
+
? "x402 payment required but no wallet configured. Set SVM_PRIVATE_KEY to enable automatic USDC payments."
|
|
42
|
+
: `Error: ${result.error}` });
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const data = result.data as { leaderboard: Array<{ name: string; pnl_sol: number; buy_count: number; sell_count: number; win_rate: number | null }> };
|
|
47
|
+
const lines = (data.leaderboard || []).map(
|
|
48
|
+
(k, i) => `${i + 1}. ${k.name}: ${k.pnl_sol > 0 ? "+" : ""}${k.pnl_sol.toFixed(2)} SOL PnL (${k.buy_count}B/${k.sell_count}S${k.win_rate != null ? `, ${(k.win_rate * 100).toFixed(0)}% WR` : ""})`
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
callback?.({
|
|
52
|
+
text: `KOL Leaderboard (${period}):\n${lines.join("\n") || "No data for this period."}`,
|
|
53
|
+
content: data,
|
|
54
|
+
});
|
|
55
|
+
return undefined;
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
examples: [
|
|
59
|
+
[
|
|
60
|
+
{ name: "user1", content: { text: "Show me the top performing KOLs this week" } },
|
|
61
|
+
{ name: "assistant", content: { text: "Here are the top KOLs by PnL..." } },
|
|
62
|
+
],
|
|
63
|
+
] as Action["examples"],
|
|
64
|
+
};
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MadeOnSol x402 API client.
|
|
3
|
+
* Uses @x402/fetch to automatically handle 402 → sign USDC → retry flow.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BASE = "https://madeonsol.com";
|
|
7
|
+
|
|
8
|
+
export interface MadeOnSolClientOptions {
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
/**
|
|
11
|
+
* A fetch function that handles x402 payments automatically.
|
|
12
|
+
* Created via wrapFetchWithPayment() from @x402/fetch.
|
|
13
|
+
* If not provided, uses plain fetch (requests will return 402).
|
|
14
|
+
*/
|
|
15
|
+
fetchFn?: typeof fetch;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class MadeOnSolClient {
|
|
19
|
+
private baseUrl: string;
|
|
20
|
+
private fetchFn: typeof fetch;
|
|
21
|
+
|
|
22
|
+
constructor(options: MadeOnSolClientOptions = {}) {
|
|
23
|
+
this.baseUrl = options.baseUrl || DEFAULT_BASE;
|
|
24
|
+
this.fetchFn = options.fetchFn || globalThis.fetch;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async query<T = unknown>(path: string, params?: Record<string, string | undefined>): Promise<{ data?: T; error?: string; status: number }> {
|
|
28
|
+
const url = new URL(path, this.baseUrl);
|
|
29
|
+
if (params) {
|
|
30
|
+
for (const [k, v] of Object.entries(params)) {
|
|
31
|
+
if (v !== undefined) url.searchParams.set(k, v);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const res = await this.fetchFn(url.toString(), { method: "GET" });
|
|
36
|
+
|
|
37
|
+
if (res.status === 402) {
|
|
38
|
+
const body = await res.json();
|
|
39
|
+
return { error: `Payment required: ${JSON.stringify(body.accepts?.[0] || body)}`, status: 402 };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
const text = await res.text().catch(() => "Unknown error");
|
|
44
|
+
return { error: text, status: res.status };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const data = await res.json() as T;
|
|
48
|
+
return { data, status: res.status };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
getKolFeed(params?: { limit?: string; action?: string; kol?: string }) {
|
|
52
|
+
return this.query("/api/x402/kol/feed", params);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getKolCoordination(params?: { period?: string; min_kols?: string; limit?: string }) {
|
|
56
|
+
return this.query("/api/x402/kol/coordination", params);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getKolLeaderboard(params?: { period?: string; limit?: string }) {
|
|
60
|
+
return this.query("/api/x402/kol/leaderboard", params);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getDeployerAlerts(params?: { since?: string; limit?: string; offset?: string }) {
|
|
64
|
+
return this.query("/api/x402/deployer-hunter/alerts", params);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ── Webhook management (requires RAPIDAPI_KEY) ──
|
|
68
|
+
|
|
69
|
+
private rapidApiKey?: string;
|
|
70
|
+
|
|
71
|
+
setRapidApiKey(key: string) {
|
|
72
|
+
this.rapidApiKey = key;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private async restRequest<T = unknown>(method: string, path: string, body?: unknown): Promise<{ data?: T; error?: string; status: number }> {
|
|
76
|
+
if (!this.rapidApiKey) {
|
|
77
|
+
return { error: "RAPIDAPI_KEY required for webhook/streaming features", status: 401 };
|
|
78
|
+
}
|
|
79
|
+
const res = await this.fetchFn(`${this.baseUrl}/api/v1${path}`, {
|
|
80
|
+
method,
|
|
81
|
+
headers: {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
"x-rapidapi-key": this.rapidApiKey,
|
|
84
|
+
"x-rapidapi-host": "madeonsol-solana-kol-tracker-tools-api.p.rapidapi.com",
|
|
85
|
+
},
|
|
86
|
+
...(body ? { body: JSON.stringify(body) } : {}),
|
|
87
|
+
});
|
|
88
|
+
if (!res.ok) {
|
|
89
|
+
const text = await res.text().catch(() => "Unknown error");
|
|
90
|
+
return { error: text, status: res.status };
|
|
91
|
+
}
|
|
92
|
+
return { data: await res.json() as T, status: res.status };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
createWebhook(params: { url: string; events: string[]; filters?: Record<string, unknown> }) {
|
|
96
|
+
return this.restRequest("POST", "/webhooks", params);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
listWebhooks() {
|
|
100
|
+
return this.restRequest("GET", "/webhooks");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
deleteWebhook(id: number) {
|
|
104
|
+
return this.restRequest("DELETE", `/webhooks/${id}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
testWebhook(webhookId: number) {
|
|
108
|
+
return this.restRequest("POST", "/webhooks/test", { webhook_id: webhookId });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
getStreamToken() {
|
|
112
|
+
return this.restRequest("POST", "/stream/token");
|
|
113
|
+
}
|
|
114
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { Plugin, IAgentRuntime } from "@elizaos/core";
|
|
2
|
+
import { kolFeedAction } from "./actions/kol-feed.js";
|
|
3
|
+
import { kolCoordinationAction } from "./actions/kol-coordination.js";
|
|
4
|
+
import { kolLeaderboardAction } from "./actions/kol-leaderboard.js";
|
|
5
|
+
import { deployerAlertsAction } from "./actions/deployer-alerts.js";
|
|
6
|
+
import { MadeOnSolClient } from "./client.js";
|
|
7
|
+
|
|
8
|
+
/** Key used to store the initialized client on the runtime */
|
|
9
|
+
export const MADEONSOL_CLIENT_KEY = "madeonsol:client";
|
|
10
|
+
|
|
11
|
+
export const madeOnSolPlugin: Plugin = {
|
|
12
|
+
name: "madeonsol",
|
|
13
|
+
description:
|
|
14
|
+
"Query Solana KOL trading intelligence and deployer analytics from MadeOnSol via x402 micropayments. Tracks 946 KOL wallets and 4000+ Pump.fun deployers.",
|
|
15
|
+
actions: [
|
|
16
|
+
kolFeedAction,
|
|
17
|
+
kolCoordinationAction,
|
|
18
|
+
kolLeaderboardAction,
|
|
19
|
+
deployerAlertsAction,
|
|
20
|
+
],
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Initialize the x402 payment-enabled client.
|
|
24
|
+
* Requires SVM_PRIVATE_KEY in the runtime settings for automatic payments.
|
|
25
|
+
* Without it, the plugin still works but requests will return 402 payment info.
|
|
26
|
+
*/
|
|
27
|
+
init: async (_config: Record<string, string>, runtime: IAgentRuntime) => {
|
|
28
|
+
const baseUrl = String(runtime.getSetting?.("MADEONSOL_API_URL") || "https://madeonsol.com");
|
|
29
|
+
const privateKey = runtime.getSetting?.("SVM_PRIVATE_KEY") as string | undefined;
|
|
30
|
+
|
|
31
|
+
let fetchFn: typeof fetch | undefined;
|
|
32
|
+
|
|
33
|
+
if (privateKey) {
|
|
34
|
+
try {
|
|
35
|
+
const { wrapFetchWithPayment } = await import("@x402/fetch");
|
|
36
|
+
const { x402Client } = await import("@x402/core/client");
|
|
37
|
+
const { ExactSvmScheme } = await import("@x402/svm/exact/client");
|
|
38
|
+
const { createKeyPairSignerFromBytes } = await import("@solana/kit");
|
|
39
|
+
const { base58 } = await import("@scure/base");
|
|
40
|
+
|
|
41
|
+
const signer = await createKeyPairSignerFromBytes(base58.decode(privateKey));
|
|
42
|
+
const client = new x402Client();
|
|
43
|
+
client.register("solana:*", new ExactSvmScheme(signer));
|
|
44
|
+
fetchFn = wrapFetchWithPayment(fetch, client);
|
|
45
|
+
|
|
46
|
+
console.log(`[madeonsol] x402 payments enabled, wallet: ${signer.address}`);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.warn("[madeonsol] x402 payment setup failed, running in read-only mode:", err);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
console.log("[madeonsol] No SVM_PRIVATE_KEY — running in read-only mode (402 info only)");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const madeOnSolClient = new MadeOnSolClient({ baseUrl, fetchFn });
|
|
55
|
+
|
|
56
|
+
// Enable webhook/streaming features if RAPIDAPI_KEY is provided
|
|
57
|
+
const rapidApiKey = runtime.getSetting?.("RAPIDAPI_KEY") as string | undefined;
|
|
58
|
+
if (rapidApiKey) {
|
|
59
|
+
madeOnSolClient.setRapidApiKey(rapidApiKey);
|
|
60
|
+
console.log("[madeonsol] Webhook & streaming features enabled (RAPIDAPI_KEY set)");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
(runtime as unknown as Record<string, unknown>)[MADEONSOL_CLIENT_KEY] = madeOnSolClient;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default madeOnSolPlugin;
|
|
68
|
+
export { MadeOnSolClient } from "./client.js";
|
|
69
|
+
export { kolFeedAction, kolCoordinationAction, kolLeaderboardAction, deployerAlertsAction };
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"outDir": "dist",
|
|
8
|
+
"rootDir": "src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|
package/LICENSE
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
MIT License
|