agentwallet-sdk 5.0.5 → 5.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 (271) hide show
  1. package/README.md +32 -30
  2. package/dist/ap2/index.d.ts +185 -0
  3. package/dist/ap2/index.d.ts.map +1 -0
  4. package/dist/ap2/index.js +255 -0
  5. package/dist/ap2/index.js.map +1 -0
  6. package/dist/bridge/unified.d.ts +101 -0
  7. package/dist/bridge/unified.d.ts.map +1 -0
  8. package/dist/bridge/unified.js +284 -0
  9. package/dist/bridge/unified.js.map +1 -0
  10. package/dist/chains.d.ts +62 -0
  11. package/dist/chains.d.ts.map +1 -0
  12. package/dist/chains.js +108 -0
  13. package/dist/chains.js.map +1 -0
  14. package/dist/fiat/index.d.ts +10 -0
  15. package/dist/fiat/index.d.ts.map +1 -0
  16. package/dist/fiat/index.js +9 -0
  17. package/dist/fiat/index.js.map +1 -0
  18. package/dist/fiat/onramp.d.ts +101 -0
  19. package/dist/fiat/onramp.d.ts.map +1 -0
  20. package/dist/fiat/onramp.js +155 -0
  21. package/dist/fiat/onramp.js.map +1 -0
  22. package/dist/fiat/providers/index.d.ts +16 -0
  23. package/dist/fiat/providers/index.d.ts.map +1 -0
  24. package/dist/fiat/providers/index.js +30 -0
  25. package/dist/fiat/providers/index.js.map +1 -0
  26. package/dist/fiat/providers/moonpay.d.ts +22 -0
  27. package/dist/fiat/providers/moonpay.d.ts.map +1 -0
  28. package/dist/fiat/providers/moonpay.js +107 -0
  29. package/dist/fiat/providers/moonpay.js.map +1 -0
  30. package/dist/fiat/providers/stripe.d.ts +26 -0
  31. package/dist/fiat/providers/stripe.d.ts.map +1 -0
  32. package/dist/fiat/providers/stripe.js +135 -0
  33. package/dist/fiat/providers/stripe.js.map +1 -0
  34. package/dist/fiat/providers/transak.d.ts +26 -0
  35. package/dist/fiat/providers/transak.d.ts.map +1 -0
  36. package/dist/fiat/providers/transak.js +119 -0
  37. package/dist/fiat/providers/transak.js.map +1 -0
  38. package/dist/fiat/types.d.ts +106 -0
  39. package/dist/fiat/types.d.ts.map +1 -0
  40. package/dist/fiat/types.js +13 -0
  41. package/dist/fiat/types.js.map +1 -0
  42. package/dist/flash/executor.d.ts +119 -0
  43. package/dist/flash/executor.d.ts.map +1 -0
  44. package/dist/flash/executor.js +195 -0
  45. package/dist/flash/executor.js.map +1 -0
  46. package/dist/flash/index.d.ts +28 -0
  47. package/dist/flash/index.d.ts.map +1 -0
  48. package/dist/flash/index.js +29 -0
  49. package/dist/flash/index.js.map +1 -0
  50. package/dist/flash/scanner.d.ts +133 -0
  51. package/dist/flash/scanner.d.ts.map +1 -0
  52. package/dist/flash/scanner.js +212 -0
  53. package/dist/flash/scanner.js.map +1 -0
  54. package/dist/flash/types.d.ts +136 -0
  55. package/dist/flash/types.d.ts.map +1 -0
  56. package/dist/flash/types.js +23 -0
  57. package/dist/flash/types.js.map +1 -0
  58. package/dist/gas/index.d.ts +4 -0
  59. package/dist/gas/index.d.ts.map +1 -0
  60. package/dist/gas/index.js +3 -0
  61. package/dist/gas/index.js.map +1 -0
  62. package/dist/gas/sponsor.d.ts +70 -0
  63. package/dist/gas/sponsor.d.ts.map +1 -0
  64. package/dist/gas/sponsor.js +193 -0
  65. package/dist/gas/sponsor.js.map +1 -0
  66. package/dist/gas/types.d.ts +76 -0
  67. package/dist/gas/types.d.ts.map +1 -0
  68. package/dist/gas/types.js +21 -0
  69. package/dist/gas/types.js.map +1 -0
  70. package/dist/identity/agent-identity.d.ts +276 -0
  71. package/dist/identity/agent-identity.d.ts.map +1 -0
  72. package/dist/identity/agent-identity.js +300 -0
  73. package/dist/identity/agent-identity.js.map +1 -0
  74. package/dist/identity/email-resolver.d.ts +235 -0
  75. package/dist/identity/email-resolver.js +283 -0
  76. package/dist/identity/erc6551.d.ts +441 -0
  77. package/dist/identity/erc6551.d.ts.map +1 -0
  78. package/dist/identity/erc6551.js +517 -0
  79. package/dist/identity/erc6551.js.map +1 -0
  80. package/dist/index.d.ts +286 -213
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/index.js +3 -1
  83. package/dist/index.js.map +1 -1
  84. package/dist/mev/index.d.ts +4 -0
  85. package/dist/mev/index.d.ts.map +1 -0
  86. package/dist/mev/index.js +8 -0
  87. package/dist/mev/index.js.map +1 -0
  88. package/dist/mev/protection.d.ts +54 -0
  89. package/dist/mev/protection.d.ts.map +1 -0
  90. package/dist/mev/protection.js +185 -0
  91. package/dist/mev/protection.js.map +1 -0
  92. package/dist/mev/risk.d.ts +19 -0
  93. package/dist/mev/risk.d.ts.map +1 -0
  94. package/dist/mev/risk.js +95 -0
  95. package/dist/mev/risk.js.map +1 -0
  96. package/dist/mev/types.d.ts +49 -0
  97. package/dist/mev/types.d.ts.map +1 -0
  98. package/dist/mev/types.js +2 -0
  99. package/dist/mev/types.js.map +1 -0
  100. package/dist/plugins/elizaos.d.ts +52 -0
  101. package/dist/plugins/elizaos.d.ts.map +1 -0
  102. package/dist/plugins/elizaos.js +89 -0
  103. package/dist/plugins/elizaos.js.map +1 -0
  104. package/dist/settlement/index.d.ts +4 -0
  105. package/dist/settlement/index.d.ts.map +1 -0
  106. package/dist/settlement/index.js +3 -0
  107. package/dist/settlement/index.js.map +1 -0
  108. package/dist/settlement/types.d.ts +66 -0
  109. package/dist/settlement/types.d.ts.map +1 -0
  110. package/dist/settlement/types.js +37 -0
  111. package/dist/settlement/types.js.map +1 -0
  112. package/dist/settlement/verifier.d.ts +75 -0
  113. package/dist/settlement/verifier.d.ts.map +1 -0
  114. package/dist/settlement/verifier.js +354 -0
  115. package/dist/settlement/verifier.js.map +1 -0
  116. package/dist/solana/bridge.d.ts +144 -0
  117. package/dist/solana/bridge.d.ts.map +1 -0
  118. package/dist/solana/bridge.js +352 -0
  119. package/dist/solana/bridge.js.map +1 -0
  120. package/dist/solana/index.d.ts +8 -0
  121. package/dist/solana/index.d.ts.map +1 -0
  122. package/dist/solana/index.js +6 -0
  123. package/dist/solana/index.js.map +1 -0
  124. package/dist/solana/swap.d.ts +85 -0
  125. package/dist/solana/swap.d.ts.map +1 -0
  126. package/dist/solana/swap.js +173 -0
  127. package/dist/solana/swap.js.map +1 -0
  128. package/dist/solana/types.d.ts +126 -0
  129. package/dist/solana/types.d.ts.map +1 -0
  130. package/dist/solana/types.js +10 -0
  131. package/dist/solana/types.js.map +1 -0
  132. package/dist/solana/wallet.d.ts +83 -0
  133. package/dist/solana/wallet.d.ts.map +1 -0
  134. package/dist/solana/wallet.js +164 -0
  135. package/dist/solana/wallet.js.map +1 -0
  136. package/dist/solana/x402.d.ts +69 -0
  137. package/dist/solana/x402.d.ts.map +1 -0
  138. package/dist/solana/x402.js +154 -0
  139. package/dist/solana/x402.js.map +1 -0
  140. package/dist/solver/adapter.d.ts +47 -0
  141. package/dist/solver/adapter.d.ts.map +1 -0
  142. package/dist/solver/adapter.js +146 -0
  143. package/dist/solver/adapter.js.map +1 -0
  144. package/dist/solver/analyzer.d.ts +48 -0
  145. package/dist/solver/analyzer.d.ts.map +1 -0
  146. package/dist/solver/analyzer.js +171 -0
  147. package/dist/solver/analyzer.js.map +1 -0
  148. package/dist/solver/builder.d.ts +31 -0
  149. package/dist/solver/builder.d.ts.map +1 -0
  150. package/dist/solver/builder.js +60 -0
  151. package/dist/solver/builder.js.map +1 -0
  152. package/dist/solver/index.d.ts +22 -0
  153. package/dist/solver/index.d.ts.map +1 -0
  154. package/dist/solver/index.js +25 -0
  155. package/dist/solver/index.js.map +1 -0
  156. package/dist/solver/types.d.ts +115 -0
  157. package/dist/solver/types.d.ts.map +1 -0
  158. package/dist/solver/types.js +10 -0
  159. package/dist/solver/types.js.map +1 -0
  160. package/dist/spend-guard/index.d.ts +125 -0
  161. package/dist/spend-guard/index.d.ts.map +1 -0
  162. package/dist/spend-guard/index.js +150 -0
  163. package/dist/spend-guard/index.js.map +1 -0
  164. package/dist/swap/router/cache.d.ts +13 -0
  165. package/dist/swap/router/cache.d.ts.map +1 -0
  166. package/dist/swap/router/cache.js +30 -0
  167. package/dist/swap/router/cache.js.map +1 -0
  168. package/dist/swap/router/flashbots.d.ts +10 -0
  169. package/dist/swap/router/flashbots.d.ts.map +1 -0
  170. package/dist/swap/router/flashbots.js +43 -0
  171. package/dist/swap/router/flashbots.js.map +1 -0
  172. package/dist/swap/router/health.d.ts +17 -0
  173. package/dist/swap/router/health.d.ts.map +1 -0
  174. package/dist/swap/router/health.js +38 -0
  175. package/dist/swap/router/health.js.map +1 -0
  176. package/dist/swap/router/index.d.ts +10 -0
  177. package/dist/swap/router/index.d.ts.map +1 -0
  178. package/dist/swap/router/index.js +10 -0
  179. package/dist/swap/router/index.js.map +1 -0
  180. package/dist/swap/router/providers/cowswap.d.ts +11 -0
  181. package/dist/swap/router/providers/cowswap.d.ts.map +1 -0
  182. package/dist/swap/router/providers/cowswap.js +79 -0
  183. package/dist/swap/router/providers/cowswap.js.map +1 -0
  184. package/dist/swap/router/providers/index.d.ts +20 -0
  185. package/dist/swap/router/providers/index.d.ts.map +1 -0
  186. package/dist/swap/router/providers/index.js +32 -0
  187. package/dist/swap/router/providers/index.js.map +1 -0
  188. package/dist/swap/router/providers/jupiter.d.ts +12 -0
  189. package/dist/swap/router/providers/jupiter.d.ts.map +1 -0
  190. package/dist/swap/router/providers/jupiter.js +73 -0
  191. package/dist/swap/router/providers/jupiter.js.map +1 -0
  192. package/dist/swap/router/providers/lifi.d.ts +11 -0
  193. package/dist/swap/router/providers/lifi.d.ts.map +1 -0
  194. package/dist/swap/router/providers/lifi.js +123 -0
  195. package/dist/swap/router/providers/lifi.js.map +1 -0
  196. package/dist/swap/router/providers/oneinch.d.ts +13 -0
  197. package/dist/swap/router/providers/oneinch.d.ts.map +1 -0
  198. package/dist/swap/router/providers/oneinch.js +71 -0
  199. package/dist/swap/router/providers/oneinch.js.map +1 -0
  200. package/dist/swap/router/providers/paraswap.d.ts +11 -0
  201. package/dist/swap/router/providers/paraswap.d.ts.map +1 -0
  202. package/dist/swap/router/providers/paraswap.js +73 -0
  203. package/dist/swap/router/providers/paraswap.js.map +1 -0
  204. package/dist/swap/router/providers/uniswap.d.ts +31 -0
  205. package/dist/swap/router/providers/uniswap.d.ts.map +1 -0
  206. package/dist/swap/router/providers/uniswap.js +237 -0
  207. package/dist/swap/router/providers/uniswap.js.map +1 -0
  208. package/dist/swap/router/providers/zerox.d.ts +13 -0
  209. package/dist/swap/router/providers/zerox.d.ts.map +1 -0
  210. package/dist/swap/router/providers/zerox.js +94 -0
  211. package/dist/swap/router/providers/zerox.js.map +1 -0
  212. package/dist/swap/router/router.d.ts +86 -0
  213. package/dist/swap/router/router.d.ts.map +1 -0
  214. package/dist/swap/router/router.js +224 -0
  215. package/dist/swap/router/router.js.map +1 -0
  216. package/dist/swap/router/rsi/engine.d.ts +60 -0
  217. package/dist/swap/router/rsi/engine.d.ts.map +1 -0
  218. package/dist/swap/router/rsi/engine.js +483 -0
  219. package/dist/swap/router/rsi/engine.js.map +1 -0
  220. package/dist/swap/router/rsi/index.d.ts +3 -0
  221. package/dist/swap/router/rsi/index.d.ts.map +1 -0
  222. package/dist/swap/router/rsi/index.js +3 -0
  223. package/dist/swap/router/rsi/index.js.map +1 -0
  224. package/dist/swap/router/rsi/types.d.ts +106 -0
  225. package/dist/swap/router/rsi/types.d.ts.map +1 -0
  226. package/dist/swap/router/rsi/types.js +3 -0
  227. package/dist/swap/router/rsi/types.js.map +1 -0
  228. package/dist/swap/router/types.d.ts +120 -0
  229. package/dist/swap/router/types.d.ts.map +1 -0
  230. package/dist/swap/router/types.js +16 -0
  231. package/dist/swap/router/types.js.map +1 -0
  232. package/dist/tax/engine.d.ts +131 -0
  233. package/dist/tax/engine.d.ts.map +1 -0
  234. package/dist/tax/engine.js +307 -0
  235. package/dist/tax/engine.js.map +1 -0
  236. package/dist/tax/index.d.ts +9 -0
  237. package/dist/tax/index.d.ts.map +1 -0
  238. package/dist/tax/index.js +12 -0
  239. package/dist/tax/index.js.map +1 -0
  240. package/dist/tax/lots.d.ts +60 -0
  241. package/dist/tax/lots.d.ts.map +1 -0
  242. package/dist/tax/lots.js +129 -0
  243. package/dist/tax/lots.js.map +1 -0
  244. package/dist/tax/types.d.ts +113 -0
  245. package/dist/tax/types.d.ts.map +1 -0
  246. package/dist/tax/types.js +18 -0
  247. package/dist/tax/types.js.map +1 -0
  248. package/dist/verifiable-intent/index.d.ts +84 -0
  249. package/dist/verifiable-intent/index.js +385 -0
  250. package/dist/yield/index.d.ts +26 -0
  251. package/dist/yield/index.d.ts.map +1 -0
  252. package/dist/yield/index.js +29 -0
  253. package/dist/yield/index.js.map +1 -0
  254. package/dist/yield/rates.d.ts +114 -0
  255. package/dist/yield/rates.d.ts.map +1 -0
  256. package/dist/yield/rates.js +351 -0
  257. package/dist/yield/rates.js.map +1 -0
  258. package/dist/yield/types.d.ts +134 -0
  259. package/dist/yield/types.d.ts.map +1 -0
  260. package/dist/yield/types.js +24 -0
  261. package/dist/yield/types.js.map +1 -0
  262. package/dist/yield/vault.d.ts +112 -0
  263. package/dist/yield/vault.d.ts.map +1 -0
  264. package/dist/yield/vault.js +264 -0
  265. package/dist/yield/vault.js.map +1 -0
  266. package/package.json +3 -3
  267. package/LICENSE +0 -21
  268. package/dist/x402/chains/stellar/index.d.ts +0 -136
  269. package/dist/x402/chains/stellar/index.d.ts.map +0 -1
  270. package/dist/x402/chains/stellar/index.js +0 -190
  271. package/dist/x402/chains/stellar/index.js.map +0 -1
@@ -0,0 +1,283 @@
1
+ /**
2
+ * EmailResolver — AgentMail integration for agentwallet-sdk.
3
+ * Gives every agent its own email inbox and resolves emails to wallet addresses.
4
+ *
5
+ * AgentMail API: https://api.agentmail.to/v0
6
+ * Docs: https://docs.agentmail.to
7
+ */
8
+
9
+ const DEFAULT_BASE_URL = 'https://api.agentmail.to/v0';
10
+ const DEFAULT_CACHE_TTL = 300; // 5 minutes
11
+
12
+ // ── x402 payment request format embedded in email bodies ──────────────────────
13
+ const X402_PAYMENT_HEADER = '<!-- x402-payment-request';
14
+ const X402_PAYMENT_FOOTER = 'x402-payment-request -->';
15
+
16
+ function encodePaymentRequest(req) {
17
+ return `\n\n${X402_PAYMENT_HEADER}\n${JSON.stringify(req, null, 2)}\n${X402_PAYMENT_FOOTER}\n`;
18
+ }
19
+
20
+ function parsePaymentRequest(body) {
21
+ const start = body.indexOf(X402_PAYMENT_HEADER);
22
+ const end = body.indexOf(X402_PAYMENT_FOOTER);
23
+ if (start === -1 || end === -1) return undefined;
24
+ try {
25
+ const json = body.slice(start + X402_PAYMENT_HEADER.length, end).trim();
26
+ return JSON.parse(json);
27
+ } catch {
28
+ return undefined;
29
+ }
30
+ }
31
+
32
+ // ── API client helpers ─────────────────────────────────────────────────────────
33
+
34
+ async function agentMailRequest(apiKey, baseUrl, method, path, body) {
35
+ const url = `${baseUrl}${path}`;
36
+ const opts = {
37
+ method,
38
+ headers: {
39
+ Authorization: `Bearer ${apiKey}`,
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
42
+ },
43
+ };
44
+ if (body !== undefined) {
45
+ opts.body = JSON.stringify(body);
46
+ }
47
+
48
+ const res = await fetch(url, opts);
49
+ if (!res.ok) {
50
+ const text = await res.text().catch(() => '(no body)');
51
+ throw new Error(`AgentMail API error ${res.status}: ${text}`);
52
+ }
53
+ if (res.status === 204) return undefined;
54
+ return res.json();
55
+ }
56
+
57
+ // ── Map AgentMail inbox response → AgentInbox ─────────────────────────────────
58
+
59
+ function mapInbox(raw) {
60
+ // AgentMail inbox shape: { id, username, domain, display_name, created_at, ... }
61
+ const email = raw.username && raw.domain
62
+ ? `${raw.username}@${raw.domain}`
63
+ : raw.email_address ?? raw.address ?? '';
64
+ return {
65
+ emailAddress: email,
66
+ inboxId: raw.id ?? raw.inbox_id,
67
+ displayName: raw.display_name ?? raw.displayName ?? '',
68
+ createdAt: raw.created_at ?? raw.createdAt ?? new Date().toISOString(),
69
+ };
70
+ }
71
+
72
+ // ── Map AgentMail message response → AgentEmail ───────────────────────────────
73
+
74
+ function mapMessage(raw) {
75
+ const body = raw.body?.text ?? raw.text ?? raw.body ?? '';
76
+ return {
77
+ messageId: raw.id ?? raw.message_id,
78
+ from: raw.from ?? raw.sender ?? '',
79
+ to: Array.isArray(raw.to) ? raw.to : [raw.to ?? ''],
80
+ subject: raw.subject ?? '',
81
+ body,
82
+ timestamp: raw.timestamp ?? raw.received_at ?? raw.created_at ?? '',
83
+ threadId: raw.thread_id ?? raw.threadId,
84
+ paymentRequest: parsePaymentRequest(body),
85
+ };
86
+ }
87
+
88
+ // ── EmailResolver class ───────────────────────────────────────────────────────
89
+
90
+ export class EmailResolver {
91
+ constructor(config) {
92
+ if (!config?.agentMailApiKey) {
93
+ throw new Error('EmailResolver: agentMailApiKey is required');
94
+ }
95
+ this.apiKey = config.agentMailApiKey;
96
+ this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
97
+ this.cacheTtl = config.cacheTtlSeconds ?? DEFAULT_CACHE_TTL;
98
+ this.cache = new Map();
99
+ }
100
+
101
+ // ── Inbox management ────────────────────────────────────────────────────────
102
+
103
+ async createInbox({ agentName, displayName, walletAddress, chain = 'base' }) {
104
+ if (!agentName) throw new Error('agentName is required');
105
+ if (!walletAddress) throw new Error('walletAddress is required');
106
+
107
+ // AgentMail inbox creation — username becomes the local part of the email
108
+ const raw = await agentMailRequest(this.apiKey, this.baseUrl, 'POST', '/inboxes', {
109
+ username: agentName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
110
+ display_name: displayName,
111
+ // Store wallet metadata in AgentMail's custom fields
112
+ metadata: {
113
+ wallet_address: walletAddress,
114
+ chain,
115
+ sdk: 'agentwallet-sdk',
116
+ },
117
+ });
118
+
119
+ return mapInbox(raw);
120
+ }
121
+
122
+ async listInboxes() {
123
+ const data = await agentMailRequest(this.apiKey, this.baseUrl, 'GET', '/inboxes');
124
+ const items = data?.inboxes ?? data?.items ?? (Array.isArray(data) ? data : []);
125
+ return items.map(mapInbox);
126
+ }
127
+
128
+ async getInbox(inboxId) {
129
+ const raw = await agentMailRequest(this.apiKey, this.baseUrl, 'GET', `/inboxes/${inboxId}`);
130
+ return mapInbox(raw);
131
+ }
132
+
133
+ async deleteInbox(inboxId) {
134
+ await agentMailRequest(this.apiKey, this.baseUrl, 'DELETE', `/inboxes/${inboxId}`);
135
+ }
136
+
137
+ // ── Email ↔ Wallet resolution ───────────────────────────────────────────────
138
+
139
+ async resolveEmailToWallet(emailAddress) {
140
+ const normalised = emailAddress.toLowerCase().trim();
141
+
142
+ // 1. Cache hit
143
+ const cached = this.cache.get(normalised);
144
+ if (cached && Date.now() / 1000 - cached.resolvedAt < this.cacheTtl) {
145
+ return cached;
146
+ }
147
+
148
+ // 2. AgentMail lookup — scan inboxes for matching email + wallet metadata
149
+ try {
150
+ const inboxes = await this.listInboxes();
151
+ for (const inbox of inboxes) {
152
+ if (inbox.emailAddress.toLowerCase() === normalised) {
153
+ // Fetch full inbox to get metadata
154
+ const full = await agentMailRequest(
155
+ this.apiKey, this.baseUrl, 'GET', `/inboxes/${inbox.inboxId}`
156
+ );
157
+ const walletAddress = full?.metadata?.wallet_address;
158
+ const chain = full?.metadata?.chain ?? 'base';
159
+ if (walletAddress) {
160
+ const resolution = {
161
+ emailAddress: normalised,
162
+ walletAddress,
163
+ chain,
164
+ source: 'agentmail',
165
+ resolvedAt: Math.floor(Date.now() / 1000),
166
+ };
167
+ this.cache.set(normalised, resolution);
168
+ return resolution;
169
+ }
170
+ }
171
+ }
172
+ } catch (err) {
173
+ // Fall through to ENS
174
+ }
175
+
176
+ // 3. ENS fallback — resolve agent.eth-style names
177
+ // e.g., agent@ens.agentmail.to → agent.eth
178
+ if (normalised.includes('@ens.')) {
179
+ const localPart = normalised.split('@')[0];
180
+ const ensName = `${localPart}.eth`;
181
+ // ENS resolution requires viem — import dynamically to avoid hard dep
182
+ try {
183
+ const { createPublicClient, http } = await import('viem');
184
+ const { mainnet } = await import('viem/chains');
185
+ const client = createPublicClient({ chain: mainnet, transport: http() });
186
+ const addr = await client.getEnsAddress({ name: ensName });
187
+ if (addr) {
188
+ const resolution = {
189
+ emailAddress: normalised,
190
+ walletAddress: addr,
191
+ chain: 'ethereum',
192
+ source: 'ens',
193
+ resolvedAt: Math.floor(Date.now() / 1000),
194
+ };
195
+ this.cache.set(normalised, resolution);
196
+ return resolution;
197
+ }
198
+ } catch {
199
+ // ENS lookup failed
200
+ }
201
+ }
202
+
203
+ throw new Error(`EmailResolver: could not resolve wallet for ${emailAddress}`);
204
+ }
205
+
206
+ async resolveWalletToEmail(walletAddress) {
207
+ const normalised = walletAddress.toLowerCase().trim();
208
+ try {
209
+ const inboxes = await this.listInboxes();
210
+ for (const inbox of inboxes) {
211
+ const full = await agentMailRequest(
212
+ this.apiKey, this.baseUrl, 'GET', `/inboxes/${inbox.inboxId}`
213
+ );
214
+ if (full?.metadata?.wallet_address?.toLowerCase() === normalised) {
215
+ return inbox.emailAddress;
216
+ }
217
+ }
218
+ } catch {
219
+ // ignore
220
+ }
221
+ return null;
222
+ }
223
+
224
+ // ── Messaging ───────────────────────────────────────────────────────────────
225
+
226
+ async fetchMessages(inboxId, options = {}) {
227
+ const params = new URLSearchParams();
228
+ if (options.unreadOnly) params.set('unread', 'true');
229
+ if (options.limit) params.set('limit', String(options.limit));
230
+ if (options.threadId) params.set('thread_id', options.threadId);
231
+
232
+ const qs = params.toString();
233
+ const path = `/inboxes/${inboxId}/messages${qs ? `?${qs}` : ''}`;
234
+ const data = await agentMailRequest(this.apiKey, this.baseUrl, 'GET', path);
235
+ const items = data?.messages ?? data?.items ?? (Array.isArray(data) ? data : []);
236
+ return items.map(mapMessage);
237
+ }
238
+
239
+ async sendEmail({ inboxId, to, subject, body, paymentRequest, replyToMessageId }) {
240
+ const recipients = Array.isArray(to) ? to : [to];
241
+ let fullBody = body;
242
+ if (paymentRequest) {
243
+ fullBody += encodePaymentRequest(paymentRequest);
244
+ }
245
+
246
+ const payload = {
247
+ to: recipients,
248
+ subject,
249
+ body: { text: fullBody },
250
+ };
251
+ if (replyToMessageId) {
252
+ payload.reply_to_message_id = replyToMessageId;
253
+ }
254
+
255
+ const result = await agentMailRequest(
256
+ this.apiKey, this.baseUrl, 'POST', `/inboxes/${inboxId}/messages`, payload
257
+ );
258
+ return { messageId: result?.id ?? result?.message_id };
259
+ }
260
+
261
+ async replyToEmail({ inboxId, messageId, body, paymentRequest }) {
262
+ let fullBody = body;
263
+ if (paymentRequest) {
264
+ fullBody += encodePaymentRequest(paymentRequest);
265
+ }
266
+ const result = await agentMailRequest(
267
+ this.apiKey, this.baseUrl, 'POST', `/inboxes/${inboxId}/messages/${messageId}/reply`,
268
+ { body: { text: fullBody } }
269
+ );
270
+ return { messageId: result?.id ?? result?.message_id };
271
+ }
272
+
273
+ async markAsRead(inboxId, messageId) {
274
+ await agentMailRequest(
275
+ this.apiKey, this.baseUrl, 'PATCH', `/inboxes/${inboxId}/messages/${messageId}`,
276
+ { read: true }
277
+ );
278
+ }
279
+
280
+ clearCache() {
281
+ this.cache.clear();
282
+ }
283
+ }