agentlaunch-templates 0.4.2 → 0.4.4
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/__tests__/build.test.d.ts +1 -1
- package/dist/__tests__/build.test.js +5 -5
- package/dist/__tests__/build.test.js.map +1 -1
- package/dist/__tests__/consumer-commerce.test.d.ts +11 -0
- package/dist/__tests__/consumer-commerce.test.d.ts.map +1 -0
- package/dist/__tests__/consumer-commerce.test.js +118 -0
- package/dist/__tests__/consumer-commerce.test.js.map +1 -0
- package/dist/__tests__/swarm-starter-integration.test.d.ts +12 -0
- package/dist/__tests__/swarm-starter-integration.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-starter-integration.test.js +143 -0
- package/dist/__tests__/swarm-starter-integration.test.js.map +1 -0
- package/dist/__tests__/swarm-starter.test.d.ts +16 -0
- package/dist/__tests__/swarm-starter.test.d.ts.map +1 -0
- package/dist/__tests__/swarm-starter.test.js +310 -0
- package/dist/__tests__/swarm-starter.test.js.map +1 -0
- package/dist/claude-context.d.ts +1 -1
- package/dist/claude-context.d.ts.map +1 -1
- package/dist/claude-context.js +55 -49
- package/dist/claude-context.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/people.d.ts +108 -0
- package/dist/people.d.ts.map +1 -0
- package/dist/people.js +563 -0
- package/dist/people.js.map +1 -0
- package/dist/presets.d.ts +13 -13
- package/dist/presets.d.ts.map +1 -1
- package/dist/presets.js +331 -96
- package/dist/presets.js.map +1 -1
- package/dist/registry.d.ts +3 -8
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +8 -28
- package/dist/registry.js.map +1 -1
- package/dist/templates/chat-memory.d.ts +5 -14
- package/dist/templates/chat-memory.d.ts.map +1 -1
- package/dist/templates/chat-memory.js +142 -220
- package/dist/templates/chat-memory.js.map +1 -1
- package/dist/templates/consumer-commerce.d.ts +14 -0
- package/dist/templates/consumer-commerce.d.ts.map +1 -0
- package/dist/templates/consumer-commerce.js +439 -0
- package/dist/templates/consumer-commerce.js.map +1 -0
- package/dist/templates/genesis.d.ts.map +1 -1
- package/dist/templates/genesis.js +10 -0
- package/dist/templates/genesis.js.map +1 -1
- package/dist/templates/swarm-starter.d.ts +26 -0
- package/dist/templates/swarm-starter.d.ts.map +1 -0
- package/dist/templates/swarm-starter.js +1421 -0
- package/dist/templates/swarm-starter.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* consumer-commerce.ts — Consumer-facing agent template with multi-token payments
|
|
3
|
+
*
|
|
4
|
+
* Extends the swarm-starter commerce stack with:
|
|
5
|
+
* - MultiTokenPricingTable (FET + USDC pricing)
|
|
6
|
+
* - InvoiceManager (create/verify/list invoices in ctx.storage)
|
|
7
|
+
* - FiatOnrampHelper (detect "no crypto" → generate card purchase link)
|
|
8
|
+
* - DelegationChecker (verify allowance → auto-pay or fall back to RequestPayment)
|
|
9
|
+
*
|
|
10
|
+
* No custom smart contracts — uses standard ERC-20 approve/transferFrom.
|
|
11
|
+
*/
|
|
12
|
+
const PROD_API_URL = 'https://agent-launch.ai/api';
|
|
13
|
+
const DEV_API_URL = 'https://launchpad-backend-dev-1056182620041.us-central1.run.app';
|
|
14
|
+
const RESOLVED_API_URL = process.env.AGENT_LAUNCH_API_URL ??
|
|
15
|
+
(process.env.AGENT_LAUNCH_ENV === 'dev' ? DEV_API_URL : PROD_API_URL);
|
|
16
|
+
export const template = {
|
|
17
|
+
name: "consumer-commerce",
|
|
18
|
+
description: "Consumer-facing agent with multi-token payments, invoices, fiat onramp, and spending delegation",
|
|
19
|
+
category: "Commerce",
|
|
20
|
+
variables: [
|
|
21
|
+
{ name: "agent_name", required: true, description: "Name of the agent" },
|
|
22
|
+
{ name: "description", required: true, description: "Short description of what this agent does" },
|
|
23
|
+
{ name: "service_price_fet", default: "0.01", description: "Service price in FET" },
|
|
24
|
+
{ name: "service_price_usdc", default: "0.05", description: "Service price in USDC" },
|
|
25
|
+
{ name: "accepted_tokens", default: "FET,USDC", description: "Comma-separated accepted token symbols" },
|
|
26
|
+
{ name: "enable_fiat_onramp", default: "true", description: "Enable fiat onramp link generation" },
|
|
27
|
+
{ name: "enable_invoices", default: "true", description: "Enable invoice management" },
|
|
28
|
+
{ name: "enable_delegation", default: "true", description: "Enable spending delegation (auto-pay)" },
|
|
29
|
+
],
|
|
30
|
+
dependencies: ["requests", "web3"],
|
|
31
|
+
secrets: [
|
|
32
|
+
"AGENTVERSE_API_KEY",
|
|
33
|
+
"AGENTLAUNCH_API_KEY",
|
|
34
|
+
"WALLET_PRIVATE_KEY",
|
|
35
|
+
"MOONPAY_API_KEY",
|
|
36
|
+
],
|
|
37
|
+
code: `#!/usr/bin/env python3
|
|
38
|
+
"""
|
|
39
|
+
{{agent_name}} — AgentLaunch Consumer Commerce Agent
|
|
40
|
+
Generated by: agentlaunch scaffold {{agent_name}} --type consumer-commerce
|
|
41
|
+
|
|
42
|
+
Multi-token payments (FET + USDC), invoices, fiat onramp, spending delegation.
|
|
43
|
+
Uses standard ERC-20 patterns — no custom smart contracts.
|
|
44
|
+
|
|
45
|
+
Platform constants (source of truth: deployed smart contracts):
|
|
46
|
+
- Deploy fee: 120 FET (read dynamically, can change via multi-sig)
|
|
47
|
+
- Graduation target: 30,000 FET -> auto DEX listing
|
|
48
|
+
- Trading fee: 2% -> 100% to protocol treasury (NO creator fee)
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
from uagents import Agent, Context, Protocol
|
|
52
|
+
from uagents_core.contrib.protocols.chat import (
|
|
53
|
+
ChatAcknowledgement,
|
|
54
|
+
ChatMessage,
|
|
55
|
+
EndSessionContent,
|
|
56
|
+
TextContent,
|
|
57
|
+
chat_protocol_spec,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
import json
|
|
61
|
+
import os
|
|
62
|
+
from datetime import datetime
|
|
63
|
+
from uuid import uuid4
|
|
64
|
+
|
|
65
|
+
# ==============================================================================
|
|
66
|
+
# CONFIG
|
|
67
|
+
# ==============================================================================
|
|
68
|
+
|
|
69
|
+
AGENTLAUNCH_API = os.environ.get("AGENTLAUNCH_API", "${RESOLVED_API_URL}")
|
|
70
|
+
|
|
71
|
+
BUSINESS = {
|
|
72
|
+
"name": "{{agent_name}}",
|
|
73
|
+
"description": "{{description}}",
|
|
74
|
+
"version": "1.0.0",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ACCEPTED_TOKENS = [t.strip() for t in "{{accepted_tokens}}".split(",")]
|
|
78
|
+
|
|
79
|
+
# ==============================================================================
|
|
80
|
+
# MULTI-TOKEN PRICING TABLE
|
|
81
|
+
# ==============================================================================
|
|
82
|
+
|
|
83
|
+
class MultiTokenPricingTable:
|
|
84
|
+
"""Service pricing in multiple tokens (FET + USDC)."""
|
|
85
|
+
|
|
86
|
+
def __init__(self, ctx: Context):
|
|
87
|
+
self.ctx = ctx
|
|
88
|
+
|
|
89
|
+
async def get_prices(self) -> dict:
|
|
90
|
+
"""Get current pricing table from storage."""
|
|
91
|
+
raw = self.ctx.storage.get("pricing_table")
|
|
92
|
+
if raw:
|
|
93
|
+
return json.loads(raw)
|
|
94
|
+
# Default pricing
|
|
95
|
+
return {
|
|
96
|
+
"default": {
|
|
97
|
+
"FET": "{{service_price_fet}}",
|
|
98
|
+
"USDC": "{{service_price_usdc}}",
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async def set_price(self, service: str, token: str, price: str):
|
|
103
|
+
"""Set price for a service in a specific token."""
|
|
104
|
+
prices = await self.get_prices()
|
|
105
|
+
if service not in prices:
|
|
106
|
+
prices[service] = {}
|
|
107
|
+
prices[service][token] = price
|
|
108
|
+
self.ctx.storage.set("pricing_table", json.dumps(prices))
|
|
109
|
+
|
|
110
|
+
async def format_prices(self, service: str = "default") -> str:
|
|
111
|
+
"""Format prices for display."""
|
|
112
|
+
prices = await self.get_prices()
|
|
113
|
+
svc_prices = prices.get(service, prices.get("default", {}))
|
|
114
|
+
lines = []
|
|
115
|
+
for token, price in svc_prices.items():
|
|
116
|
+
if token in ACCEPTED_TOKENS:
|
|
117
|
+
lines.append(f" {price} {token}")
|
|
118
|
+
return "\\n".join(lines) if lines else " Free"
|
|
119
|
+
|
|
120
|
+
# ==============================================================================
|
|
121
|
+
# INVOICE MANAGER
|
|
122
|
+
# ==============================================================================
|
|
123
|
+
|
|
124
|
+
class InvoiceManager:
|
|
125
|
+
"""Create, verify, and list invoices in ctx.storage."""
|
|
126
|
+
|
|
127
|
+
def __init__(self, ctx: Context):
|
|
128
|
+
self.ctx = ctx
|
|
129
|
+
|
|
130
|
+
async def create(self, payer: str, service: str, amount: str, token: str = "FET") -> dict:
|
|
131
|
+
"""Create a new invoice."""
|
|
132
|
+
invoice_id = f"inv_{uuid4().hex[:8]}"
|
|
133
|
+
invoice = {
|
|
134
|
+
"id": invoice_id,
|
|
135
|
+
"issuer": str(self.ctx.address),
|
|
136
|
+
"payer": payer,
|
|
137
|
+
"service": service,
|
|
138
|
+
"amount": amount,
|
|
139
|
+
"token": token,
|
|
140
|
+
"status": "pending",
|
|
141
|
+
"created_at": datetime.now().isoformat(),
|
|
142
|
+
"updated_at": datetime.now().isoformat(),
|
|
143
|
+
}
|
|
144
|
+
self.ctx.storage.set(f"invoice_{invoice_id}", json.dumps(invoice))
|
|
145
|
+
|
|
146
|
+
# Update index
|
|
147
|
+
index_raw = self.ctx.storage.get("invoice_index")
|
|
148
|
+
index = json.loads(index_raw) if index_raw else []
|
|
149
|
+
index.append(invoice_id)
|
|
150
|
+
self.ctx.storage.set("invoice_index", json.dumps(index))
|
|
151
|
+
|
|
152
|
+
return invoice
|
|
153
|
+
|
|
154
|
+
async def get(self, invoice_id: str) -> dict | None:
|
|
155
|
+
"""Get an invoice by ID."""
|
|
156
|
+
raw = self.ctx.storage.get(f"invoice_{invoice_id}")
|
|
157
|
+
return json.loads(raw) if raw else None
|
|
158
|
+
|
|
159
|
+
async def list_invoices(self, status: str = None) -> list:
|
|
160
|
+
"""List all invoices, optionally filtered by status."""
|
|
161
|
+
index_raw = self.ctx.storage.get("invoice_index")
|
|
162
|
+
if not index_raw:
|
|
163
|
+
return []
|
|
164
|
+
index = json.loads(index_raw)
|
|
165
|
+
invoices = []
|
|
166
|
+
for inv_id in index:
|
|
167
|
+
inv = await self.get(inv_id)
|
|
168
|
+
if inv and (status is None or inv.get("status") == status):
|
|
169
|
+
invoices.append(inv)
|
|
170
|
+
return invoices
|
|
171
|
+
|
|
172
|
+
async def mark_paid(self, invoice_id: str, tx_hash: str) -> dict | None:
|
|
173
|
+
"""Mark an invoice as paid."""
|
|
174
|
+
inv = await self.get(invoice_id)
|
|
175
|
+
if not inv:
|
|
176
|
+
return None
|
|
177
|
+
inv["status"] = "paid"
|
|
178
|
+
inv["tx_hash"] = tx_hash
|
|
179
|
+
inv["updated_at"] = datetime.now().isoformat()
|
|
180
|
+
self.ctx.storage.set(f"invoice_{invoice_id}", json.dumps(inv))
|
|
181
|
+
return inv
|
|
182
|
+
|
|
183
|
+
# ==============================================================================
|
|
184
|
+
# FIAT ONRAMP HELPER
|
|
185
|
+
# ==============================================================================
|
|
186
|
+
|
|
187
|
+
class FiatOnrampHelper:
|
|
188
|
+
"""Generate fiat-to-crypto purchase links for users without crypto."""
|
|
189
|
+
|
|
190
|
+
PROVIDERS = {
|
|
191
|
+
"moonpay": "https://buy.moonpay.com",
|
|
192
|
+
"transak": "https://global.transak.com",
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
CRYPTO_CODES = {
|
|
196
|
+
"FET": {"moonpay": "fet_bsc", "transak": "FET"},
|
|
197
|
+
"USDC": {"moonpay": "usdc_bsc", "transak": "USDC"},
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
def __init__(self, ctx: Context):
|
|
201
|
+
self.ctx = ctx
|
|
202
|
+
self.enabled = "{{enable_fiat_onramp}}" == "true"
|
|
203
|
+
|
|
204
|
+
def generate_link(
|
|
205
|
+
self,
|
|
206
|
+
wallet_address: str,
|
|
207
|
+
fiat_amount: str = "50",
|
|
208
|
+
fiat_currency: str = "USD",
|
|
209
|
+
crypto_token: str = "FET",
|
|
210
|
+
provider: str = "moonpay",
|
|
211
|
+
) -> str | None:
|
|
212
|
+
"""Generate a fiat onramp URL."""
|
|
213
|
+
if not self.enabled:
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
codes = self.CRYPTO_CODES.get(crypto_token.upper())
|
|
217
|
+
if not codes:
|
|
218
|
+
return None
|
|
219
|
+
|
|
220
|
+
base_url = self.PROVIDERS.get(provider)
|
|
221
|
+
if not base_url:
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
api_key = os.environ.get("MOONPAY_API_KEY", "")
|
|
225
|
+
|
|
226
|
+
if provider == "moonpay":
|
|
227
|
+
return (
|
|
228
|
+
f"{base_url}?"
|
|
229
|
+
f"apiKey={api_key}&"
|
|
230
|
+
f"currencyCode={codes['moonpay']}&"
|
|
231
|
+
f"baseCurrencyCode={fiat_currency.lower()}&"
|
|
232
|
+
f"baseCurrencyAmount={fiat_amount}&"
|
|
233
|
+
f"walletAddress={wallet_address}"
|
|
234
|
+
)
|
|
235
|
+
else:
|
|
236
|
+
return (
|
|
237
|
+
f"{base_url}?"
|
|
238
|
+
f"apiKey={api_key}&"
|
|
239
|
+
f"cryptoCurrencyCode={codes['transak']}&"
|
|
240
|
+
f"fiatCurrency={fiat_currency.upper()}&"
|
|
241
|
+
f"fiatAmount={fiat_amount}&"
|
|
242
|
+
f"walletAddress={wallet_address}&"
|
|
243
|
+
f"network=bsc"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# ==============================================================================
|
|
247
|
+
# DELEGATION CHECKER
|
|
248
|
+
# ==============================================================================
|
|
249
|
+
|
|
250
|
+
class DelegationChecker:
|
|
251
|
+
"""Check ERC-20 allowances for auto-pay from delegated spending limits."""
|
|
252
|
+
|
|
253
|
+
def __init__(self, ctx: Context):
|
|
254
|
+
self.ctx = ctx
|
|
255
|
+
self.enabled = "{{enable_delegation}}" == "true"
|
|
256
|
+
|
|
257
|
+
async def check_delegation(self, owner: str, token_address: str) -> str:
|
|
258
|
+
"""Check allowance on-chain. Returns remaining allowance as string."""
|
|
259
|
+
if not self.enabled:
|
|
260
|
+
return "0"
|
|
261
|
+
|
|
262
|
+
# Store delegation status in ctx.storage for tracking
|
|
263
|
+
key = f"delegation_{owner}_{token_address[:8]}"
|
|
264
|
+
raw = self.ctx.storage.get(key)
|
|
265
|
+
if raw:
|
|
266
|
+
return json.loads(raw).get("remaining", "0")
|
|
267
|
+
return "0"
|
|
268
|
+
|
|
269
|
+
async def record_delegation(self, owner: str, token_address: str, amount: str):
|
|
270
|
+
"""Record a delegation grant in storage."""
|
|
271
|
+
key = f"delegation_{owner}_{token_address[:8]}"
|
|
272
|
+
self.ctx.storage.set(key, json.dumps({
|
|
273
|
+
"owner": owner,
|
|
274
|
+
"token_address": token_address,
|
|
275
|
+
"remaining": amount,
|
|
276
|
+
"updated_at": datetime.now().isoformat(),
|
|
277
|
+
}))
|
|
278
|
+
|
|
279
|
+
# ==============================================================================
|
|
280
|
+
# REVENUE TRACKER
|
|
281
|
+
# ==============================================================================
|
|
282
|
+
|
|
283
|
+
class RevenueTracker:
|
|
284
|
+
"""Track income and expenses by token."""
|
|
285
|
+
|
|
286
|
+
def __init__(self, ctx: Context):
|
|
287
|
+
self.ctx = ctx
|
|
288
|
+
|
|
289
|
+
async def record_income(self, amount: str, token: str, service: str, payer: str):
|
|
290
|
+
"""Record an income event."""
|
|
291
|
+
raw = self.ctx.storage.get("revenue_summary") or "{}"
|
|
292
|
+
summary = json.loads(raw)
|
|
293
|
+
|
|
294
|
+
by_token = summary.get("by_token", {})
|
|
295
|
+
if token not in by_token:
|
|
296
|
+
by_token[token] = {"income": 0.0, "expenses": 0.0}
|
|
297
|
+
by_token[token]["income"] += float(amount)
|
|
298
|
+
summary["by_token"] = by_token
|
|
299
|
+
summary["total_income"] = summary.get("total_income", 0.0) + float(amount)
|
|
300
|
+
summary["transaction_count"] = summary.get("transaction_count", 0) + 1
|
|
301
|
+
summary["last_updated"] = datetime.now().isoformat()
|
|
302
|
+
|
|
303
|
+
self.ctx.storage.set("revenue_summary", json.dumps(summary))
|
|
304
|
+
|
|
305
|
+
async def get_summary(self) -> dict:
|
|
306
|
+
"""Get revenue summary."""
|
|
307
|
+
raw = self.ctx.storage.get("revenue_summary") or "{}"
|
|
308
|
+
return json.loads(raw)
|
|
309
|
+
|
|
310
|
+
# ==============================================================================
|
|
311
|
+
# AGENT SETUP
|
|
312
|
+
# ==============================================================================
|
|
313
|
+
|
|
314
|
+
agent = Agent()
|
|
315
|
+
chat_proto = Protocol(spec=chat_protocol_spec)
|
|
316
|
+
|
|
317
|
+
# ==============================================================================
|
|
318
|
+
# CHAT HANDLER — COMMERCE FLOW
|
|
319
|
+
# ==============================================================================
|
|
320
|
+
|
|
321
|
+
@chat_proto.on_message(ChatMessage)
|
|
322
|
+
async def handle_message(ctx: Context, sender: str, msg: ChatMessage):
|
|
323
|
+
ctx.logger.info(f"Message from {sender}")
|
|
324
|
+
text = msg.content[0].text.strip() if msg.content else ""
|
|
325
|
+
lower = text.lower()
|
|
326
|
+
|
|
327
|
+
pricing = MultiTokenPricingTable(ctx)
|
|
328
|
+
invoices = InvoiceManager(ctx)
|
|
329
|
+
fiat = FiatOnrampHelper(ctx)
|
|
330
|
+
revenue = RevenueTracker(ctx)
|
|
331
|
+
|
|
332
|
+
# --- Commands ---
|
|
333
|
+
|
|
334
|
+
if lower in ("help", "/help"):
|
|
335
|
+
prices = await pricing.format_prices()
|
|
336
|
+
response = (
|
|
337
|
+
f"**{BUSINESS['name']}** — {BUSINESS['description']}\\n\\n"
|
|
338
|
+
f"**Pricing:**\\n{prices}\\n\\n"
|
|
339
|
+
f"**Commands:**\\n"
|
|
340
|
+
f" \`help\` — Show this message\\n"
|
|
341
|
+
f" \`prices\` — View pricing in all tokens\\n"
|
|
342
|
+
f" \`invoice <service>\` — Create an invoice\\n"
|
|
343
|
+
f" \`buy-crypto\` — Get a link to buy crypto with a card\\n"
|
|
344
|
+
f" \`revenue\` — View earnings\\n"
|
|
345
|
+
f" \`status\` — Service status\\n\\n"
|
|
346
|
+
f"**Accepted tokens:** {', '.join(ACCEPTED_TOKENS)}"
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
elif lower == "prices":
|
|
350
|
+
prices = await pricing.format_prices()
|
|
351
|
+
response = f"**Current Pricing:**\\n{prices}\\n\\n**Accepted:** {', '.join(ACCEPTED_TOKENS)}"
|
|
352
|
+
|
|
353
|
+
elif lower.startswith("invoice"):
|
|
354
|
+
parts = text.split(maxsplit=1)
|
|
355
|
+
service = parts[1] if len(parts) > 1 else "default"
|
|
356
|
+
inv = await invoices.create(sender, service, "{{service_price_fet}}", "FET")
|
|
357
|
+
response = (
|
|
358
|
+
f"**Invoice Created**\\n"
|
|
359
|
+
f" ID: {inv['id']}\\n"
|
|
360
|
+
f" Service: {inv['service']}\\n"
|
|
361
|
+
f" Amount: {inv['amount']} {inv['token']}\\n"
|
|
362
|
+
f" Status: {inv['status']}"
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
elif lower in ("buy-crypto", "buy crypto", "no crypto", "get crypto"):
|
|
366
|
+
link = fiat.generate_link(sender, "50", "USD", "FET")
|
|
367
|
+
if link:
|
|
368
|
+
response = (
|
|
369
|
+
f"**Buy crypto with your card:**\\n"
|
|
370
|
+
f"[Purchase FET]({link})\\n\\n"
|
|
371
|
+
f"You\\'ll receive FET in your wallet within minutes."
|
|
372
|
+
)
|
|
373
|
+
else:
|
|
374
|
+
response = "Fiat onramp is not enabled for this agent."
|
|
375
|
+
|
|
376
|
+
elif lower == "revenue":
|
|
377
|
+
summary = await revenue.get_summary()
|
|
378
|
+
total = summary.get("total_income", 0)
|
|
379
|
+
txns = summary.get("transaction_count", 0)
|
|
380
|
+
by_token = summary.get("by_token", {})
|
|
381
|
+
token_lines = "\\n".join(
|
|
382
|
+
f" {t}: {d.get('income', 0):.4f} income, {d.get('expenses', 0):.4f} expenses"
|
|
383
|
+
for t, d in by_token.items()
|
|
384
|
+
) if by_token else " No revenue yet"
|
|
385
|
+
response = (
|
|
386
|
+
f"**Revenue Summary**\\n"
|
|
387
|
+
f" Total income: {total:.4f}\\n"
|
|
388
|
+
f" Transactions: {txns}\\n\\n"
|
|
389
|
+
f"**By Token:**\\n{token_lines}"
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
elif lower == "status":
|
|
393
|
+
inv_list = await invoices.list_invoices("pending")
|
|
394
|
+
response = (
|
|
395
|
+
f"**{BUSINESS['name']}** v{BUSINESS['version']}\\n"
|
|
396
|
+
f" Accepted tokens: {', '.join(ACCEPTED_TOKENS)}\\n"
|
|
397
|
+
f" Pending invoices: {len(inv_list)}\\n"
|
|
398
|
+
f" Delegation: {'enabled' if '{{enable_delegation}}' == 'true' else 'disabled'}\\n"
|
|
399
|
+
f" Fiat onramp: {'enabled' if '{{enable_fiat_onramp}}' == 'true' else 'disabled'}"
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
else:
|
|
403
|
+
# === YOUR COMMERCE LOGIC ===
|
|
404
|
+
# This is where you add your custom service logic.
|
|
405
|
+
# After fulfilling a service, record revenue:
|
|
406
|
+
# await revenue.record_income("0.01", "FET", "my_service", sender)
|
|
407
|
+
prices = await pricing.format_prices()
|
|
408
|
+
response = (
|
|
409
|
+
f"Welcome to **{BUSINESS['name']}**!\\n\\n"
|
|
410
|
+
f"{BUSINESS['description']}\\n\\n"
|
|
411
|
+
f"**Pricing:**\\n{prices}\\n\\n"
|
|
412
|
+
f"Type \`help\` for commands, or \`invoice <service>\` to get started."
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
await ctx.send(sender, ChatMessage(
|
|
416
|
+
timestamp=datetime.now(),
|
|
417
|
+
msg_id=str(uuid4()),
|
|
418
|
+
content=[TextContent(text=response)],
|
|
419
|
+
))
|
|
420
|
+
|
|
421
|
+
await ctx.send(sender, ChatMessage(
|
|
422
|
+
timestamp=datetime.now(),
|
|
423
|
+
msg_id=str(uuid4()),
|
|
424
|
+
content=[EndSessionContent()],
|
|
425
|
+
))
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
@chat_proto.on_message(ChatAcknowledgement)
|
|
429
|
+
async def handle_ack(ctx: Context, sender: str, msg: ChatAcknowledgement):
|
|
430
|
+
ctx.logger.info(f"Ack from {sender}: {msg.acknowledged_msg_id}")
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
agent.include(chat_proto, publish_manifest=True)
|
|
434
|
+
|
|
435
|
+
if __name__ == "__main__":
|
|
436
|
+
agent.run()
|
|
437
|
+
`,
|
|
438
|
+
};
|
|
439
|
+
//# sourceMappingURL=consumer-commerce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumer-commerce.js","sourceRoot":"","sources":["../../src/templates/consumer-commerce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,MAAM,YAAY,GAAG,6BAA6B,CAAC;AACnD,MAAM,WAAW,GAAG,iEAAiE,CAAC;AACtF,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB;IACvD,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,iGAAiG;IAC9G,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE;QACxE,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2CAA2C,EAAE;QACjG,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE;QACnF,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,uBAAuB,EAAE;QACrF,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,wCAAwC,EAAE;QACvG,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,oCAAoC,EAAE;QAClG,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,2BAA2B,EAAE;QACtF,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,uCAAuC,EAAE;KACrG;IACD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;IAClC,OAAO,EAAE;QACP,oBAAoB;QACpB,qBAAqB;QACrB,oBAAoB;QACpB,iBAAiB;KAClB;IACD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDAgC+C,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgXtE;CACA,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genesis.d.ts","sourceRoot":"","sources":["../../src/templates/genesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQpD,eAAO,MAAM,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"genesis.d.ts","sourceRoot":"","sources":["../../src/templates/genesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQpD,eAAO,MAAM,QAAQ,EAAE,aA2wCtB,CAAC"}
|
|
@@ -939,8 +939,16 @@ class HoldingsManager:
|
|
|
939
939
|
results.append({"address": addr, "name": "Error", "price": 0, "holders": 0})
|
|
940
940
|
return results
|
|
941
941
|
|
|
942
|
+
@staticmethod
|
|
943
|
+
def _validate_eth_address(address: str) -> bool:
|
|
944
|
+
"""Validate Ethereum address format to prevent URL injection."""
|
|
945
|
+
import re
|
|
946
|
+
return bool(re.match(r'^0x[a-fA-F0-9]{40}$', address))
|
|
947
|
+
|
|
942
948
|
@staticmethod
|
|
943
949
|
def generate_buy_link(token_address: str, amount: int = 0) -> str:
|
|
950
|
+
if not HoldingsManager._validate_eth_address(token_address):
|
|
951
|
+
return f"Error: Invalid token address format: {token_address}"
|
|
944
952
|
base = os.environ.get("AGENTLAUNCH_FRONTEND", "https://agent-launch.ai")
|
|
945
953
|
url = f"{base}/trade/{token_address}?action=buy"
|
|
946
954
|
if amount:
|
|
@@ -949,6 +957,8 @@ class HoldingsManager:
|
|
|
949
957
|
|
|
950
958
|
@staticmethod
|
|
951
959
|
def generate_sell_link(token_address: str, amount: int = 0) -> str:
|
|
960
|
+
if not HoldingsManager._validate_eth_address(token_address):
|
|
961
|
+
return f"Error: Invalid token address format: {token_address}"
|
|
952
962
|
base = os.environ.get("AGENTLAUNCH_FRONTEND", "https://agent-launch.ai")
|
|
953
963
|
url = f"{base}/trade/{token_address}?action=sell"
|
|
954
964
|
if amount:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"genesis.js","sourceRoot":"","sources":["../../src/templates/genesis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,6FAA6F;AAC7F,MAAM,YAAY,GAAG,6BAA6B,CAAC;AACnD,MAAM,WAAW,GAAG,iEAAiE,CAAC;AACtF,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB;IACvD,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,IAAI,EAAE,SAAS;IACf,WAAW,EACT,iGAAiG;IACnG,QAAQ,EAAE,iBAAiB;IAC3B,SAAS,EAAE;QACT,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mBAAmB,EAAE;QACxE;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,yBAAyB;YAClC,WAAW,EAAE,2CAA2C;SACzD;QACD;YACE,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,QAAQ;YACjB,WAAW,EACT,uFAAuF;SAC1F;QACD;YACE,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,kBAAkB;YAC3B,WAAW,EAAE,wDAAwD;SACtE;QACD;YACE,IAAI,EAAE,kBAAkB;YACxB,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,qCAAqC;SACnD;QACD;YACE,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,EAAE;YACX,WAAW,EAAE,kEAAkE;SAChF;QACD;YACE,IAAI,EAAE,yBAAyB;YAC/B,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,uCAAuC;SACrD;QACD;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,iDAAiD;SAC/D;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;KACF;IACD,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;IAClC,OAAO,EAAE;QACP,oBAAoB;QACpB,qBAAqB;QACrB,eAAe;QACf,qBAAqB;QACrB,iBAAiB;KAClB;IACD,IAAI,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uDAgG+C,gBAAgB
|
|
1
|
+
{"version":3,"file":"genesis.js","sourceRoot":"","sources":["../../src/templates/genesis.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* swarm-starter template: full commerce stack for agent swarms
|
|
3
|
+
*
|
|
4
|
+
* This is the flagship template for the AgentLaunch platform. It generates a
|
|
5
|
+
* production-ready agent with an inline commerce engine: payments, pricing,
|
|
6
|
+
* tiers, revenue tracking, self-awareness (own token metrics), and cross-holdings.
|
|
7
|
+
*
|
|
8
|
+
* Layers (bottom to top):
|
|
9
|
+
* 1. Logger — structured logging with audit trail
|
|
10
|
+
* 2. Security — rate limiting, input validation
|
|
11
|
+
* 3. Health — uptime, error rate tracking
|
|
12
|
+
* 4. Cache — in-memory TTL cache
|
|
13
|
+
* 5. Revenue/Tier — PricingTable, TierManager
|
|
14
|
+
* 6. Commerce — PaymentService, WalletManager, RevenueTracker
|
|
15
|
+
* 7. SelfAware — token price/holder awareness
|
|
16
|
+
* 8. Holdings — HoldingsManager for cross-token operations
|
|
17
|
+
* 9. SwarmBusiness — YOUR LOGIC HERE
|
|
18
|
+
*
|
|
19
|
+
* Platform constants (source of truth: deployed smart contracts):
|
|
20
|
+
* - Deploy fee: 120 FET (read dynamically, can change via multi-sig)
|
|
21
|
+
* - Graduation target: 30,000 FET -> auto DEX listing
|
|
22
|
+
* - Trading fee: 2% -> 100% to protocol treasury (NO creator fee)
|
|
23
|
+
*/
|
|
24
|
+
import type { AgentTemplate } from "../registry.js";
|
|
25
|
+
export declare const template: AgentTemplate;
|
|
26
|
+
//# sourceMappingURL=swarm-starter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm-starter.d.ts","sourceRoot":"","sources":["../../src/templates/swarm-starter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQpD,eAAO,MAAM,QAAQ,EAAE,aAi3CtB,CAAC"}
|