agentlaunch-templates 0.1.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.
Files changed (37) hide show
  1. package/dist/generator.d.ts +43 -0
  2. package/dist/generator.d.ts.map +1 -0
  3. package/dist/generator.js +213 -0
  4. package/dist/generator.js.map +1 -0
  5. package/dist/index.d.ts +41 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +39 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/registry.d.ts +49 -0
  10. package/dist/registry.d.ts.map +1 -0
  11. package/dist/registry.js +47 -0
  12. package/dist/registry.js.map +1 -0
  13. package/dist/templates/custom.d.ts +11 -0
  14. package/dist/templates/custom.d.ts.map +1 -0
  15. package/dist/templates/custom.js +458 -0
  16. package/dist/templates/custom.js.map +1 -0
  17. package/dist/templates/data-analyzer.d.ts +11 -0
  18. package/dist/templates/data-analyzer.d.ts.map +1 -0
  19. package/dist/templates/data-analyzer.js +565 -0
  20. package/dist/templates/data-analyzer.js.map +1 -0
  21. package/dist/templates/gifter.d.ts +15 -0
  22. package/dist/templates/gifter.d.ts.map +1 -0
  23. package/dist/templates/gifter.js +717 -0
  24. package/dist/templates/gifter.js.map +1 -0
  25. package/dist/templates/price-monitor.d.ts +11 -0
  26. package/dist/templates/price-monitor.d.ts.map +1 -0
  27. package/dist/templates/price-monitor.js +577 -0
  28. package/dist/templates/price-monitor.js.map +1 -0
  29. package/dist/templates/research.d.ts +11 -0
  30. package/dist/templates/research.d.ts.map +1 -0
  31. package/dist/templates/research.js +593 -0
  32. package/dist/templates/research.js.map +1 -0
  33. package/dist/templates/trading-bot.d.ts +11 -0
  34. package/dist/templates/trading-bot.d.ts.map +1 -0
  35. package/dist/templates/trading-bot.js +559 -0
  36. package/dist/templates/trading-bot.js.map +1 -0
  37. package/package.json +24 -0
@@ -0,0 +1,565 @@
1
+ /**
2
+ * data-analyzer.ts — Serves structured data feeds and query results
3
+ *
4
+ * Platform constants (source of truth: deployed smart contracts):
5
+ * - Deploy fee: 120 FET (read dynamically, can change via multi-sig)
6
+ * - Graduation target: 30,000 FET -> auto DEX listing
7
+ * - Trading fee: 2% -> 100% to protocol treasury (NO creator fee)
8
+ */
9
+ export const template = {
10
+ name: "data-analyzer",
11
+ description: "Serves structured data feeds and query results from the AgentLaunch platform",
12
+ category: "Data",
13
+ variables: [
14
+ { name: "agent_name", required: true, description: "Name of the agent" },
15
+ {
16
+ name: "description",
17
+ default: "Serves structured data feeds and query results from the AgentLaunch platform",
18
+ description: "Short description of what this agent does",
19
+ },
20
+ {
21
+ name: "cache_ttl_seconds",
22
+ default: "300",
23
+ description: "How long to cache data feed results (seconds)",
24
+ },
25
+ {
26
+ name: "max_results",
27
+ default: "20",
28
+ description: "Maximum number of results to return per query",
29
+ },
30
+ {
31
+ name: "rate_limit_per_minute",
32
+ default: "20",
33
+ description: "Max requests per user per minute",
34
+ },
35
+ {
36
+ name: "free_requests_per_day",
37
+ default: "10",
38
+ description: "Free tier daily request quota",
39
+ },
40
+ {
41
+ name: "premium_token_threshold",
42
+ default: "1000",
43
+ description: "Token balance required for premium tier",
44
+ },
45
+ ],
46
+ dependencies: ["requests"],
47
+ secrets: ["AGENTVERSE_API_KEY", "AGENTLAUNCH_API_KEY", "AGENT_ADDRESS", "AGENT_OWNER_ADDRESS"],
48
+ code: `#!/usr/bin/env python3
49
+ """
50
+ {{agent_name}} — AgentLaunch Data Analyzer Agent
51
+ Generated by: agentlaunch scaffold {{agent_name}} --type data-analyzer
52
+
53
+ Serves structured data feeds from the AgentLaunch platform:
54
+ - Token listings (paginated, sorted by market cap)
55
+ - Individual token statistics
56
+ - Platform-wide market summary
57
+
58
+ Platform constants (source of truth: deployed smart contracts):
59
+ - Deploy fee: 120 FET (read dynamically, can change via multi-sig)
60
+ - Graduation target: 30,000 FET -> auto DEX listing
61
+ - Trading fee: 2% -> 100% to protocol treasury (NO creator fee)
62
+ """
63
+
64
+ from uagents import Agent, Context, Protocol
65
+ from uagents_core.contrib.protocols.chat import (
66
+ ChatAcknowledgement,
67
+ ChatMessage,
68
+ EndSessionContent,
69
+ TextContent,
70
+ chat_protocol_spec,
71
+ )
72
+
73
+ import json
74
+ import os
75
+ import time
76
+ from collections import defaultdict
77
+ from datetime import datetime
78
+ from typing import Any, Dict, List, Optional
79
+ from uuid import uuid4
80
+
81
+ import requests
82
+
83
+ # ==============================================================================
84
+ # API CONFIG — Override via environment variables, never hardcode
85
+ # ==============================================================================
86
+
87
+ AGENTLAUNCH_API = os.environ.get("AGENTLAUNCH_API", "https://agent-launch.ai/api")
88
+
89
+ # ==============================================================================
90
+ # BUSINESS CONFIG
91
+ # ==============================================================================
92
+
93
+ OWNER_ADDRESS = os.environ.get("AGENT_OWNER_ADDRESS", "")
94
+
95
+ BUSINESS = {
96
+ "name": "{{agent_name}}",
97
+ "description": "{{description}}",
98
+ "version": "1.0.0",
99
+ "cache_ttl_seconds": int("{{cache_ttl_seconds}}"),
100
+ "max_results": int("{{max_results}}"),
101
+ "free_requests_per_day": {{free_requests_per_day}},
102
+ "premium_token_threshold": {{premium_token_threshold}},
103
+ "rate_limit_per_minute": {{rate_limit_per_minute}},
104
+ "max_input_length": 5000,
105
+ }
106
+
107
+
108
+ # ==============================================================================
109
+ # LAYER 1: FOUNDATION
110
+ # ==============================================================================
111
+
112
+
113
+ class Logger:
114
+ """Structured logging with audit trail."""
115
+
116
+ @staticmethod
117
+ def info(ctx: Context, event: str, data: Optional[Dict] = None) -> None:
118
+ ctx.logger.info(f"[{event}] {json.dumps(data or {})}")
119
+
120
+ @staticmethod
121
+ def audit(ctx: Context, user: str, action: str) -> None:
122
+ ctx.logger.info(
123
+ f"[AUDIT] user={user[:20]} action={action} "
124
+ f"ts={datetime.utcnow().isoformat()}"
125
+ )
126
+
127
+ @staticmethod
128
+ def error(ctx: Context, event: str, error: str) -> None:
129
+ ctx.logger.error(f"[{event}] {error}")
130
+
131
+
132
+ # ==============================================================================
133
+ # LAYER 2: SECURITY
134
+ # ==============================================================================
135
+
136
+
137
+ class Security:
138
+ """Rate limiting and input validation."""
139
+
140
+ def __init__(self) -> None:
141
+ self._requests: Dict[str, List[float]] = defaultdict(list)
142
+ self._check_count: int = 0
143
+
144
+ def check(self, ctx: Context, user_id: str, message: str) -> tuple:
145
+ now = time.time()
146
+
147
+ self._requests[user_id] = [
148
+ t for t in self._requests[user_id] if now - t < 60
149
+ ]
150
+ if len(self._requests[user_id]) >= BUSINESS["rate_limit_per_minute"]:
151
+ return None, "Rate limit exceeded. Please wait a moment."
152
+ self._requests[user_id].append(now)
153
+
154
+ self._check_count += 1
155
+ if self._check_count % 100 == 0:
156
+ stale = [
157
+ k
158
+ for k, v in self._requests.items()
159
+ if not v or (now - max(v)) > 300
160
+ ]
161
+ for k in stale:
162
+ del self._requests[k]
163
+
164
+ if not message or not message.strip():
165
+ return None, "Empty message."
166
+ if len(message) > BUSINESS["max_input_length"]:
167
+ return None, f"Message too long (max {BUSINESS['max_input_length']} chars)."
168
+
169
+ return message.strip(), None
170
+
171
+
172
+ # ==============================================================================
173
+ # LAYER 3: STABILITY
174
+ # ==============================================================================
175
+
176
+
177
+ class Health:
178
+ """Track uptime and error rate."""
179
+
180
+ def __init__(self) -> None:
181
+ self._start: datetime = datetime.utcnow()
182
+ self._requests: int = 0
183
+ self._errors: int = 0
184
+
185
+ def record(self, success: bool) -> None:
186
+ self._requests += 1
187
+ if not success:
188
+ self._errors += 1
189
+
190
+ def status(self) -> Dict[str, Any]:
191
+ uptime = (datetime.utcnow() - self._start).total_seconds()
192
+ error_rate = (self._errors / self._requests * 100) if self._requests else 0
193
+ return {
194
+ "status": "healthy" if error_rate < 10 else "degraded",
195
+ "uptime_seconds": int(uptime),
196
+ "requests": self._requests,
197
+ "error_rate": f"{error_rate:.1f}%",
198
+ }
199
+
200
+
201
+ # ==============================================================================
202
+ # LAYER 4: SPEED
203
+ # ==============================================================================
204
+
205
+
206
+ class Cache:
207
+ """In-memory TTL cache."""
208
+
209
+ def __init__(self, max_size: int = 1000) -> None:
210
+ self._data: Dict[str, tuple] = {}
211
+ self._max_size: int = max_size
212
+
213
+ def get(self, key: str) -> Any:
214
+ if key in self._data:
215
+ value, expires = self._data[key]
216
+ if expires > time.time():
217
+ return value
218
+ del self._data[key]
219
+ return None
220
+
221
+ def set(self, key: str, value: Any, ttl: int = 300) -> None:
222
+ if len(self._data) >= self._max_size:
223
+ now = time.time()
224
+ expired = [k for k, (_, exp) in self._data.items() if exp <= now]
225
+ for k in expired:
226
+ del self._data[k]
227
+ if len(self._data) >= self._max_size:
228
+ to_drop = sorted(self._data.items(), key=lambda x: x[1][1])[
229
+ : self._max_size // 10
230
+ ]
231
+ for k, _ in to_drop:
232
+ del self._data[k]
233
+ self._data[key] = (value, time.time() + ttl)
234
+
235
+
236
+ # ==============================================================================
237
+ # LAYER 5: REVENUE
238
+ # ==============================================================================
239
+
240
+
241
+ class Revenue:
242
+ """Token-gated access and daily usage quotas."""
243
+
244
+ def __init__(self, cache: Cache) -> None:
245
+ self._cache = cache
246
+ self._usage: Dict[str, List[str]] = defaultdict(list)
247
+
248
+ def get_tier(self, user_address: str) -> str:
249
+ cached = self._cache.get(f"tier:{user_address}")
250
+ if cached is not None:
251
+ return cached
252
+ try:
253
+ r = requests.get(
254
+ f"{AGENTLAUNCH_API}/agents/token/{user_address}", timeout=5
255
+ )
256
+ if r.status_code == 200:
257
+ data = r.json()
258
+ balance = data.get("balance", 0)
259
+ tier = (
260
+ "premium"
261
+ if balance >= BUSINESS["premium_token_threshold"]
262
+ else "free"
263
+ )
264
+ self._cache.set(f"tier:{user_address}", tier, ttl=300)
265
+ return tier
266
+ except Exception:
267
+ pass
268
+ return "free"
269
+
270
+ def check_quota(self, user_id: str, tier: str) -> tuple:
271
+ today = datetime.utcnow().date().isoformat()
272
+ self._usage[user_id] = [
273
+ t for t in self._usage[user_id] if t.startswith(today)
274
+ ]
275
+ today_usage = len(self._usage[user_id])
276
+ limit = 1000 if tier == "premium" else BUSINESS["free_requests_per_day"]
277
+ if today_usage >= limit:
278
+ if tier == "free":
279
+ return False, (
280
+ f"Free limit reached ({limit}/day). "
281
+ f"Hold {BUSINESS['premium_token_threshold']} tokens for premium!"
282
+ )
283
+ return False, f"Daily limit reached ({limit}/day)."
284
+ self._usage[user_id].append(datetime.utcnow().isoformat())
285
+ return True, None
286
+
287
+
288
+ # ==============================================================================
289
+ # AGENTLAUNCH INTEGRATION
290
+ # ==============================================================================
291
+
292
+
293
+ class AgentLaunch:
294
+ """Create and manage tokens on AgentLaunch."""
295
+
296
+ @staticmethod
297
+ def tokenize() -> Dict:
298
+ agent_address = os.environ.get("AGENT_ADDRESS")
299
+ if not agent_address:
300
+ return {"error": "AGENT_ADDRESS env var not set."}
301
+ try:
302
+ r = requests.post(
303
+ f"{AGENTLAUNCH_API}/agents/tokenize",
304
+ headers={
305
+ "X-API-Key": os.environ.get("AGENTLAUNCH_API_KEY", ""),
306
+ "Content-Type": "application/json",
307
+ },
308
+ json={
309
+ "agentAddress": agent_address,
310
+ "name": BUSINESS["name"],
311
+ "description": BUSINESS["description"],
312
+ },
313
+ timeout=30,
314
+ )
315
+ return r.json() if r.status_code in [200, 201] else {"error": r.text}
316
+ except Exception as e:
317
+ return {"error": str(e)}
318
+
319
+
320
+ # ==============================================================================
321
+ # DATA ANALYZER BUSINESS LOGIC
322
+ # ==============================================================================
323
+
324
+
325
+ class DataAnalyzerBusiness:
326
+ """
327
+ Queries the AgentLaunch REST API and returns structured data:
328
+ - Token listings sorted by market cap
329
+ - Individual token detail
330
+ - Platform summary statistics
331
+
332
+ All results are cached locally to avoid hammering the API.
333
+
334
+ Note: Trading fee is 2% -> 100% to protocol treasury (no creator fee).
335
+ """
336
+
337
+ def __init__(self, cache: Cache) -> None:
338
+ self._cache = cache
339
+
340
+ def fetch_tokens(self, page: int = 1) -> Optional[List[Dict]]:
341
+ cache_key = f"tokens:page:{page}"
342
+ cached = self._cache.get(cache_key)
343
+ if cached is not None:
344
+ return cached
345
+ try:
346
+ r = requests.get(
347
+ f"{AGENTLAUNCH_API}/agents/tokens",
348
+ params={"page": page, "limit": BUSINESS["max_results"]},
349
+ timeout=10,
350
+ )
351
+ if r.status_code == 200:
352
+ data = r.json()
353
+ tokens = data.get("data") or data.get("tokens") or data
354
+ if isinstance(tokens, list):
355
+ self._cache.set(cache_key, tokens, ttl=BUSINESS["cache_ttl_seconds"])
356
+ return tokens
357
+ except Exception:
358
+ pass
359
+ return None
360
+
361
+ def fetch_token(self, address: str) -> Optional[Dict]:
362
+ cache_key = f"token:{address}"
363
+ cached = self._cache.get(cache_key)
364
+ if cached is not None:
365
+ return cached
366
+ try:
367
+ r = requests.get(
368
+ f"{AGENTLAUNCH_API}/agents/token/{address}", timeout=10
369
+ )
370
+ if r.status_code == 200:
371
+ data = r.json()
372
+ token = data.get("data") or data
373
+ if isinstance(token, dict):
374
+ self._cache.set(cache_key, token, ttl=BUSINESS["cache_ttl_seconds"])
375
+ return token
376
+ except Exception:
377
+ pass
378
+ return None
379
+
380
+ def format_token_row(self, token: Dict, index: int) -> str:
381
+ name = token.get("name", "Unknown")[:20]
382
+ symbol = token.get("symbol", "???")[:8]
383
+ price = token.get("price") or token.get("currentPrice") or 0
384
+ market_cap = token.get("marketCap") or token.get("market_cap") or 0
385
+ return f"{index:>3}. {name:<22} ({symbol:<8}) | {float(price):.6f} FET | MC: {float(market_cap):,.0f} FET"
386
+
387
+ async def handle(self, ctx: Context, user_id: str, message: str, tier: str) -> str:
388
+ lower = message.lower()
389
+
390
+ # "tokens" or "list" — paginated token listing
391
+ if lower in ("tokens", "list", "top"):
392
+ tokens = self.fetch_tokens(page=1)
393
+ if tokens is None:
394
+ return "Could not fetch token listing. Please try again."
395
+ if not tokens:
396
+ return "No tokens found."
397
+ lines = ["**Top Tokens by Market Cap**\\n"]
398
+ for i, tok in enumerate(tokens[: BUSINESS["max_results"]], start=1):
399
+ lines.append(self.format_token_row(tok, i))
400
+ lines.append(f"\\nShowing {len(tokens)} tokens. Cache TTL: {BUSINESS['cache_ttl_seconds']}s")
401
+ return "\\n".join(lines)
402
+
403
+ # "token <address>" — single token detail
404
+ if lower.startswith("token "):
405
+ parts = message.split()
406
+ if len(parts) >= 2:
407
+ address = parts[1].strip()
408
+ token = self.fetch_token(address)
409
+ if token is None:
410
+ return f"Could not find token at address {address}."
411
+ name = token.get("name", "Unknown")
412
+ symbol = token.get("symbol", "???")
413
+ price = token.get("price") or token.get("currentPrice") or 0
414
+ market_cap = token.get("marketCap") or token.get("market_cap") or 0
415
+ listed = token.get("listed") or token.get("isListed") or False
416
+ description = token.get("description", "N/A")[:200]
417
+ return (
418
+ f"**{name}** ({symbol})\\n"
419
+ f"Address: {address}\\n"
420
+ f"Price: {float(price):.6f} FET\\n"
421
+ f"Market Cap: {float(market_cap):,.0f} FET\\n"
422
+ f"Listed on DEX: {'Yes' if listed else 'No'}\\n"
423
+ f"Graduation target: 30,000 FET\\n"
424
+ f"Description: {description}"
425
+ )
426
+
427
+ return (
428
+ f"Welcome to {BUSINESS['name']}!\\n\\n"
429
+ f"Commands:\\n"
430
+ f" tokens — list top tokens by market cap\\n"
431
+ f" token <address> — get detail for a specific token\\n\\n"
432
+ f"Platform: agent-launch.ai | Fee: 2% -> 100% protocol treasury"
433
+ )
434
+
435
+
436
+ # ==============================================================================
437
+ # REPLY HELPER
438
+ # ==============================================================================
439
+
440
+
441
+ async def reply(ctx: Context, sender: str, text: str, end: bool = False) -> None:
442
+ content = [TextContent(type="text", text=text)]
443
+ if end:
444
+ content.append(EndSessionContent(type="end-session"))
445
+ try:
446
+ await ctx.send(
447
+ sender,
448
+ ChatMessage(timestamp=datetime.utcnow(), msg_id=uuid4(), content=content),
449
+ )
450
+ except Exception as e:
451
+ ctx.logger.error(f"Failed to send reply to {sender[:20]}: {e}")
452
+
453
+
454
+ # ==============================================================================
455
+ # MAIN AGENT
456
+ # ==============================================================================
457
+
458
+ cache = Cache(max_size=1000)
459
+ security = Security()
460
+ health = Health()
461
+ revenue = Revenue(cache)
462
+ business = DataAnalyzerBusiness(cache)
463
+
464
+ agent = Agent()
465
+ chat_proto = Protocol(spec=chat_protocol_spec)
466
+
467
+
468
+ @chat_proto.on_message(ChatMessage)
469
+ async def handle_chat(ctx: Context, sender: str, msg: ChatMessage) -> None:
470
+ try:
471
+ await ctx.send(
472
+ sender,
473
+ ChatAcknowledgement(
474
+ timestamp=datetime.utcnow(), acknowledged_msg_id=msg.msg_id
475
+ ),
476
+ )
477
+ except Exception as e:
478
+ ctx.logger.error(f"Failed to send ack to {sender[:20]}: {e}")
479
+
480
+ text = " ".join(
481
+ item.text for item in msg.content if isinstance(item, TextContent)
482
+ ).strip()
483
+ text = text[: BUSINESS["max_input_length"]]
484
+
485
+ clean, error = security.check(ctx, sender, text)
486
+ if error:
487
+ health.record(False)
488
+ await reply(ctx, sender, error, end=True)
489
+ return
490
+
491
+ Logger.audit(ctx, sender, "request")
492
+
493
+ lower = clean.lower()
494
+
495
+ if lower in ("help", "?"):
496
+ tier = revenue.get_tier(sender)
497
+ await reply(
498
+ ctx,
499
+ sender,
500
+ f"**{BUSINESS['name']}** v{BUSINESS['version']}\\n\\n"
501
+ f"{BUSINESS['description']}\\n\\n"
502
+ f"Your tier: {tier.upper()}\\n\\n"
503
+ f"Commands: help, status, tokenize, tokens, token <addr>",
504
+ )
505
+ return
506
+
507
+ if lower == "status":
508
+ s = health.status()
509
+ await reply(
510
+ ctx,
511
+ sender,
512
+ f"Status: {s['status']} | Uptime: {s['uptime_seconds']}s | "
513
+ f"Requests: {s['requests']} | Error rate: {s['error_rate']}",
514
+ )
515
+ return
516
+
517
+ if "tokenize" in lower:
518
+ if OWNER_ADDRESS and sender != OWNER_ADDRESS:
519
+ await reply(ctx, sender, "Only the agent owner can trigger tokenization.", end=True)
520
+ return
521
+ result = AgentLaunch.tokenize()
522
+ link = result.get("data", {}).get("handoff_link") or result.get("handoff_link")
523
+ await reply(
524
+ ctx,
525
+ sender,
526
+ f"Token created! Deploy here: {link}" if link else f"Result: {json.dumps(result)}",
527
+ end=True,
528
+ )
529
+ return
530
+
531
+ tier = revenue.get_tier(sender)
532
+ allowed, quota_error = revenue.check_quota(sender, tier)
533
+ if not allowed:
534
+ health.record(False)
535
+ await reply(ctx, sender, quota_error, end=True)
536
+ return
537
+
538
+ try:
539
+ response = await business.handle(ctx, sender, clean, tier)
540
+ health.record(True)
541
+ except Exception as e:
542
+ health.record(False)
543
+ Logger.error(ctx, "business_handle", str(e))
544
+ response = "Something went wrong. Please try again."
545
+
546
+ await reply(ctx, sender, response, end=True)
547
+
548
+
549
+ @chat_proto.on_message(ChatAcknowledgement)
550
+ async def handle_ack(ctx: Context, sender: str, msg: ChatAcknowledgement) -> None:
551
+ ctx.logger.debug(f"Ack from {sender[:20]} for msg {msg.acknowledged_msg_id}")
552
+
553
+
554
+ @agent.on_interval(period=3600)
555
+ async def periodic_health(ctx: Context) -> None:
556
+ ctx.logger.info(f"[HEALTH] {json.dumps(health.status())}")
557
+
558
+
559
+ agent.include(chat_proto, publish_manifest=True)
560
+
561
+ if __name__ == "__main__":
562
+ agent.run()
563
+ `,
564
+ };
565
+ //# sourceMappingURL=data-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-analyzer.js","sourceRoot":"","sources":["../../src/templates/data-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,8EAA8E;IAC3F,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE;QACxE;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,8EAA8E;YACvF,WAAW,EAAE,2CAA2C;SACzD;QACD;YACE,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,+CAA+C;SAC7D;QACD;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,+CAA+C;SAC7D;QACD;YACE,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,kCAAkC;SAChD;QACD;YACE,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,+BAA+B;SAC7C;QACD;YACE,IAAI,EAAE,yBAAyB;YAC/B,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,yCAAyC;SACvD;KACF;IACD,YAAY,EAAE,CAAC,UAAU,CAAC;IAC1B,OAAO,EAAE,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,eAAe,EAAE,qBAAqB,CAAC;IAC9F,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmgBP;CACA,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * gifter.ts — FET Gifter pattern: distributes testnet FET and BNB to new developers
3
+ *
4
+ * This template is based on the FET Gifter agent pattern (faucet type from
5
+ * packages/cli/src/commands/scaffold.ts). It adapts the gifter use case for
6
+ * Agentverse-native deployment with Chat Protocol v0.3.0.
7
+ *
8
+ * Platform constants (source of truth: deployed smart contracts):
9
+ * - Deploy fee: 120 FET (read dynamically, can change via multi-sig)
10
+ * - Graduation target: 30,000 FET -> auto DEX listing
11
+ * - Trading fee: 2% -> 100% to protocol treasury (NO creator fee)
12
+ */
13
+ import type { AgentTemplate } from "../registry.js";
14
+ export declare const template: AgentTemplate;
15
+ //# sourceMappingURL=gifter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gifter.d.ts","sourceRoot":"","sources":["../../src/templates/gifter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,eAAO,MAAM,QAAQ,EAAE,aAgsBtB,CAAC"}