@elizaos/plugin-elizamaker 2.0.3-beta.5 → 2.0.3-beta.7

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.
Files changed (45) hide show
  1. package/dist/drop-routes.d.ts +22 -0
  2. package/dist/drop-routes.d.ts.map +1 -0
  3. package/dist/drop-routes.js +162 -0
  4. package/dist/drop-routes.js.map +1 -0
  5. package/dist/drop-service-registry.d.ts +4 -0
  6. package/dist/drop-service-registry.d.ts.map +1 -0
  7. package/dist/drop-service-registry.js +12 -0
  8. package/dist/drop-service-registry.js.map +1 -0
  9. package/dist/drop-service.d.ts +46 -0
  10. package/dist/drop-service.d.ts.map +1 -0
  11. package/dist/drop-service.js +136 -0
  12. package/dist/drop-service.js.map +1 -0
  13. package/dist/index.d.ts +13 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +42 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/init-registry-services.d.ts +18 -0
  18. package/dist/init-registry-services.d.ts.map +1 -0
  19. package/dist/init-registry-services.js +64 -0
  20. package/dist/init-registry-services.js.map +1 -0
  21. package/dist/merkle-tree.d.ts +90 -0
  22. package/dist/merkle-tree.d.ts.map +1 -0
  23. package/dist/merkle-tree.js +118 -0
  24. package/dist/merkle-tree.js.map +1 -0
  25. package/dist/nft-verify.d.ts +16 -0
  26. package/dist/nft-verify.d.ts.map +1 -0
  27. package/dist/nft-verify.js +94 -0
  28. package/dist/nft-verify.js.map +1 -0
  29. package/dist/og-tracker.d.ts +29 -0
  30. package/dist/og-tracker.d.ts.map +1 -0
  31. package/dist/og-tracker.js +41 -0
  32. package/dist/og-tracker.js.map +1 -0
  33. package/dist/plugin.d.ts +4 -0
  34. package/dist/plugin.d.ts.map +1 -0
  35. package/dist/plugin.js +105 -0
  36. package/dist/plugin.js.map +1 -0
  37. package/dist/registry-service-registry.d.ts +4 -0
  38. package/dist/registry-service-registry.d.ts.map +1 -0
  39. package/dist/registry-service-registry.js +12 -0
  40. package/dist/registry-service-registry.js.map +1 -0
  41. package/dist/twitter-verify.d.ts +29 -0
  42. package/dist/twitter-verify.d.ts.map +1 -0
  43. package/dist/twitter-verify.js +164 -0
  44. package/dist/twitter-verify.js.map +1 -0
  45. package/package.json +4 -4
@@ -0,0 +1,164 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import {
4
+ createIntegrationTelemetrySpan,
5
+ resolveStateDir
6
+ } from "@elizaos/agent";
7
+ import { logger } from "@elizaos/core";
8
+ const WHITELIST_FILE = "whitelist.json";
9
+ function generateVerificationMessage(agentName, walletAddress) {
10
+ const shortAddr = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;
11
+ return `Verifying my Eliza agent "${agentName}" | ${shortAddr} #ElizaAgent`;
12
+ }
13
+ function parseTweetUrl(url) {
14
+ const match = url.match(/(?:twitter\.com|x\.com)\/(\w+)\/status\/(\d+)/);
15
+ if (!match) return null;
16
+ return { screenName: match[1], tweetId: match[2] };
17
+ }
18
+ async function verifyTweet(tweetUrl, walletAddress) {
19
+ const parsed = parseTweetUrl(tweetUrl);
20
+ if (!parsed) {
21
+ return {
22
+ verified: false,
23
+ error: "Invalid tweet URL. Use a twitter.com or x.com status URL.",
24
+ handle: null
25
+ };
26
+ }
27
+ const apiUrl = `https://api.fxtwitter.com/${parsed.screenName}/status/${parsed.tweetId}`;
28
+ const verifySpan = createIntegrationTelemetrySpan({
29
+ boundary: "marketplace",
30
+ operation: "verify_tweet",
31
+ timeoutMs: 15e3
32
+ });
33
+ let response;
34
+ try {
35
+ response = await fetch(apiUrl, {
36
+ headers: { "User-Agent": "ElizaVerifier/1.0" },
37
+ signal: AbortSignal.timeout(15e3)
38
+ });
39
+ } catch (err) {
40
+ verifySpan.failure({ error: err });
41
+ logger.warn(`[twitter-verify] FxTwitter fetch failed: ${err}`);
42
+ return {
43
+ verified: false,
44
+ error: "Could not reach tweet verification service. Try again later.",
45
+ handle: null
46
+ };
47
+ }
48
+ if (!response.ok) {
49
+ if (response.status === 404) {
50
+ verifySpan.success({ statusCode: 404 });
51
+ return {
52
+ verified: false,
53
+ error: "Tweet not found. Make sure the URL is correct and the tweet is public.",
54
+ handle: null
55
+ };
56
+ }
57
+ verifySpan.failure({
58
+ statusCode: response.status,
59
+ errorKind: "http_error"
60
+ });
61
+ return {
62
+ verified: false,
63
+ error: `Tweet fetch failed (HTTP ${response.status})`,
64
+ handle: null
65
+ };
66
+ }
67
+ let data;
68
+ try {
69
+ data = await response.json();
70
+ } catch (err) {
71
+ verifySpan.failure({ error: err, statusCode: response.status });
72
+ return {
73
+ verified: false,
74
+ error: "Invalid response from verification service",
75
+ handle: null
76
+ };
77
+ }
78
+ if (!data.tweet?.text) {
79
+ verifySpan.failure({
80
+ statusCode: response.status,
81
+ errorKind: "empty_content"
82
+ });
83
+ return {
84
+ verified: false,
85
+ error: "Could not read tweet content",
86
+ handle: null
87
+ };
88
+ }
89
+ const tweetText = data.tweet.text;
90
+ const handle = data.tweet.author?.screen_name ?? parsed.screenName;
91
+ const shortAddr = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;
92
+ const hasAddress = tweetText.includes(shortAddr) || tweetText.toLowerCase().includes(walletAddress.toLowerCase().slice(0, 10));
93
+ const hasHashtag = tweetText.includes("#ElizaAgent");
94
+ if (!hasAddress) {
95
+ return {
96
+ verified: false,
97
+ error: "Tweet does not contain your wallet address. Make sure you copied the full verification message.",
98
+ handle
99
+ };
100
+ }
101
+ if (!hasHashtag) {
102
+ return {
103
+ verified: false,
104
+ error: "Tweet is missing #ElizaAgent hashtag.",
105
+ handle
106
+ };
107
+ }
108
+ verifySpan.success({ statusCode: response.status });
109
+ return { verified: true, error: null, handle };
110
+ }
111
+ function whitelistPath() {
112
+ return path.join(resolveStateDir(), WHITELIST_FILE);
113
+ }
114
+ function loadWhitelist() {
115
+ const filePath = whitelistPath();
116
+ if (!fs.existsSync(filePath)) return { verified: {} };
117
+ const raw = fs.readFileSync(filePath, "utf-8");
118
+ try {
119
+ return JSON.parse(raw);
120
+ } catch {
121
+ logger.warn(
122
+ `[twitter-verify] Corrupt whitelist file, resetting: ${filePath}`
123
+ );
124
+ return { verified: {} };
125
+ }
126
+ }
127
+ function saveWhitelist(data) {
128
+ const filePath = whitelistPath();
129
+ const dir = path.dirname(filePath);
130
+ if (!fs.existsSync(dir)) {
131
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
132
+ }
133
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), {
134
+ encoding: "utf-8",
135
+ mode: 384
136
+ });
137
+ }
138
+ function markAddressVerified(address, tweetUrl, handle) {
139
+ const wl = loadWhitelist();
140
+ wl.verified[address.toLowerCase()] = {
141
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
142
+ tweetUrl,
143
+ handle
144
+ };
145
+ saveWhitelist(wl);
146
+ logger.info(`[twitter-verify] Address ${address} verified via @${handle}`);
147
+ }
148
+ function isAddressWhitelisted(address) {
149
+ const wl = loadWhitelist();
150
+ return address.toLowerCase() in wl.verified;
151
+ }
152
+ function getVerifiedAddresses() {
153
+ const wl = loadWhitelist();
154
+ return Object.keys(wl.verified);
155
+ }
156
+ export {
157
+ generateVerificationMessage,
158
+ getVerifiedAddresses,
159
+ isAddressWhitelisted,
160
+ loadWhitelist,
161
+ markAddressVerified,
162
+ verifyTweet
163
+ };
164
+ //# sourceMappingURL=twitter-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/twitter-verify.ts"],"sourcesContent":["/**\n * Twitter/X verification for whitelist eligibility.\n *\n * Users post a verification message on X containing their agent name and\n * wallet address. The app verifies the tweet exists using the FxTwitter API\n * (free, no auth required). Verified addresses are stored locally and can\n * be collected into a Merkle tree for on-chain whitelist proofs.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n createIntegrationTelemetrySpan,\n resolveStateDir,\n} from \"@elizaos/agent\";\nimport { logger } from \"@elizaos/core\";\n\nexport interface VerificationResult {\n verified: boolean;\n error: string | null;\n handle: string | null;\n}\n\nconst WHITELIST_FILE = \"whitelist.json\";\n\n// ── Types ────────────────────────────────────────────────────────────────\n\ninterface WhitelistEntry {\n timestamp: string;\n tweetUrl: string;\n handle: string;\n}\n\ninterface WhitelistData {\n verified: Record<string, WhitelistEntry>;\n}\n\n// ── Verification Message ─────────────────────────────────────────────────\n\nexport function generateVerificationMessage(\n agentName: string,\n walletAddress: string,\n): string {\n const shortAddr = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n return `Verifying my Eliza agent \"${agentName}\" | ${shortAddr} #ElizaAgent`;\n}\n\n// ── Tweet Verification ───────────────────────────────────────────────────\n\nfunction parseTweetUrl(\n url: string,\n): { screenName: string; tweetId: string } | null {\n const match = url.match(/(?:twitter\\.com|x\\.com)\\/(\\w+)\\/status\\/(\\d+)/);\n if (!match) return null;\n return { screenName: match[1], tweetId: match[2] };\n}\n\nexport async function verifyTweet(\n tweetUrl: string,\n walletAddress: string,\n): Promise<VerificationResult> {\n const parsed = parseTweetUrl(tweetUrl);\n if (!parsed) {\n return {\n verified: false,\n error: \"Invalid tweet URL. Use a twitter.com or x.com status URL.\",\n handle: null,\n };\n }\n\n const apiUrl = `https://api.fxtwitter.com/${parsed.screenName}/status/${parsed.tweetId}`;\n\n const verifySpan = createIntegrationTelemetrySpan({\n boundary: \"marketplace\",\n operation: \"verify_tweet\",\n timeoutMs: 15_000,\n });\n\n let response: Response;\n try {\n response = await fetch(apiUrl, {\n headers: { \"User-Agent\": \"ElizaVerifier/1.0\" },\n signal: AbortSignal.timeout(15_000),\n });\n } catch (err) {\n verifySpan.failure({ error: err });\n logger.warn(`[twitter-verify] FxTwitter fetch failed: ${err}`);\n return {\n verified: false,\n error: \"Could not reach tweet verification service. Try again later.\",\n handle: null,\n };\n }\n\n if (!response.ok) {\n if (response.status === 404) {\n verifySpan.success({ statusCode: 404 });\n return {\n verified: false,\n error:\n \"Tweet not found. Make sure the URL is correct and the tweet is public.\",\n handle: null,\n };\n }\n verifySpan.failure({\n statusCode: response.status,\n errorKind: \"http_error\",\n });\n return {\n verified: false,\n error: `Tweet fetch failed (HTTP ${response.status})`,\n handle: null,\n };\n }\n\n let data: {\n code?: number;\n tweet?: {\n text?: string;\n author?: { screen_name?: string };\n };\n };\n\n try {\n data = (await response.json()) as typeof data;\n } catch (err) {\n verifySpan.failure({ error: err, statusCode: response.status });\n return {\n verified: false,\n error: \"Invalid response from verification service\",\n handle: null,\n };\n }\n\n if (!data.tweet?.text) {\n verifySpan.failure({\n statusCode: response.status,\n errorKind: \"empty_content\",\n });\n return {\n verified: false,\n error: \"Could not read tweet content\",\n handle: null,\n };\n }\n\n const tweetText = data.tweet.text;\n const handle = data.tweet.author?.screen_name ?? parsed.screenName;\n\n const shortAddr = `${walletAddress.slice(0, 6)}...${walletAddress.slice(-4)}`;\n const hasAddress =\n tweetText.includes(shortAddr) ||\n tweetText.toLowerCase().includes(walletAddress.toLowerCase().slice(0, 10));\n const hasHashtag = tweetText.includes(\"#ElizaAgent\");\n\n if (!hasAddress) {\n return {\n verified: false,\n error:\n \"Tweet does not contain your wallet address. Make sure you copied the full verification message.\",\n handle,\n };\n }\n if (!hasHashtag) {\n return {\n verified: false,\n error: \"Tweet is missing #ElizaAgent hashtag.\",\n handle,\n };\n }\n\n verifySpan.success({ statusCode: response.status });\n return { verified: true, error: null, handle };\n}\n\n// ── Whitelist Storage ────────────────────────────────────────────────────\n\nfunction whitelistPath(): string {\n return path.join(resolveStateDir(), WHITELIST_FILE);\n}\n\nexport function loadWhitelist(): WhitelistData {\n const filePath = whitelistPath();\n if (!fs.existsSync(filePath)) return { verified: {} };\n const raw = fs.readFileSync(filePath, \"utf-8\");\n try {\n return JSON.parse(raw) as WhitelistData;\n } catch {\n logger.warn(\n `[twitter-verify] Corrupt whitelist file, resetting: ${filePath}`,\n );\n return { verified: {} };\n }\n}\n\nfunction saveWhitelist(data: WhitelistData): void {\n const filePath = whitelistPath();\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), {\n encoding: \"utf-8\",\n mode: 0o600,\n });\n}\n\nexport function markAddressVerified(\n address: string,\n tweetUrl: string,\n handle: string,\n): void {\n const wl = loadWhitelist();\n wl.verified[address.toLowerCase()] = {\n timestamp: new Date().toISOString(),\n tweetUrl,\n handle,\n };\n saveWhitelist(wl);\n logger.info(`[twitter-verify] Address ${address} verified via @${handle}`);\n}\n\nexport function isAddressWhitelisted(address: string): boolean {\n const wl = loadWhitelist();\n return address.toLowerCase() in wl.verified;\n}\n\nexport function getVerifiedAddresses(): string[] {\n const wl = loadWhitelist();\n return Object.keys(wl.verified);\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elizaos/plugin-elizamaker",
3
- "version": "2.0.3-beta.5",
3
+ "version": "2.0.3-beta.7",
4
4
  "type": "module",
5
5
  "description": "ElizaMaker: ERC-8041 NFT drop/mint/whitelist routes, Twitter-verified Merkle proofs, and OG code tracking.",
6
6
  "main": "./dist/index.js",
@@ -34,8 +34,8 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@elizaos/agent": "2.0.3-beta.5",
38
- "@elizaos/core": "2.0.3-beta.5",
37
+ "@elizaos/agent": "2.0.3-beta.7",
38
+ "@elizaos/core": "2.0.3-beta.7",
39
39
  "ethers": "^6.15.0"
40
40
  },
41
41
  "agentConfig": {
@@ -64,5 +64,5 @@
64
64
  "devDependencies": {
65
65
  "tsup": "^8.5.1"
66
66
  },
67
- "gitHead": "ff6157011c9459670021cc28a6797592a78b8817"
67
+ "gitHead": "61094f10458d11055c75b3dd0bae374e3f66bac5"
68
68
  }