@hybrd/xmtp 1.4.4 → 2.0.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/README.md +209 -319
- package/dist/index.cjs +138 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +131 -78
- package/dist/index.js.map +1 -1
- package/package.json +10 -6
- package/src/client.ts +19 -39
- package/src/index.ts +8 -5
- package/src/lib/jwt.ts +16 -23
- package/src/lib/secret.ts +33 -0
- package/src/plugin.ts +98 -39
- package/src/index.ts.old +0 -145
- package/src/lib/message-listener.test.ts.old +0 -369
- package/src/lib/message-listener.ts.old +0 -343
- package/src/localStorage.ts.old +0 -203
- package/src/plugin.filters.test.ts +0 -158
- package/src/service-client.ts.old +0 -309
- package/src/transactionMonitor.ts.old +0 -275
- package/src/types.ts.old +0 -157
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
import { http, createPublicClient, formatUnits, parseAbi } from "viem"
|
|
2
|
-
import { base, baseSepolia } from "viem/chains"
|
|
3
|
-
import { validateEnvironment } from "./client"
|
|
4
|
-
import { networks } from "./constants"
|
|
5
|
-
|
|
6
|
-
// Get network configuration
|
|
7
|
-
const { XMTP_NETWORK_ID } = validateEnvironment(["XMTP_NETWORK_ID"])
|
|
8
|
-
const networkConfigResult = networks.find(
|
|
9
|
-
(network) => network.networkId === XMTP_NETWORK_ID
|
|
10
|
-
)
|
|
11
|
-
if (!networkConfigResult) {
|
|
12
|
-
throw new Error(`Network ID ${XMTP_NETWORK_ID} not found`)
|
|
13
|
-
}
|
|
14
|
-
// Use a non-null assertion since we've verified it exists
|
|
15
|
-
const networkConfig = networkConfigResult
|
|
16
|
-
|
|
17
|
-
// Create public client for monitoring
|
|
18
|
-
const publicClient = createPublicClient({
|
|
19
|
-
chain: XMTP_NETWORK_ID === "base-mainnet" ? base : baseSepolia,
|
|
20
|
-
transport: http()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
// ERC20 Transfer event ABI
|
|
24
|
-
const erc20Abi = parseAbi([
|
|
25
|
-
"event Transfer(address indexed from, address indexed to, uint256 value)",
|
|
26
|
-
"function balanceOf(address owner) view returns (uint256)"
|
|
27
|
-
])
|
|
28
|
-
|
|
29
|
-
export interface TransactionEvent {
|
|
30
|
-
hash: string
|
|
31
|
-
from: string
|
|
32
|
-
to: string
|
|
33
|
-
value: bigint
|
|
34
|
-
blockNumber: bigint
|
|
35
|
-
timestamp?: bigint
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface MonitoredWallet {
|
|
39
|
-
address: string
|
|
40
|
-
tossId: string
|
|
41
|
-
lastCheckedBlock?: bigint
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export class TransactionMonitor {
|
|
45
|
-
private monitoredWallets: Map<string, MonitoredWallet> = new Map()
|
|
46
|
-
private isMonitoring = false
|
|
47
|
-
private monitoringInterval?: NodeJS.Timeout
|
|
48
|
-
private onTransactionCallback?: (
|
|
49
|
-
event: TransactionEvent,
|
|
50
|
-
wallet: MonitoredWallet
|
|
51
|
-
) => Promise<void>
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Add a wallet address to monitor
|
|
55
|
-
*/
|
|
56
|
-
async addWalletToMonitor(address: string, tossId: string): Promise<void> {
|
|
57
|
-
const lowerAddress = address.toLowerCase()
|
|
58
|
-
console.log(
|
|
59
|
-
`📍 Adding wallet ${lowerAddress} (toss: ${tossId}) to monitoring`
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
// Get current block number as starting point
|
|
63
|
-
const currentBlock = await publicClient.getBlockNumber()
|
|
64
|
-
|
|
65
|
-
this.monitoredWallets.set(lowerAddress, {
|
|
66
|
-
address: lowerAddress,
|
|
67
|
-
tossId,
|
|
68
|
-
lastCheckedBlock: currentBlock
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
console.log(`✅ Now monitoring ${this.monitoredWallets.size} wallets`)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Remove a wallet from monitoring
|
|
76
|
-
*/
|
|
77
|
-
removeWalletFromMonitor(address: string): void {
|
|
78
|
-
const lowerAddress = address.toLowerCase()
|
|
79
|
-
this.monitoredWallets.delete(lowerAddress)
|
|
80
|
-
console.log(`🗑️ Removed wallet ${lowerAddress} from monitoring`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Set callback function for when transactions are detected
|
|
85
|
-
*/
|
|
86
|
-
onTransaction(
|
|
87
|
-
callback: (
|
|
88
|
-
event: TransactionEvent,
|
|
89
|
-
wallet: MonitoredWallet
|
|
90
|
-
) => Promise<void>
|
|
91
|
-
): void {
|
|
92
|
-
this.onTransactionCallback = callback
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Start monitoring for transactions
|
|
97
|
-
*/
|
|
98
|
-
async startMonitoring(intervalMs = 30000): Promise<void> {
|
|
99
|
-
if (this.isMonitoring) {
|
|
100
|
-
console.log("⚠️ Transaction monitoring is already running")
|
|
101
|
-
return
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.isMonitoring = true
|
|
105
|
-
console.log(
|
|
106
|
-
`🔍 Starting transaction monitoring (checking every ${intervalMs / 1000}s)`
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
// Initial check
|
|
110
|
-
await this.checkForNewTransactions()
|
|
111
|
-
|
|
112
|
-
// Set up periodic monitoring
|
|
113
|
-
this.monitoringInterval = setInterval(() => {
|
|
114
|
-
void (async () => {
|
|
115
|
-
try {
|
|
116
|
-
await this.checkForNewTransactions()
|
|
117
|
-
} catch (error) {
|
|
118
|
-
console.error("Error during transaction monitoring:", error)
|
|
119
|
-
}
|
|
120
|
-
})()
|
|
121
|
-
}, intervalMs)
|
|
122
|
-
|
|
123
|
-
console.log("✅ Transaction monitoring started")
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Stop monitoring
|
|
128
|
-
*/
|
|
129
|
-
stopMonitoring(): void {
|
|
130
|
-
if (this.monitoringInterval) {
|
|
131
|
-
clearInterval(this.monitoringInterval)
|
|
132
|
-
this.monitoringInterval = undefined
|
|
133
|
-
}
|
|
134
|
-
this.isMonitoring = false
|
|
135
|
-
console.log("🛑 Transaction monitoring stopped")
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Check for new transactions to monitored wallets
|
|
140
|
-
*/
|
|
141
|
-
private async checkForNewTransactions(): Promise<void> {
|
|
142
|
-
if (this.monitoredWallets.size === 0) {
|
|
143
|
-
return
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
console.debug(
|
|
147
|
-
`🔍 Checking transactions for ${this.monitoredWallets.size} monitored wallets...`
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
const currentBlock = await publicClient.getBlockNumber()
|
|
152
|
-
|
|
153
|
-
for (const [, wallet] of this.monitoredWallets) {
|
|
154
|
-
await this.checkWalletTransactions(wallet, currentBlock)
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
console.error("Error checking for new transactions:", error)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Check transactions for a specific wallet
|
|
163
|
-
*/
|
|
164
|
-
private async checkWalletTransactions(
|
|
165
|
-
wallet: MonitoredWallet,
|
|
166
|
-
currentBlock: bigint
|
|
167
|
-
): Promise<void> {
|
|
168
|
-
try {
|
|
169
|
-
const fromBlock = wallet.lastCheckedBlock || currentBlock - 100n // Check last 100 blocks if no last checked block
|
|
170
|
-
|
|
171
|
-
console.debug(
|
|
172
|
-
`Checking wallet ${wallet.address} from block ${fromBlock} to ${currentBlock}`
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
// Get USDC transfer events to this wallet
|
|
176
|
-
const logs = await publicClient.getLogs({
|
|
177
|
-
address: networkConfig.tokenAddress as `0x${string}`,
|
|
178
|
-
event: erc20Abi[0], // Transfer event
|
|
179
|
-
args: {
|
|
180
|
-
to: wallet.address as `0x${string}`
|
|
181
|
-
},
|
|
182
|
-
fromBlock: fromBlock + 1n, // +1 to avoid checking same block twice
|
|
183
|
-
toBlock: currentBlock
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
console.debug(
|
|
187
|
-
`Found ${logs.length} potential transactions for wallet ${wallet.address}`
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
for (const log of logs) {
|
|
191
|
-
const event: TransactionEvent = {
|
|
192
|
-
hash: log.transactionHash,
|
|
193
|
-
from: log.args.from as string,
|
|
194
|
-
to: log.args.to as string,
|
|
195
|
-
value: log.args.value as bigint,
|
|
196
|
-
blockNumber: log.blockNumber || 0n
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
console.log(`🔔 New transaction detected: ${event.hash}`)
|
|
200
|
-
console.log(` From: ${event.from}`)
|
|
201
|
-
console.log(` To: ${event.to}`)
|
|
202
|
-
console.log(
|
|
203
|
-
` Amount: ${formatUnits(event.value, networkConfig.decimals)} USDC`
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
// Call the callback if set
|
|
207
|
-
if (this.onTransactionCallback) {
|
|
208
|
-
try {
|
|
209
|
-
await this.onTransactionCallback(event, wallet)
|
|
210
|
-
} catch (callbackError) {
|
|
211
|
-
console.error("Error in transaction callback:", callbackError)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Update last checked block for this wallet
|
|
217
|
-
wallet.lastCheckedBlock = currentBlock
|
|
218
|
-
} catch (error) {
|
|
219
|
-
console.error(
|
|
220
|
-
`Error checking transactions for wallet ${wallet.address}:`,
|
|
221
|
-
error
|
|
222
|
-
)
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Get current wallet balance
|
|
228
|
-
*/
|
|
229
|
-
async getWalletBalance(address: string): Promise<string> {
|
|
230
|
-
try {
|
|
231
|
-
const balance = await publicClient.readContract({
|
|
232
|
-
address: networkConfig.tokenAddress as `0x${string}`,
|
|
233
|
-
abi: erc20Abi,
|
|
234
|
-
functionName: "balanceOf",
|
|
235
|
-
args: [address as `0x${string}`]
|
|
236
|
-
})
|
|
237
|
-
return formatUnits(balance, networkConfig.decimals)
|
|
238
|
-
} catch (error) {
|
|
239
|
-
console.error(`Error getting balance for ${address}:`, error)
|
|
240
|
-
return "0"
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Check if monitoring is active
|
|
246
|
-
*/
|
|
247
|
-
isActive(): boolean {
|
|
248
|
-
return this.isMonitoring
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
/**
|
|
252
|
-
* Get list of monitored wallets
|
|
253
|
-
*/
|
|
254
|
-
getMonitoredWallets(): MonitoredWallet[] {
|
|
255
|
-
return Array.from(this.monitoredWallets.values())
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Manual balance check for discrepancies
|
|
260
|
-
*/
|
|
261
|
-
async performBalanceAudit(): Promise<void> {
|
|
262
|
-
console.log("🔍 Performing balance audit for monitored wallets...")
|
|
263
|
-
|
|
264
|
-
for (const [address, wallet] of this.monitoredWallets) {
|
|
265
|
-
try {
|
|
266
|
-
const balance = await this.getWalletBalance(address)
|
|
267
|
-
console.log(
|
|
268
|
-
`💰 Wallet ${address} (toss: ${wallet.tossId}): ${balance} USDC`
|
|
269
|
-
)
|
|
270
|
-
} catch (error) {
|
|
271
|
-
console.error(`Error checking balance for ${address}:`, error)
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
package/src/types.ts.old
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview XMTP Types
|
|
3
|
-
*
|
|
4
|
-
* Type definitions for both the XMTP core client and service client library.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { GroupUpdated } from "@xmtp/content-type-group-updated"
|
|
8
|
-
import { Reaction } from "@xmtp/content-type-reaction"
|
|
9
|
-
import { Reply } from "@xmtp/content-type-reply"
|
|
10
|
-
import { TransactionReference } from "@xmtp/content-type-transaction-reference"
|
|
11
|
-
import { WalletSendCallsParams } from "@xmtp/content-type-wallet-send-calls"
|
|
12
|
-
import { Client, Conversation, DecodedMessage } from "@xmtp/node-sdk"
|
|
13
|
-
import type { Resolver } from "./resolver/resolver"
|
|
14
|
-
|
|
15
|
-
export type HonoVariables = {
|
|
16
|
-
xmtpClient: XmtpClient
|
|
17
|
-
resolver?: Resolver
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// ===================================================================
|
|
21
|
-
// XMTP Core Client Types
|
|
22
|
-
// ===================================================================
|
|
23
|
-
|
|
24
|
-
type Codec =
|
|
25
|
-
| GroupUpdated
|
|
26
|
-
| Reaction
|
|
27
|
-
| Reply
|
|
28
|
-
| TransactionReference
|
|
29
|
-
| WalletSendCallsParams
|
|
30
|
-
|
|
31
|
-
export type XmtpClient = Client<string | Codec>
|
|
32
|
-
export type XmtpConversation = Conversation<string | Codec>
|
|
33
|
-
export type XmtpMessage = DecodedMessage<string | Codec>
|
|
34
|
-
export type XmtpSender = {
|
|
35
|
-
address: string
|
|
36
|
-
inboxId: string
|
|
37
|
-
name: string
|
|
38
|
-
basename?: string
|
|
39
|
-
}
|
|
40
|
-
export type XmtpSubjects = Record<string, `0x${string}`>
|
|
41
|
-
|
|
42
|
-
export interface MessageEvent {
|
|
43
|
-
conversation: XmtpConversation
|
|
44
|
-
message: XmtpMessage
|
|
45
|
-
rootMessage: XmtpMessage
|
|
46
|
-
parentMessage?: XmtpMessage // The directly referenced message if this is a reply
|
|
47
|
-
sender: XmtpSender
|
|
48
|
-
subjects: XmtpSubjects
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ===================================================================
|
|
52
|
-
// XMTP Service Client Types
|
|
53
|
-
// ===================================================================
|
|
54
|
-
|
|
55
|
-
export interface XmtpServiceClientConfig {
|
|
56
|
-
serviceUrl: string
|
|
57
|
-
serviceToken: string
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface TransactionCall {
|
|
61
|
-
to: string
|
|
62
|
-
data: string
|
|
63
|
-
gas?: string
|
|
64
|
-
value?: string
|
|
65
|
-
metadata?: Record<string, unknown>
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface TransactionRequest {
|
|
69
|
-
fromAddress: string
|
|
70
|
-
chainId: string
|
|
71
|
-
calls: TransactionCall[]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface XmtpServiceResponse<T = unknown> {
|
|
75
|
-
success: boolean
|
|
76
|
-
data?: T
|
|
77
|
-
error?: string
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface XmtpServiceMessage {
|
|
81
|
-
id: string
|
|
82
|
-
conversationId: string
|
|
83
|
-
content: string | Record<string, unknown>
|
|
84
|
-
senderInboxId: string
|
|
85
|
-
sentAt: string
|
|
86
|
-
contentType?: {
|
|
87
|
-
typeId: string
|
|
88
|
-
authorityId?: string
|
|
89
|
-
versionMajor?: number
|
|
90
|
-
versionMinor?: number
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export interface XmtpRootMessageResponse {
|
|
95
|
-
id: string
|
|
96
|
-
conversationId: string
|
|
97
|
-
content: string | Record<string, unknown>
|
|
98
|
-
senderInboxId: string
|
|
99
|
-
sentAt: string
|
|
100
|
-
contentType?: {
|
|
101
|
-
typeId: string
|
|
102
|
-
authorityId?: string
|
|
103
|
-
versionMajor?: number
|
|
104
|
-
versionMinor?: number
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Function parameter types
|
|
109
|
-
export interface SendMessageParams {
|
|
110
|
-
content: string
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export interface SendReplyParams {
|
|
114
|
-
content: string
|
|
115
|
-
messageId: string
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface SendReactionParams {
|
|
119
|
-
messageId: string
|
|
120
|
-
emoji: string
|
|
121
|
-
action: "added" | "removed"
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export interface SendTransactionParams extends TransactionRequest {}
|
|
125
|
-
|
|
126
|
-
export interface GetMessageParams {
|
|
127
|
-
messageId: string
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface GetRootMessageParams {
|
|
131
|
-
messageId: string
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Response types
|
|
135
|
-
export interface SendMessageResponse {
|
|
136
|
-
success: boolean
|
|
137
|
-
action: "send"
|
|
138
|
-
conversationId: string
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export interface SendReplyResponse {
|
|
142
|
-
success: boolean
|
|
143
|
-
action: "reply"
|
|
144
|
-
conversationId: string
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export interface SendReactionResponse {
|
|
148
|
-
success: boolean
|
|
149
|
-
action: "react"
|
|
150
|
-
conversationId: string
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export interface SendTransactionResponse {
|
|
154
|
-
success: boolean
|
|
155
|
-
action: "transaction"
|
|
156
|
-
conversationId: string
|
|
157
|
-
}
|