@azeth/sdk 0.2.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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/dist/account/balance.d.ts +41 -0
- package/dist/account/balance.d.ts.map +1 -0
- package/dist/account/balance.js +264 -0
- package/dist/account/balance.js.map +1 -0
- package/dist/account/create.d.ts +27 -0
- package/dist/account/create.d.ts.map +1 -0
- package/dist/account/create.js +116 -0
- package/dist/account/create.js.map +1 -0
- package/dist/account/deposit.d.ts +34 -0
- package/dist/account/deposit.d.ts.map +1 -0
- package/dist/account/deposit.js +88 -0
- package/dist/account/deposit.js.map +1 -0
- package/dist/account/guardian-approval.d.ts +111 -0
- package/dist/account/guardian-approval.d.ts.map +1 -0
- package/dist/account/guardian-approval.js +223 -0
- package/dist/account/guardian-approval.js.map +1 -0
- package/dist/account/guardian.d.ts +27 -0
- package/dist/account/guardian.d.ts.map +1 -0
- package/dist/account/guardian.js +67 -0
- package/dist/account/guardian.js.map +1 -0
- package/dist/account/history.d.ts +22 -0
- package/dist/account/history.d.ts.map +1 -0
- package/dist/account/history.js +144 -0
- package/dist/account/history.js.map +1 -0
- package/dist/account/transfer.d.ts +28 -0
- package/dist/account/transfer.d.ts.map +1 -0
- package/dist/account/transfer.js +137 -0
- package/dist/account/transfer.js.map +1 -0
- package/dist/auth/erc8128.d.ts +14 -0
- package/dist/auth/erc8128.d.ts.map +1 -0
- package/dist/auth/erc8128.js +92 -0
- package/dist/auth/erc8128.js.map +1 -0
- package/dist/client.d.ts +394 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +970 -0
- package/dist/client.js.map +1 -0
- package/dist/events/emitter.d.ts +96 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/emitter.js +90 -0
- package/dist/events/emitter.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/messaging/message-router.d.ts +69 -0
- package/dist/messaging/message-router.d.ts.map +1 -0
- package/dist/messaging/message-router.js +307 -0
- package/dist/messaging/message-router.js.map +1 -0
- package/dist/messaging/rate-limiter.d.ts +31 -0
- package/dist/messaging/rate-limiter.d.ts.map +1 -0
- package/dist/messaging/rate-limiter.js +74 -0
- package/dist/messaging/rate-limiter.js.map +1 -0
- package/dist/messaging/xmtp.d.ts +144 -0
- package/dist/messaging/xmtp.d.ts.map +1 -0
- package/dist/messaging/xmtp.js +473 -0
- package/dist/messaging/xmtp.js.map +1 -0
- package/dist/payments/agreements.d.ts +87 -0
- package/dist/payments/agreements.d.ts.map +1 -0
- package/dist/payments/agreements.js +337 -0
- package/dist/payments/agreements.js.map +1 -0
- package/dist/payments/budget.d.ts +118 -0
- package/dist/payments/budget.d.ts.map +1 -0
- package/dist/payments/budget.js +176 -0
- package/dist/payments/budget.js.map +1 -0
- package/dist/payments/smart-fetch.d.ts +65 -0
- package/dist/payments/smart-fetch.d.ts.map +1 -0
- package/dist/payments/smart-fetch.js +115 -0
- package/dist/payments/smart-fetch.js.map +1 -0
- package/dist/payments/x402.d.ts +89 -0
- package/dist/payments/x402.d.ts.map +1 -0
- package/dist/payments/x402.js +620 -0
- package/dist/payments/x402.js.map +1 -0
- package/dist/registry/discover.d.ts +43 -0
- package/dist/registry/discover.d.ts.map +1 -0
- package/dist/registry/discover.js +272 -0
- package/dist/registry/discover.js.map +1 -0
- package/dist/registry/register.d.ts +44 -0
- package/dist/registry/register.d.ts.map +1 -0
- package/dist/registry/register.js +126 -0
- package/dist/registry/register.js.map +1 -0
- package/dist/reputation/opinion.d.ts +52 -0
- package/dist/reputation/opinion.d.ts.map +1 -0
- package/dist/reputation/opinion.js +198 -0
- package/dist/reputation/opinion.js.map +1 -0
- package/dist/utils/addresses.d.ts +6 -0
- package/dist/utils/addresses.d.ts.map +1 -0
- package/dist/utils/addresses.js +53 -0
- package/dist/utils/addresses.js.map +1 -0
- package/dist/utils/errors.d.ts +23 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +188 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/execution.d.ts +20 -0
- package/dist/utils/execution.d.ts.map +1 -0
- package/dist/utils/execution.js +28 -0
- package/dist/utils/execution.js.map +1 -0
- package/dist/utils/paymaster.d.ts +35 -0
- package/dist/utils/paymaster.d.ts.map +1 -0
- package/dist/utils/paymaster.js +115 -0
- package/dist/utils/paymaster.js.map +1 -0
- package/dist/utils/retry.d.ts +19 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +68 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/userop.d.ts +55 -0
- package/dist/utils/userop.d.ts.map +1 -0
- package/dist/utils/userop.js +201 -0
- package/dist/utils/userop.js.map +1 -0
- package/dist/utils/validation.d.ts +8 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +35 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { AzethError, } from '@azeth/common';
|
|
3
|
+
import { RateLimiter } from './rate-limiter.js';
|
|
4
|
+
/** XMTP messaging client backed by @xmtp/agent-sdk.
|
|
5
|
+
*
|
|
6
|
+
* Provides E2E encrypted agent-to-agent messaging via the XMTP network.
|
|
7
|
+
* Messages are rate-limited per sender and reachability results are cached.
|
|
8
|
+
*/
|
|
9
|
+
export class XMTPClient {
|
|
10
|
+
// We use `any` for the agent SDK types because they are imported dynamically
|
|
11
|
+
// and declaring full type stubs would be fragile. The public API is fully typed.
|
|
12
|
+
_agent = null;
|
|
13
|
+
/** Static Client class from @xmtp/agent-sdk, used for fetchInboxStates.
|
|
14
|
+
* The Agent's client instance doesn't expose this method, so we use the static version. */
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
_ClientClass = null;
|
|
17
|
+
_xmtpEnv = 'production';
|
|
18
|
+
_handlers = [];
|
|
19
|
+
_rateLimiter = null;
|
|
20
|
+
_reachabilityCache = new Map();
|
|
21
|
+
_reachabilityCacheTtlMs = 300_000; // 5 minutes default
|
|
22
|
+
_maxMessageLength = 10_000;
|
|
23
|
+
_ready = false;
|
|
24
|
+
_listening = false;
|
|
25
|
+
_messageStreamAbort = null;
|
|
26
|
+
_convStreamAbort = null;
|
|
27
|
+
_messageRouter = null;
|
|
28
|
+
_autoReply = false;
|
|
29
|
+
/** Initialize the XMTP client with a private key.
|
|
30
|
+
*
|
|
31
|
+
* Creates an XMTP Agent using the provided private key and config.
|
|
32
|
+
* Must be called before any messaging operations.
|
|
33
|
+
*
|
|
34
|
+
* @param privateKey - Owner's private key (0x-prefixed hex)
|
|
35
|
+
* @param config - Optional XMTP configuration
|
|
36
|
+
* @throws AzethError if initialization fails
|
|
37
|
+
*/
|
|
38
|
+
async initialize(privateKey, config) {
|
|
39
|
+
if (this._ready)
|
|
40
|
+
return;
|
|
41
|
+
// Dynamic import of @xmtp/agent-sdk to keep it optional at load time
|
|
42
|
+
let Agent;
|
|
43
|
+
let ClientClass;
|
|
44
|
+
let createUser;
|
|
45
|
+
let createSigner;
|
|
46
|
+
try {
|
|
47
|
+
const sdk = await import('@xmtp/agent-sdk');
|
|
48
|
+
Agent = sdk.Agent;
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
ClientClass = sdk.Client;
|
|
51
|
+
createUser = sdk.createUser;
|
|
52
|
+
createSigner = sdk.createSigner;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new AzethError('XMTP Agent SDK not installed. Run: pnpm add @xmtp/agent-sdk', 'INVALID_INPUT');
|
|
56
|
+
}
|
|
57
|
+
const user = createUser(privateKey);
|
|
58
|
+
const signer = createSigner(user);
|
|
59
|
+
// Resolve encryption key: config -> generate
|
|
60
|
+
let dbEncryptionKey;
|
|
61
|
+
if (config?.dbEncryptionKey) {
|
|
62
|
+
const hex = config.dbEncryptionKey.replace(/^0x/, '');
|
|
63
|
+
if (hex.length !== 64) {
|
|
64
|
+
throw new AzethError('dbEncryptionKey must be exactly 32 bytes (64 hex chars)', 'INVALID_INPUT', { field: 'dbEncryptionKey' });
|
|
65
|
+
}
|
|
66
|
+
dbEncryptionKey = Buffer.from(hex, 'hex');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// MEDIUM-7 (Audit): Auto-generating a random encryption key. The XMTP local database
|
|
70
|
+
// will be encrypted with this ephemeral key. On process restart, the key is lost and
|
|
71
|
+
// the database becomes unreadable — all XMTP conversation history and group state will
|
|
72
|
+
// be inaccessible. For persistent messaging, always provide config.dbEncryptionKey.
|
|
73
|
+
console.warn('[XMTPClient] No dbEncryptionKey provided — auto-generating ephemeral key. '
|
|
74
|
+
+ 'XMTP message history will be LOST on restart. Set dbEncryptionKey for persistence.');
|
|
75
|
+
dbEncryptionKey = crypto.randomBytes(32);
|
|
76
|
+
}
|
|
77
|
+
const env = config?.env ?? 'production';
|
|
78
|
+
const dbPath = config?.dbPath ?? null;
|
|
79
|
+
try {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
|
+
this._agent = await Agent.create(signer, {
|
|
82
|
+
env,
|
|
83
|
+
dbPath,
|
|
84
|
+
dbEncryptionKey,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
89
|
+
// Sanitize XMTP-internal identifiers (InboxIDs, hex hashes) from error messages
|
|
90
|
+
const sanitizedMsg = msg.replace(/[0-9a-fA-F]{32,}/g, '[redacted-id]');
|
|
91
|
+
throw new AzethError(`XMTP client creation failed: ${sanitizedMsg}`, 'NETWORK_ERROR', { cause: 'xmtp', originalError: e instanceof Error ? e.name : undefined });
|
|
92
|
+
}
|
|
93
|
+
// Store Client class + env for static fetchInboxStates calls
|
|
94
|
+
this._ClientClass = ClientClass ?? null;
|
|
95
|
+
this._xmtpEnv = env;
|
|
96
|
+
// Apply config
|
|
97
|
+
this._reachabilityCacheTtlMs = config?.reachabilityCacheTtlMs ?? 300_000;
|
|
98
|
+
this._maxMessageLength = config?.maxMessageLength ?? 10_000;
|
|
99
|
+
this._rateLimiter = new RateLimiter(config?.rateLimitPerMinute ?? 10);
|
|
100
|
+
this._autoReply = config?.autoReply ?? false;
|
|
101
|
+
this._ready = true;
|
|
102
|
+
}
|
|
103
|
+
/** Send a text message to an Ethereum address.
|
|
104
|
+
*
|
|
105
|
+
* Checks reachability, creates or finds a DM conversation, then sends.
|
|
106
|
+
*
|
|
107
|
+
* @param params - Message parameters (to, content, contentType)
|
|
108
|
+
* @returns The conversation ID
|
|
109
|
+
* @throws AzethError if the recipient is unreachable, content exceeds limits, or sending fails
|
|
110
|
+
*/
|
|
111
|
+
async sendMessage(params) {
|
|
112
|
+
this._requireReady();
|
|
113
|
+
if (params.content.length > this._maxMessageLength) {
|
|
114
|
+
throw new AzethError(`Message content exceeds maximum length of ${this._maxMessageLength} characters`, 'INVALID_INPUT', { field: 'content', maxLength: this._maxMessageLength });
|
|
115
|
+
}
|
|
116
|
+
const reachable = await this.canReach(params.to);
|
|
117
|
+
if (!reachable) {
|
|
118
|
+
throw new AzethError(`Recipient ${params.to} is not reachable on the XMTP network`, 'RECIPIENT_UNREACHABLE', { address: params.to });
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const dm = await this._agent.createDmWithAddress(params.to);
|
|
122
|
+
await dm.sendText(params.content);
|
|
123
|
+
return dm.id;
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
127
|
+
// Sanitize XMTP-internal identifiers (InboxIDs, hex hashes) from error messages
|
|
128
|
+
const sanitizedMsg = msg.replace(/[0-9a-fA-F]{32,}/g, '[redacted-id]');
|
|
129
|
+
throw new AzethError(`Failed to send XMTP message: ${sanitizedMsg}`, 'NETWORK_ERROR', { cause: 'xmtp', originalError: e instanceof Error ? e.name : undefined });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/** Register a handler for incoming messages.
|
|
133
|
+
*
|
|
134
|
+
* Starts the agent's message listener on first handler registration.
|
|
135
|
+
* Returns an unsubscribe function that removes the handler.
|
|
136
|
+
*
|
|
137
|
+
* @param handler - Async function called for each incoming message
|
|
138
|
+
* @returns Unsubscribe function
|
|
139
|
+
*/
|
|
140
|
+
onMessage(handler) {
|
|
141
|
+
this._handlers.push(handler);
|
|
142
|
+
if (!this._listening && this._ready) {
|
|
143
|
+
this._startListening();
|
|
144
|
+
}
|
|
145
|
+
return () => {
|
|
146
|
+
this._handlers = this._handlers.filter(h => h !== handler);
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** Check if an Ethereum address is reachable on the XMTP network.
|
|
150
|
+
*
|
|
151
|
+
* Results are cached with a configurable TTL (default 5 minutes).
|
|
152
|
+
* Returns `false` on errors rather than throwing.
|
|
153
|
+
*
|
|
154
|
+
* @param address - Ethereum address to check
|
|
155
|
+
* @returns Whether the address can receive XMTP messages
|
|
156
|
+
*/
|
|
157
|
+
async canReach(address) {
|
|
158
|
+
if (!this._ready || !this._agent)
|
|
159
|
+
return false;
|
|
160
|
+
const key = address.toLowerCase();
|
|
161
|
+
const cached = this._reachabilityCache.get(key);
|
|
162
|
+
if (cached && Date.now() < cached.expiresAt) {
|
|
163
|
+
return cached.reachable;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const identifier = { identifier: key, identifierKind: 0 };
|
|
167
|
+
const results = await this._agent.client.canMessage([identifier]);
|
|
168
|
+
const reachable = results.get(key) ?? results.get(address) ?? false;
|
|
169
|
+
this._reachabilityCache.set(key, {
|
|
170
|
+
reachable,
|
|
171
|
+
expiresAt: Date.now() + this._reachabilityCacheTtlMs,
|
|
172
|
+
});
|
|
173
|
+
return reachable;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/** List active XMTP conversations.
|
|
180
|
+
*
|
|
181
|
+
* @returns Array of conversation summaries
|
|
182
|
+
*/
|
|
183
|
+
async getConversations() {
|
|
184
|
+
if (!this._ready || !this._agent)
|
|
185
|
+
return [];
|
|
186
|
+
try {
|
|
187
|
+
// Include Unknown (0) + Allowed (1) consent states so new incoming DMs are visible.
|
|
188
|
+
// Without this, only Allowed conversations appear and new contacts are invisible.
|
|
189
|
+
const consentStates = [0, 1]; // Unknown, Allowed
|
|
190
|
+
await this._agent.client.conversations.syncAll(consentStates);
|
|
191
|
+
const conversations = await this._agent.client.conversations.list({ consentStates });
|
|
192
|
+
const results = [];
|
|
193
|
+
for (const conv of conversations) {
|
|
194
|
+
const peerAddress = await this._extractPeerAddress(conv);
|
|
195
|
+
results.push({
|
|
196
|
+
id: conv.id,
|
|
197
|
+
peerAddress,
|
|
198
|
+
createdAt: conv.createdAt.getTime(),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return results;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return [];
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/** Read recent messages from a specific conversation.
|
|
208
|
+
*
|
|
209
|
+
* Syncs conversations first, then fetches messages from the conversation
|
|
210
|
+
* matching the given ID. Returns messages sorted by timestamp (newest first).
|
|
211
|
+
*
|
|
212
|
+
* @param conversationId - The XMTP conversation ID to read from
|
|
213
|
+
* @param limit - Maximum number of messages to return (default 20, max 100)
|
|
214
|
+
* @returns Array of messages with sender, content, and timestamp
|
|
215
|
+
*/
|
|
216
|
+
async getMessages(conversationId, limit = 20) {
|
|
217
|
+
if (!this._ready || !this._agent)
|
|
218
|
+
return [];
|
|
219
|
+
const clampedLimit = Math.max(1, Math.min(100, limit));
|
|
220
|
+
try {
|
|
221
|
+
const consentStates = [0, 1]; // Unknown + Allowed
|
|
222
|
+
await this._agent.client.conversations.syncAll(consentStates);
|
|
223
|
+
const conversations = await this._agent.client.conversations.list({ consentStates });
|
|
224
|
+
const conv = conversations.find(c => c.id === conversationId);
|
|
225
|
+
if (!conv)
|
|
226
|
+
return [];
|
|
227
|
+
// Fetch more than requested to compensate for filtered internal messages
|
|
228
|
+
const rawMessages = await conv.messages({ limit: clampedLimit + 10 });
|
|
229
|
+
// Filter out XMTP internal messages (group membership events, etc.)
|
|
230
|
+
// Only include messages with string content (actual user text).
|
|
231
|
+
const textMessages = rawMessages.filter(msg => typeof msg.content === 'string');
|
|
232
|
+
// Batch-resolve sender inbox IDs to Ethereum addresses
|
|
233
|
+
const uniqueSenders = [...new Set(textMessages.map(m => m.senderInboxId).filter(Boolean))];
|
|
234
|
+
const senderMap = new Map();
|
|
235
|
+
if (uniqueSenders.length > 0 && this._ClientClass) {
|
|
236
|
+
try {
|
|
237
|
+
const states = await this._ClientClass.fetchInboxStates(uniqueSenders, this._xmtpEnv);
|
|
238
|
+
for (let i = 0; i < states.length; i++) {
|
|
239
|
+
const state = states[i];
|
|
240
|
+
if (state?.identifiers) {
|
|
241
|
+
for (const id of state.identifiers) {
|
|
242
|
+
if (id.identifierKind === 0 && id.identifier) {
|
|
243
|
+
senderMap.set(uniqueSenders[i], id.identifier);
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch { /* resolution failed — fall back to inbox IDs */ }
|
|
251
|
+
}
|
|
252
|
+
return textMessages.slice(0, clampedLimit).map(msg => ({
|
|
253
|
+
sender: senderMap.get(msg.senderInboxId) ?? msg.senderInboxId ?? 'unknown',
|
|
254
|
+
content: msg.content,
|
|
255
|
+
contentType: 'text/plain',
|
|
256
|
+
timestamp: Number(msg.sentAtNs / 1000000n), // ns -> ms
|
|
257
|
+
conversationId,
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return [];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/** Read recent messages from a conversation with a specific peer address.
|
|
265
|
+
*
|
|
266
|
+
* Convenience method that finds the conversation by peer address
|
|
267
|
+
* and reads messages from it.
|
|
268
|
+
*
|
|
269
|
+
* @param peerAddress - The Ethereum address of the conversation peer
|
|
270
|
+
* @param limit - Maximum number of messages to return (default 20, max 100)
|
|
271
|
+
* @returns Array of messages, or empty array if no conversation found
|
|
272
|
+
*/
|
|
273
|
+
async getMessagesByPeer(peerAddress, limit = 20) {
|
|
274
|
+
const conversations = await this.getConversations();
|
|
275
|
+
const conv = conversations.find(c => c.peerAddress.toLowerCase() === peerAddress.toLowerCase());
|
|
276
|
+
if (!conv)
|
|
277
|
+
return [];
|
|
278
|
+
return this.getMessages(conv.id, limit);
|
|
279
|
+
}
|
|
280
|
+
/** Whether the client has been successfully initialized and is ready */
|
|
281
|
+
isReady() {
|
|
282
|
+
return this._ready;
|
|
283
|
+
}
|
|
284
|
+
/** Attach a MessageRouter for structured message dispatch.
|
|
285
|
+
*
|
|
286
|
+
* When a router is set and autoReply is enabled (via XMTPConfig or by
|
|
287
|
+
* setting autoReply=true here), incoming messages are automatically
|
|
288
|
+
* routed through the router and responses sent back to the sender.
|
|
289
|
+
*
|
|
290
|
+
* @param router - The MessageRouter instance to use for dispatch
|
|
291
|
+
* @param autoReply - Enable auto-reply (default: uses config value)
|
|
292
|
+
*/
|
|
293
|
+
setRouter(router, autoReply) {
|
|
294
|
+
this._messageRouter = router;
|
|
295
|
+
if (autoReply !== undefined) {
|
|
296
|
+
this._autoReply = autoReply;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/** Tear down the XMTP client.
|
|
300
|
+
*
|
|
301
|
+
* Stops the agent, clears all handlers, caches, and timers.
|
|
302
|
+
*/
|
|
303
|
+
async destroy() {
|
|
304
|
+
this._ready = false;
|
|
305
|
+
this._listening = false;
|
|
306
|
+
if (this._messageStreamAbort) {
|
|
307
|
+
this._messageStreamAbort();
|
|
308
|
+
this._messageStreamAbort = null;
|
|
309
|
+
}
|
|
310
|
+
if (this._convStreamAbort) {
|
|
311
|
+
this._convStreamAbort();
|
|
312
|
+
this._convStreamAbort = null;
|
|
313
|
+
}
|
|
314
|
+
if (this._agent) {
|
|
315
|
+
try {
|
|
316
|
+
await this._agent.stop();
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
// Best-effort cleanup
|
|
320
|
+
}
|
|
321
|
+
this._agent = null;
|
|
322
|
+
}
|
|
323
|
+
this._handlers = [];
|
|
324
|
+
this._reachabilityCache.clear();
|
|
325
|
+
this._messageRouter = null;
|
|
326
|
+
this._autoReply = false;
|
|
327
|
+
if (this._rateLimiter) {
|
|
328
|
+
this._rateLimiter.destroy();
|
|
329
|
+
this._rateLimiter = null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// ── Private ──────────────────────────────────────
|
|
333
|
+
_requireReady() {
|
|
334
|
+
if (!this._ready || !this._agent) {
|
|
335
|
+
throw new AzethError('XMTP client not initialized. Call initialize() first.', 'INVALID_INPUT');
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
/** Start streaming incoming messages and new conversations */
|
|
339
|
+
_startListening() {
|
|
340
|
+
if (this._listening || !this._agent)
|
|
341
|
+
return;
|
|
342
|
+
this._listening = true;
|
|
343
|
+
const agent = this._agent;
|
|
344
|
+
let abortMessages = false;
|
|
345
|
+
let abortConvs = false;
|
|
346
|
+
this._messageStreamAbort = () => { abortMessages = true; };
|
|
347
|
+
this._convStreamAbort = () => { abortConvs = true; };
|
|
348
|
+
// Stream all messages from existing conversations
|
|
349
|
+
void (async () => {
|
|
350
|
+
try {
|
|
351
|
+
await agent.client.conversations.syncAll([0, 1]); // Unknown + Allowed
|
|
352
|
+
const stream = await agent.client.conversations.streamAllMessages();
|
|
353
|
+
for await (const message of stream) {
|
|
354
|
+
if (abortMessages)
|
|
355
|
+
break;
|
|
356
|
+
// Skip our own messages
|
|
357
|
+
if (message.senderInboxId === agent.client.inboxId)
|
|
358
|
+
continue;
|
|
359
|
+
await this._handleIncoming(message);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
if (!abortMessages) {
|
|
364
|
+
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
365
|
+
console.error('[XMTPClient] Message stream error:', msg);
|
|
366
|
+
this._listening = false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
})();
|
|
370
|
+
// Stream new conversations to pick up first messages from new contacts
|
|
371
|
+
void (async () => {
|
|
372
|
+
try {
|
|
373
|
+
const stream = await agent.client.conversations.stream();
|
|
374
|
+
for await (const conv of stream) {
|
|
375
|
+
if (abortConvs)
|
|
376
|
+
break;
|
|
377
|
+
await conv.sync();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
if (!abortConvs) {
|
|
382
|
+
const msg = err instanceof Error ? err.message : 'Unknown error';
|
|
383
|
+
console.error('[XMTPClient] Conversation stream error:', msg);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
})();
|
|
387
|
+
}
|
|
388
|
+
/** Process a single incoming message from the stream */
|
|
389
|
+
async _handleIncoming(message) {
|
|
390
|
+
// Skip XMTP internal messages (group membership events, etc.)
|
|
391
|
+
if (typeof message.content !== 'string')
|
|
392
|
+
return;
|
|
393
|
+
const content = message.content;
|
|
394
|
+
// Audit #10: Drop oversized messages to prevent memory exhaustion
|
|
395
|
+
const MAX_MESSAGE_SIZE = 65_536; // 64KB
|
|
396
|
+
if (content.length > MAX_MESSAGE_SIZE) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
// Rate limit per sender inbox ID
|
|
400
|
+
if (this._rateLimiter && !this._rateLimiter.checkLimit(message.senderInboxId)) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
// XMTPMessage.sender is typed as `string` to accommodate XMTP inbox IDs
|
|
404
|
+
// which are not necessarily valid Ethereum addresses.
|
|
405
|
+
const sender = message.senderInboxId ?? 'unknown';
|
|
406
|
+
const xmtpMessage = {
|
|
407
|
+
sender,
|
|
408
|
+
content,
|
|
409
|
+
contentType: 'text/plain',
|
|
410
|
+
timestamp: Number(message.sentAtNs / 1000000n), // ns -> ms
|
|
411
|
+
conversationId: message.conversationId,
|
|
412
|
+
};
|
|
413
|
+
for (const handler of this._handlers) {
|
|
414
|
+
try {
|
|
415
|
+
await handler(xmtpMessage);
|
|
416
|
+
}
|
|
417
|
+
catch {
|
|
418
|
+
// Individual handler errors should not crash the stream
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Auto-reply via router if enabled
|
|
422
|
+
if (this._messageRouter && this._autoReply) {
|
|
423
|
+
try {
|
|
424
|
+
const response = await this._messageRouter.routeMessage(sender, content);
|
|
425
|
+
// Send response back to the sender's conversation
|
|
426
|
+
const conversations = await this._agent.client.conversations.list({ consentStates: [0, 1] });
|
|
427
|
+
const conv = conversations.find(c => c.id === message.conversationId);
|
|
428
|
+
if (conv) {
|
|
429
|
+
// Use the conversation's send method via DM creation
|
|
430
|
+
// (createDmWithAddress handles finding or creating the conversation)
|
|
431
|
+
const peerAddress = await this._extractPeerAddress(conv);
|
|
432
|
+
const dm = await this._agent.createDmWithAddress(peerAddress);
|
|
433
|
+
await dm.sendText(response);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch {
|
|
437
|
+
// Auto-reply errors should not crash the stream
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
/** Extract peer address from a conversation object.
|
|
442
|
+
*
|
|
443
|
+
* Uses `peerInboxId` + `client.fetchInboxStates()` to resolve the peer's
|
|
444
|
+
* wallet address. This avoids `conv.members()` which throws an internal
|
|
445
|
+
* error in XMTP SDK v5 due to private field access issues on listed conversations.
|
|
446
|
+
*/
|
|
447
|
+
async _extractPeerAddress(conv) {
|
|
448
|
+
try {
|
|
449
|
+
const peerInboxId = conv.peerInboxId;
|
|
450
|
+
if (peerInboxId && this._ClientClass) {
|
|
451
|
+
// Use the static Client.fetchInboxStates — the Agent's client instance
|
|
452
|
+
// doesn't expose this method despite the type declarations claiming so.
|
|
453
|
+
const states = await this._ClientClass.fetchInboxStates([peerInboxId], this._xmtpEnv);
|
|
454
|
+
const state = states?.[0];
|
|
455
|
+
if (state?.identifiers) {
|
|
456
|
+
for (const id of state.identifiers) {
|
|
457
|
+
// identifierKind 0 = Ethereum address
|
|
458
|
+
if (id.identifierKind === 0 && id.identifier) {
|
|
459
|
+
return id.identifier;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
catch {
|
|
466
|
+
// fetchInboxStates can fail on network errors — fall through to sentinel
|
|
467
|
+
}
|
|
468
|
+
// L-13 fix (Audit #8): Return a clearly invalid sentinel rather than the zero address,
|
|
469
|
+
// which could be confused with a real address and cause accidental fund transfers.
|
|
470
|
+
return '0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead';
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
//# sourceMappingURL=xmtp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xmtp.js","sourceRoot":"","sources":["../../src/messaging/xmtp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { type PublicClient, type WalletClient, type Chain, type Transport, type Account } from 'viem';
|
|
2
|
+
import { type AzethContractAddresses, type PaymentAgreement } from '@azeth/common';
|
|
3
|
+
import type { AzethSmartAccountClient } from '../utils/userop.js';
|
|
4
|
+
export interface CreateAgreementParams {
|
|
5
|
+
payee: `0x${string}`;
|
|
6
|
+
token: `0x${string}`;
|
|
7
|
+
amount: bigint;
|
|
8
|
+
interval: number;
|
|
9
|
+
endTime?: bigint;
|
|
10
|
+
maxExecutions?: number;
|
|
11
|
+
totalCap?: bigint;
|
|
12
|
+
}
|
|
13
|
+
export interface AgreementResult {
|
|
14
|
+
agreementId: bigint;
|
|
15
|
+
txHash: `0x${string}`;
|
|
16
|
+
}
|
|
17
|
+
/** Create a recurring payment agreement via ERC-4337 UserOperation.
|
|
18
|
+
*
|
|
19
|
+
* Routes the call through the smart account so msg.sender = smart account address.
|
|
20
|
+
* The SmartAccountClient wraps the PaymentAgreementModule.createAgreement() call
|
|
21
|
+
* inside AzethAccount.execute() via a UserOp submitted to EntryPoint v0.7.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createPaymentAgreement(publicClient: PublicClient<Transport, Chain>, smartAccountClient: AzethSmartAccountClient, addresses: AzethContractAddresses, account: `0x${string}`, params: CreateAgreementParams): Promise<AgreementResult>;
|
|
24
|
+
/** Get agreement details */
|
|
25
|
+
export declare function getAgreement(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<PaymentAgreement>;
|
|
26
|
+
/** Find an active agreement from a given account to a specific payee.
|
|
27
|
+
* Iterates from newest to oldest (newest more likely active).
|
|
28
|
+
* Scans at most MAX_AGREEMENT_SCAN agreements to prevent O(n) RPC calls.
|
|
29
|
+
*
|
|
30
|
+
* @param publicClient - viem public client for on-chain reads
|
|
31
|
+
* @param addresses - Contract addresses containing paymentAgreementModule
|
|
32
|
+
* @param account - The payer's smart account address
|
|
33
|
+
* @param payee - The payee address to match
|
|
34
|
+
* @param token - Optional token address to filter by
|
|
35
|
+
* @returns The first matching active agreement, or null
|
|
36
|
+
*/
|
|
37
|
+
export declare function findAgreementWithPayee(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, payee: `0x${string}`, token?: `0x${string}`): Promise<PaymentAgreement | null>;
|
|
38
|
+
/** Execute a due payment agreement via ERC-4337 UserOperation.
|
|
39
|
+
*
|
|
40
|
+
* Routes the call through the smart account so msg.sender = smart account address.
|
|
41
|
+
*/
|
|
42
|
+
export declare function executeAgreement(publicClient: PublicClient<Transport, Chain>, smartAccountClient: AzethSmartAccountClient, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<`0x${string}`>;
|
|
43
|
+
/** Execute a payment agreement as a third-party keeper.
|
|
44
|
+
*
|
|
45
|
+
* The contract's executeAgreement() is permissionless — any msg.sender can trigger it.
|
|
46
|
+
* When the caller is NOT the payer (i.e., it's a keeper or payee), we cannot build a
|
|
47
|
+
* UserOp for the payer's smart account (AA24 signature mismatch). Instead:
|
|
48
|
+
*
|
|
49
|
+
* - If the keeper has their own smart account: route via the keeper's SmartAccountClient
|
|
50
|
+
* (the keeper's smart account calls the module, which executes on the payer's account)
|
|
51
|
+
* - If the keeper has no smart account: call the module directly from the keeper's EOA
|
|
52
|
+
* via walletClient.writeContract()
|
|
53
|
+
*/
|
|
54
|
+
export declare function executeAgreementAsKeeper(publicClient: PublicClient<Transport, Chain>, keeperSmartAccountClient: AzethSmartAccountClient | null, walletClient: WalletClient<Transport, Chain, Account>, addresses: AzethContractAddresses, payerAccount: `0x${string}`, agreementId: bigint): Promise<`0x${string}`>;
|
|
55
|
+
/** Cancel an active payment agreement via ERC-4337 UserOperation.
|
|
56
|
+
*
|
|
57
|
+
* Routes the call through the smart account so msg.sender = smart account address.
|
|
58
|
+
* Only the payer (agreement creator) can cancel. Immediate effect, no timelock.
|
|
59
|
+
*/
|
|
60
|
+
export declare function cancelAgreement(publicClient: PublicClient<Transport, Chain>, smartAccountClient: AzethSmartAccountClient, addresses: AzethContractAddresses, agreementId: bigint): Promise<`0x${string}`>;
|
|
61
|
+
/** Get the total number of agreements for an account */
|
|
62
|
+
export declare function getAgreementCount(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`): Promise<bigint>;
|
|
63
|
+
/** Check if a payment agreement can be executed right now.
|
|
64
|
+
* Returns [executable, reason] — reason explains why if not executable.
|
|
65
|
+
*/
|
|
66
|
+
export declare function canExecutePayment(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<{
|
|
67
|
+
executable: boolean;
|
|
68
|
+
reason: string;
|
|
69
|
+
}>;
|
|
70
|
+
/** Check if a payment agreement is executable (ignoring interval timing).
|
|
71
|
+
* Checks: active, not expired, not maxed, not capped, guardian whitelist,
|
|
72
|
+
* guardian limits, and payer balance >= accrued amount. */
|
|
73
|
+
export declare function isAgreementExecutable(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<boolean>;
|
|
74
|
+
/** Get comprehensive agreement data in a single RPC call.
|
|
75
|
+
* Combines getAgreement + isAgreementExecutable + isAgreementDue +
|
|
76
|
+
* getNextExecutionTime + getAgreementCount. */
|
|
77
|
+
export declare function getAgreementData(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<{
|
|
78
|
+
agreement: PaymentAgreement;
|
|
79
|
+
executable: boolean;
|
|
80
|
+
reason: string;
|
|
81
|
+
isDue: boolean;
|
|
82
|
+
nextExecutionTime: bigint;
|
|
83
|
+
count: bigint;
|
|
84
|
+
}>;
|
|
85
|
+
/** Get the next execution timestamp for a payment agreement */
|
|
86
|
+
export declare function getNextExecutionTime(publicClient: PublicClient<Transport, Chain>, addresses: AzethContractAddresses, account: `0x${string}`, agreementId: bigint): Promise<bigint>;
|
|
87
|
+
//# sourceMappingURL=agreements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agreements.d.ts","sourceRoot":"","sources":["../../src/payments/agreements.ts"],"names":[],"mappings":"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"}
|