clawntenna 0.11.2 → 0.11.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/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/chains.ts","../src/contracts.ts","../src/crypto/encrypt.ts","../src/types.ts","../src/constants.ts","../src/crypto/ecdh.ts","../src/escrow.ts","../src/rpc-errors.ts","../src/retry.ts","../src/serialize.ts"],"sourcesContent":["import { ethers } from 'ethers';\nimport { CHAINS } from './chains.js';\nimport { REGISTRY_ABI, KEY_MANAGER_ABI, SCHEMA_REGISTRY_ABI, IDENTITY_REGISTRY_ABI, ESCROW_ABI } from './contracts.js';\nimport {\n derivePublicTopicKey,\n deriveKeyFromPassphrase,\n encryptMessage,\n decryptMessage,\n} from './crypto/encrypt.js';\nimport {\n deriveKeypairFromSignature,\n keypairFromPrivateKey,\n computeSharedSecret,\n deriveAESKeyFromSecret,\n encryptTopicKeyForUser,\n decryptTopicKey,\n bytesToHex,\n hexToBytes,\n} from './crypto/ecdh.js';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { AccessLevel, DepositStatus } from './types.js';\nimport type {\n ClawtennaOptions,\n ReadOptions,\n SendOptions,\n Message,\n Topic,\n Application,\n Member,\n TopicMessageFee,\n SchemaInfo,\n TopicSchemaBinding,\n ChainName,\n EscrowDeposit,\n EscrowConfig,\n DepositTimer,\n EnrichedDeposit,\n RecipientStats,\n WalletCredibility,\n} from './types.js';\nimport {\n formatTimeout,\n isDepositExpired,\n timeUntilRefund,\n getDepositDeadline,\n} from './escrow.js';\nimport { classifyRpcError } from './rpc-errors.js';\nimport { withRetry } from './retry.js';\n\nexport class Clawntenna {\n readonly provider: ethers.JsonRpcProvider;\n readonly chainName: ChainName;\n\n private _signer: ethers.Signer | null;\n private _address: string | null;\n private _registry: ethers.Contract;\n private _keyManager: ethers.Contract;\n private _schemaRegistry: ethers.Contract;\n private _identityRegistry: ethers.Contract | null;\n private _escrow: ethers.Contract | null;\n\n /** @deprecated Use `signer` instead. */\n get wallet(): ethers.Signer | null { return this._signer; }\n get signer(): ethers.Signer | null { return this._signer; }\n get registry(): ethers.Contract { return this._registry; }\n get keyManager(): ethers.Contract { return this._keyManager; }\n get schemaRegistry(): ethers.Contract { return this._schemaRegistry; }\n get identityRegistry(): ethers.Contract | null { return this._identityRegistry; }\n get escrow(): ethers.Contract | null { return this._escrow; }\n\n // In-memory ECDH state\n private ecdhPrivateKey: Uint8Array | null = null;\n private ecdhPublicKey: Uint8Array | null = null;\n private topicKeys: Map<number, Uint8Array> = new Map();\n\n // Token decimals cache (ERC-20 decimals never change)\n private tokenDecimalsCache: Map<string, number> = new Map();\n private static ERC20_DECIMALS_ABI = ['function decimals() view returns (uint8)'];\n\n constructor(options: ClawtennaOptions = {}) {\n const chainName = options.chain ?? 'base';\n const chain = CHAINS[chainName];\n if (!chain) throw new Error(`Unsupported chain: ${chainName}`);\n this.chainName = chainName;\n\n const rpcUrl = options.rpcUrl ?? chain.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n\n const registryAddr = options.registryAddress ?? chain.registry;\n const keyManagerAddr = options.keyManagerAddress ?? chain.keyManager;\n const schemaRegistryAddr = options.schemaRegistryAddress ?? chain.schemaRegistry;\n const escrowAddr = options.escrowAddress ?? chain.escrow;\n\n const wallet = options.privateKey\n ? new ethers.Wallet(options.privateKey, this.provider)\n : null;\n const runner = wallet ?? this.provider;\n\n this._signer = wallet;\n this._address = wallet?.address ?? null;\n this._registry = new ethers.Contract(registryAddr, REGISTRY_ABI, runner);\n this._keyManager = new ethers.Contract(keyManagerAddr, KEY_MANAGER_ABI, runner);\n this._schemaRegistry = new ethers.Contract(schemaRegistryAddr, SCHEMA_REGISTRY_ABI, runner);\n this._identityRegistry = chain.identityRegistry\n ? new ethers.Contract(chain.identityRegistry, IDENTITY_REGISTRY_ABI, runner)\n : null;\n this._escrow = escrowAddr\n ? new ethers.Contract(escrowAddr, ESCROW_ABI, runner)\n : null;\n }\n\n /**\n * Connect an external signer (e.g. from BrowserProvider).\n * Reconnects all contract instances to the new signer.\n */\n async connectSigner(signer: ethers.Signer): Promise<void> {\n this._address = await signer.getAddress();\n this._signer = signer;\n this._registry = this._registry.connect(signer) as ethers.Contract;\n this._keyManager = this._keyManager.connect(signer) as ethers.Contract;\n this._schemaRegistry = this._schemaRegistry.connect(signer) as ethers.Contract;\n if (this._identityRegistry) {\n this._identityRegistry = this._identityRegistry.connect(signer) as ethers.Contract;\n }\n if (this._escrow) {\n this._escrow = this._escrow.connect(signer) as ethers.Contract;\n }\n }\n\n private requireSigner(): ethers.Signer {\n if (!this._signer) {\n throw new Error('Signer required. Pass privateKey in constructor or call connectSigner().');\n }\n return this._signer;\n }\n\n private requireAddress(): string {\n if (!this._address) {\n throw new Error('Signer required. Pass privateKey in constructor or call connectSigner().');\n }\n return this._address;\n }\n\n private async _wrapRpcError<T>(fn: () => Promise<T>, method: string): Promise<T> {\n try {\n return await withRetry(fn);\n } catch (err) {\n if (err instanceof Error) {\n const hint = classifyRpcError(err, { method, chainName: this.chainName });\n if (hint) throw new Error(hint, { cause: err });\n }\n throw err;\n }\n }\n\n get address(): string | null {\n return this._address;\n }\n\n // ===== MESSAGING =====\n\n /**\n * Send an encrypted message to a topic.\n * Automatically determines encryption key based on topic access level.\n */\n async sendMessage(topicId: number, text: string, options?: SendOptions): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n\n // Auto-check: refuse to reply to a message whose escrow deposit was refunded\n if (options?.replyTo && this.escrow && !options?.skipRefundCheck) {\n const refunded = await this.isMessageRefunded(options.replyTo);\n if (refunded) {\n throw new Error(`Cannot reply: escrow deposit was refunded (tx: ${options.replyTo})`);\n }\n }\n\n let replyText = options?.replyText;\n let replyAuthor = options?.replyAuthor;\n\n // Auto-resolve reply metadata if replyTo is set but text/author aren't\n if (options?.replyTo && (!replyText || !replyAuthor)) {\n try {\n const messages = await this.readMessages(topicId, { limit: 50 });\n const original = messages.find(m => m.txHash === options.replyTo);\n if (original) {\n replyText = replyText || original.text.slice(0, 100);\n replyAuthor = replyAuthor || original.sender;\n }\n } catch {\n // Non-fatal: reply will still work, just without cached text/author\n }\n }\n\n const key = await this.getEncryptionKey(topicId);\n const encrypted = encryptMessage(text, key, {\n replyTo: options?.replyTo,\n replyText,\n replyAuthor,\n mentions: options?.mentions,\n });\n\n return this.registry.sendMessage(topicId, ethers.toUtf8Bytes(encrypted));\n }\n\n /**\n * Read and decrypt recent messages from a topic.\n */\n async readMessages(topicId: number, options?: ReadOptions): Promise<Message[]> {\n const limit = options?.limit ?? 50;\n const key = await this.getEncryptionKey(topicId);\n const filter = this.registry.filters.MessageSent(topicId);\n\n // Chunked log fetching to stay within RPC limits (e.g. Avalanche 2048 block cap)\n const CHUNK_SIZE = 2000;\n const currentBlock = await this.provider.getBlockNumber();\n const chain = CHAINS[this.chainName];\n const maxRange = options?.fromBlock != null ? currentBlock - options.fromBlock : chain.defaultLookback;\n const startBlock = currentBlock - maxRange;\n\n const allEvents: ethers.EventLog[] = [];\n let toBlock = currentBlock;\n\n while (toBlock > startBlock && allEvents.length < limit) {\n const chunkFrom = Math.max(toBlock - CHUNK_SIZE + 1, startBlock);\n const events = await this._wrapRpcError(\n () => this.registry.queryFilter(filter, chunkFrom, toBlock),\n 'readMessages',\n );\n // Prepend since we're walking backwards\n allEvents.unshift(...(events as ethers.EventLog[]));\n toBlock = chunkFrom - 1;\n }\n\n const recent = allEvents.slice(-limit);\n const messages: Message[] = [];\n\n for (const log of recent) {\n const payloadStr = ethers.toUtf8String(log.args.payload);\n const parsed = decryptMessage(payloadStr, key);\n\n messages.push({\n topicId,\n sender: log.args.sender,\n text: parsed?.text ?? '[decryption failed]',\n replyTo: parsed?.replyTo ?? null,\n mentions: parsed?.mentions ?? null,\n timestamp: Number(log.args.timestamp),\n txHash: log.transactionHash,\n blockNumber: log.blockNumber,\n });\n }\n\n return messages;\n }\n\n /**\n * Subscribe to real-time messages on a topic.\n * Returns an unsubscribe function.\n */\n onMessage(\n topicId: number,\n callback: (msg: Message) => void\n ): () => void {\n let key: Uint8Array | null = null;\n\n // Pre-derive key, then start listening\n this.getEncryptionKey(topicId).then((k) => {\n key = k;\n });\n\n const handler = (\n tId: bigint,\n sender: string,\n payload: string,\n timestamp: bigint,\n event: ethers.EventLog\n ) => {\n if (!key) return;\n const payloadStr = ethers.toUtf8String(payload);\n const parsed = decryptMessage(payloadStr, key);\n\n callback({\n topicId: Number(tId),\n sender,\n text: parsed?.text ?? '[decryption failed]',\n replyTo: parsed?.replyTo ?? null,\n mentions: parsed?.mentions ?? null,\n timestamp: Number(timestamp),\n txHash: event.transactionHash,\n blockNumber: event.blockNumber,\n });\n };\n\n this.registry.on(this.registry.filters.MessageSent(topicId), handler);\n return () => {\n this.registry.off(this.registry.filters.MessageSent(topicId), handler);\n };\n }\n\n // ===== NICKNAMES =====\n\n async setNickname(appId: number, nickname: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setNickname(appId, nickname);\n }\n\n async getNickname(appId: number, address: string): Promise<string> {\n return this.registry.getNickname(appId, address);\n }\n\n async hasNickname(appId: number, address: string): Promise<boolean> {\n return this.registry.hasNickname(appId, address);\n }\n\n async canChangeNickname(appId: number, address: string): Promise<{ canChange: boolean; timeRemaining: bigint }> {\n const [canChange, timeRemaining] = await this.registry.canChangeNickname(appId, address);\n return { canChange, timeRemaining };\n }\n\n async clearNickname(appId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.clearNickname(appId);\n }\n\n async setNicknameCooldown(appId: number, cooldownSeconds: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setNicknameCooldown(appId, cooldownSeconds);\n }\n\n async getNicknameCooldown(appId: number): Promise<bigint> {\n return this.registry.appNicknameCooldown(appId);\n }\n\n // ===== TOPICS =====\n\n async createTopic(\n appId: number,\n name: string,\n description: string,\n accessLevel: AccessLevel\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.createTopic(appId, name, description, accessLevel);\n }\n\n async getTopic(topicId: number): Promise<Topic> {\n return this._wrapRpcError(async () => {\n const t = await this.registry.getTopic(topicId);\n return {\n id: t.id,\n applicationId: t.applicationId,\n name: t.name,\n description: t.description,\n owner: t.owner,\n creator: t.creator,\n createdAt: t.createdAt,\n lastMessageAt: t.lastMessageAt,\n messageCount: t.messageCount,\n accessLevel: Number(t.accessLevel),\n active: t.active,\n };\n }, 'getTopic');\n }\n\n async getApplicationTopics(appId: number): Promise<bigint[]> {\n return this.registry.getApplicationTopics(appId);\n }\n\n async getTopicCount(): Promise<number> {\n const count = await this.registry.topicCount();\n return Number(count);\n }\n\n async setTopicPermission(\n topicId: number,\n user: string,\n permission: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setTopicPermission(topicId, user, permission);\n }\n\n async getTopicPermission(topicId: number, user: string): Promise<number> {\n const perm = await this.registry.getTopicPermission(topicId, user);\n return Number(perm);\n }\n\n // ===== MEMBERS =====\n\n async addMember(\n appId: number,\n address: string,\n nickname: string,\n roles: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.addMember(appId, address, nickname, roles);\n }\n\n async removeMember(appId: number, address: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.removeMember(appId, address);\n }\n\n async updateMemberRoles(\n appId: number,\n address: string,\n roles: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.updateMemberRoles(appId, address, roles);\n }\n\n async getMember(appId: number, address: string): Promise<Member> {\n const m = await this.registry.getMember(appId, address);\n return {\n account: m.account,\n nickname: m.nickname,\n roles: Number(m.roles),\n joinedAt: m.joinedAt,\n };\n }\n\n async isMember(appId: number, address: string): Promise<boolean> {\n return this.registry.isMember(appId, address);\n }\n\n async getApplicationMembers(appId: number): Promise<string[]> {\n return this.registry.getApplicationMembers(appId);\n }\n\n // ===== ACCESS CHECKS =====\n\n async canRead(topicId: number, address: string): Promise<boolean> {\n return this.registry.canReadTopic(topicId, address);\n }\n\n async canWrite(topicId: number, address: string): Promise<boolean> {\n return this.registry.canWriteToTopic(topicId, address);\n }\n\n // ===== APPLICATIONS =====\n\n async createApplication(\n name: string,\n description: string,\n frontendUrl: string,\n allowPublicTopicCreation: boolean\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.createApplication(name, description, frontendUrl, allowPublicTopicCreation);\n }\n\n async getApplicationCount(): Promise<number> {\n const count = await this.registry.applicationCount();\n return Number(count);\n }\n\n async updateFrontendUrl(appId: number, frontendUrl: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.updateApplicationFrontendUrl(appId, frontendUrl);\n }\n\n async getApplication(appId: number): Promise<Application> {\n return this._wrapRpcError(async () => {\n const a = await this.registry.getApplication(appId);\n return {\n id: a.id,\n name: a.name,\n description: a.description,\n frontendUrl: a.frontendUrl,\n owner: a.owner,\n createdAt: a.createdAt,\n memberCount: Number(a.memberCount),\n topicCount: Number(a.topicCount),\n active: a.active,\n allowPublicTopicCreation: a.allowPublicTopicCreation,\n topicCreationFeeToken: a.topicCreationFeeToken,\n topicCreationFeeAmount: a.topicCreationFeeAmount,\n };\n }, 'getApplication');\n }\n\n // ===== FEES =====\n\n async getTopicMessageFee(topicId: number): Promise<TopicMessageFee> {\n const [token, amount] = await this.registry.getTopicMessageFee(topicId);\n return { token, amount };\n }\n\n /**\n * Set topic creation fee for an application (app admin only).\n * feeAmount accepts:\n * - bigint: raw token units (e.g. 150000n for 0.15 USDC)\n * - string | number: human-readable amount — decimals are auto-resolved from the token contract\n * (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)\n */\n async setTopicCreationFee(\n appId: number,\n feeToken: string,\n feeAmount: bigint | string | number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const rawAmount = typeof feeAmount === 'bigint'\n ? feeAmount\n : await this.parseTokenAmount(feeToken, feeAmount);\n return this.registry.setTopicCreationFee(appId, feeToken, rawAmount);\n }\n\n /**\n * Set per-message fee for a topic (topic admin only).\n * feeAmount accepts:\n * - bigint: raw token units (e.g. 150000n for 0.15 USDC)\n * - string | number: human-readable amount — decimals are auto-resolved from the token contract\n * (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)\n */\n async setTopicMessageFee(\n topicId: number,\n feeToken: string,\n feeAmount: bigint | string | number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const rawAmount = typeof feeAmount === 'bigint'\n ? feeAmount\n : await this.parseTokenAmount(feeToken, feeAmount);\n return this.registry.setTopicMessageFee(topicId, feeToken, rawAmount);\n }\n\n // ===== TOKEN AMOUNTS =====\n\n /**\n * Get the number of decimals for an ERC-20 token.\n * Returns 18 for native ETH (address(0)).\n * Results are cached per token address.\n */\n async getTokenDecimals(tokenAddress: string): Promise<number> {\n if (tokenAddress === ethers.ZeroAddress) return 18;\n\n const key = tokenAddress.toLowerCase();\n const cached = this.tokenDecimalsCache.get(key);\n if (cached !== undefined) return cached;\n\n const erc20 = new ethers.Contract(tokenAddress, Clawntenna.ERC20_DECIMALS_ABI, this.provider);\n const decimals = Number(await erc20.decimals());\n this.tokenDecimalsCache.set(key, decimals);\n return decimals;\n }\n\n /**\n * Convert a human-readable token amount to raw units (bigint).\n * Looks up the token's on-chain decimals automatically.\n *\n * Examples:\n * parseTokenAmount('0xUSDC...', '0.15') → 150000n (USDC = 6 decimals)\n * parseTokenAmount('0xUSDC...', 10) → 10000000n (USDC = 6 decimals)\n * parseTokenAmount(ZeroAddress, '0.01') → 10000000000000000n (native ETH = 18 decimals)\n */\n async parseTokenAmount(tokenAddress: string, amount: string | number): Promise<bigint> {\n const decimals = await this.getTokenDecimals(tokenAddress);\n return ethers.parseUnits(String(amount), decimals);\n }\n\n /**\n * Convert raw token units (bigint) to a human-readable string.\n * Looks up the token's on-chain decimals automatically.\n *\n * Examples:\n * formatTokenAmount('0xUSDC...', 150000n) → '0.15'\n * formatTokenAmount(ZeroAddress, 10000000000000000n) → '0.01'\n */\n async formatTokenAmount(tokenAddress: string, amount: bigint): Promise<string> {\n const decimals = await this.getTokenDecimals(tokenAddress);\n return ethers.formatUnits(amount, decimals);\n }\n\n // ===== ESCROW =====\n\n private requireEscrow(): ethers.Contract {\n if (!this.escrow) {\n throw new Error('Escrow not available on this chain. Use baseSepolia or pass escrowAddress.');\n }\n return this.escrow;\n }\n\n /**\n * Enable escrow for a topic (topic owner only).\n */\n async enableEscrow(topicId: number, timeout: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().enableEscrow(topicId, timeout);\n }\n\n /**\n * Disable escrow for a topic (topic owner only).\n */\n async disableEscrow(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().disableEscrow(topicId);\n }\n\n /**\n * Check if escrow is enabled for a topic.\n */\n async isEscrowEnabled(topicId: number): Promise<boolean> {\n return this.requireEscrow().isEscrowEnabled(topicId);\n }\n\n /**\n * Get escrow config for a topic (enabled + timeout).\n */\n async getEscrowConfig(topicId: number): Promise<EscrowConfig> {\n const escrow = this.requireEscrow();\n const [enabled, timeout] = await Promise.all([\n escrow.isEscrowEnabled(topicId) as Promise<boolean>,\n escrow.topicEscrowTimeout(topicId) as Promise<bigint>,\n ]);\n return { enabled, timeout };\n }\n\n /**\n * Get full deposit details by ID.\n */\n async getDeposit(depositId: number): Promise<EscrowDeposit> {\n const d = await this.requireEscrow().getDeposit(depositId);\n return {\n id: d.id,\n topicId: d.topicId,\n sender: d.sender,\n recipient: d.recipient,\n token: d.token,\n amount: d.amount,\n appOwner: d.appOwner,\n depositedAt: d.depositedAt,\n timeout: d.timeout,\n status: Number(d.status) as DepositStatus,\n };\n }\n\n /**\n * Get deposit status (0=Pending, 1=Released, 2=Refunded).\n */\n async getDepositStatus(depositId: number): Promise<DepositStatus> {\n const status = await this.requireEscrow().getDepositStatus(depositId);\n return Number(status) as DepositStatus;\n }\n\n /**\n * Get pending deposit IDs for a topic.\n */\n async getPendingDeposits(topicId: number): Promise<bigint[]> {\n return this.requireEscrow().getPendingDeposits(topicId);\n }\n\n /**\n * Check if a deposit can be refunded (timeout expired and still pending).\n */\n async canClaimRefund(depositId: number): Promise<boolean> {\n return this.requireEscrow().canClaimRefund(depositId);\n }\n\n /**\n * Claim a refund for a single deposit.\n */\n async claimRefund(depositId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().claimRefund(depositId);\n }\n\n /**\n * Batch claim refunds for multiple deposits.\n */\n async batchClaimRefunds(depositIds: number[]): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().batchClaimRefunds(depositIds);\n }\n\n /**\n * Respond to specific deposits by sending a message and binding it on-chain (topic owner only).\n * This creates an auditable record: \"at block X, owner sent message Y for deposits [a, b, c]\".\n * Each deposit must have a recorded response before it can be released.\n * @param topicId Topic ID\n * @param payload Message payload (encrypted response)\n * @param depositIds Array of deposit IDs being responded to\n */\n async respondToDeposits(topicId: number, payload: string | Uint8Array, depositIds: number[]): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.respondToDeposits(topicId, payload, depositIds);\n }\n\n /**\n * Release a single escrow deposit (topic owner only).\n * Requires a prior respondToDeposits() call for this deposit.\n * @param depositId Deposit ID to release\n * @param messageRef Optional off-chain message reference (default 0)\n */\n async releaseDeposit(depositId: number, messageRef: number = 0): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().releaseDeposit(depositId, messageRef);\n }\n\n /**\n * Batch release escrow deposits (topic owner only, max 50).\n * Requires a prior respondToDeposits() call for each deposit.\n * @param depositIds Array of deposit IDs to release\n * @param messageRefs Optional array of off-chain references (empty or same length)\n */\n async batchReleaseDeposits(depositIds: number[], messageRefs: number[] = []): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().batchReleaseDeposits(depositIds, messageRefs);\n }\n\n /**\n * Get the message reference for a released deposit.\n */\n async getDepositMessageRef(depositId: number): Promise<bigint> {\n return this.requireEscrow().getDepositMessageRef(depositId);\n }\n\n /**\n * Check if a deposit has a recorded owner response.\n */\n async hasResponse(depositId: number): Promise<boolean> {\n return this.requireEscrow().hasResponse(depositId);\n }\n\n /**\n * Get lifetime escrow stats for a wallet (V4).\n */\n async getRecipientStats(wallet: string): Promise<RecipientStats> {\n const s = await this.requireEscrow().getRecipientStats(wallet);\n return {\n depositsReceived: BigInt(s.depositsReceived),\n depositsReleased: BigInt(s.depositsReleased),\n depositsRefunded: BigInt(s.depositsRefunded),\n depositsExpired: BigInt(s.depositsExpired),\n };\n }\n\n /**\n * Get credibility snapshot for a wallet (V4).\n * Returns response rate as 0-100 percentage and lifetime escrow totals.\n */\n async getWalletCredibility(wallet: string): Promise<WalletCredibility> {\n const escrow = this.requireEscrow();\n const cred = await escrow.getCredibility(wallet);\n\n // Convert basis points to percentage\n const responseRate = Number(cred.responseRate) / 100;\n\n // Try to format amounts using the first deposit's token, fall back to null\n let formattedEarned: string | null = null;\n let formattedRefunded: string | null = null;\n try {\n // For native ETH (most common), format as ether\n formattedEarned = ethers.formatEther(cred.totalEarned);\n formattedRefunded = ethers.formatEther(cred.totalRefunded);\n } catch {\n // Non-fatal\n }\n\n return {\n responseRate,\n depositsReceived: BigInt(cred.depositsReceived),\n depositsReleased: BigInt(cred.depositsReleased),\n depositsRefunded: BigInt(cred.depositsRefunded),\n totalEarned: BigInt(cred.totalEarned),\n totalRefunded: BigInt(cred.totalRefunded),\n formattedEarned,\n formattedRefunded,\n };\n }\n\n /**\n * Get the on-chain total amount earned by a wallet via escrow releases (V4).\n */\n async getAmountEarned(wallet: string): Promise<bigint> {\n return this.requireEscrow().amountEarned(wallet);\n }\n\n /**\n * Get the on-chain total amount lost to refunds for a wallet (V4).\n */\n async getAmountRefunded(wallet: string): Promise<bigint> {\n return this.requireEscrow().amountRefunded(wallet);\n }\n\n /**\n * Get response rate for a wallet as basis points (0-10000) (V4).\n */\n async getResponseRate(wallet: string): Promise<number> {\n const rate = await this.requireEscrow().getResponseRate(wallet);\n return Number(rate);\n }\n\n /**\n * Parse a transaction receipt to extract the depositId from a DepositRecorded event.\n * Returns null if no DepositRecorded event is found (e.g. no escrow on this tx).\n */\n async getMessageDepositId(txHash: string): Promise<bigint | null> {\n if (!this.escrow) return null;\n\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (!receipt) return null;\n\n const iface = this.escrow.interface;\n for (const log of receipt.logs) {\n try {\n const parsed = iface.parseLog(log);\n if (parsed?.name === 'DepositRecorded') {\n return parsed.args.depositId;\n }\n } catch { /* skip non-matching logs */ }\n }\n return null;\n }\n\n /**\n * Get the deposit status for a message by its transaction hash.\n * Returns null if the message has no associated escrow deposit.\n */\n async getMessageDepositStatus(txHash: string): Promise<DepositStatus | null> {\n const depositId = await this.getMessageDepositId(txHash);\n if (depositId === null) return null;\n return this.getDepositStatus(Number(depositId));\n }\n\n /**\n * Check if a message's escrow deposit was refunded.\n * Returns false if no escrow deposit exists for the tx.\n */\n async isMessageRefunded(txHash: string): Promise<boolean> {\n const status = await this.getMessageDepositStatus(txHash);\n return status === DepositStatus.Refunded;\n }\n\n /**\n * Get timer info for a deposit — remaining time, expiry status, and claimability.\n * Useful for building countdown UIs.\n */\n async getDepositTimer(depositId: number): Promise<DepositTimer> {\n const d = await this.getDeposit(depositId);\n const nowSeconds = Math.floor(Date.now() / 1000);\n const remaining = timeUntilRefund(d.depositedAt, d.timeout, nowSeconds);\n const expired = remaining === 0;\n const canClaim = expired && d.status === DepositStatus.Pending\n ? await this.canClaimRefund(depositId)\n : false;\n\n return {\n depositId: d.id,\n expired,\n remainingSeconds: remaining,\n deadline: getDepositDeadline(d.depositedAt, d.timeout),\n formattedRemaining: formatTimeout(remaining),\n canClaim,\n };\n }\n\n // ===== PRIVATE HELPERS =====\n\n /**\n * Query contract events in chunked ranges to stay within public RPC limits.\n */\n private async _queryFilterChunked(\n contract: ethers.BaseContract,\n filter: ethers.ContractEventName,\n fromBlock: number,\n toBlock: number,\n chunkSize = 10_000,\n ): Promise<ethers.EventLog[]> {\n const results: ethers.EventLog[] = [];\n for (let start = fromBlock; start <= toBlock; start += chunkSize) {\n const end = Math.min(start + chunkSize - 1, toBlock);\n const chunk = await this._wrapRpcError(\n () => contract.queryFilter(filter, start, end),\n 'queryFilterChunked',\n );\n results.push(...(chunk as ethers.EventLog[]));\n }\n return results;\n }\n\n // ===== ESCROW INBOX (deposit → message bridge) =====\n\n /**\n * Reverse lookup: find the transaction hash that created a deposit.\n * Queries DepositRecorded events filtered by depositId (first indexed param).\n */\n async getDepositTxHash(depositId: number): Promise<string | null> {\n const escrow = this.requireEscrow();\n const chain = CHAINS[this.chainName];\n const currentBlock = await this.provider.getBlockNumber();\n const startBlock = currentBlock - chain.defaultLookback;\n\n const filter = escrow.filters.DepositRecorded(depositId);\n const events = await this._queryFilterChunked(escrow, filter, startBlock, currentBlock);\n\n if (events.length === 0) return null;\n return (events[0] as ethers.EventLog).transactionHash;\n }\n\n /**\n * Full reverse lookup: deposit → tx hash → tx receipt → parse MessageSent → decrypt.\n * Returns the tx hash and decoded message, or null if the deposit event isn't found.\n */\n async getDepositMessage(depositId: number): Promise<{ txHash: string; message: Message } | null> {\n const txHash = await this.getDepositTxHash(depositId);\n if (!txHash) return null;\n\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (!receipt) return null;\n\n const msg = await this._parseMessageFromReceipt(receipt);\n if (!msg) return null;\n\n return { txHash, message: msg };\n }\n\n /**\n * Get the \"inbox\" — all pending deposits for a topic, enriched with their linked messages.\n * Sorted newest-first by depositedAt.\n */\n async getEscrowInbox(topicId: number): Promise<EnrichedDeposit[]> {\n const escrow = this.requireEscrow();\n const chain = CHAINS[this.chainName];\n\n // 1. Get pending deposit IDs\n const depositIds = await this.getPendingDeposits(topicId);\n if (depositIds.length === 0) return [];\n\n // 2. Fetch deposit structs\n const deposits = await Promise.all(\n depositIds.map(id => this.getDeposit(Number(id)))\n );\n\n // 3. Single event query to build depositId → txHash map\n const currentBlock = await this.provider.getBlockNumber();\n const startBlock = currentBlock - chain.defaultLookback;\n const topicFilter = escrow.filters.DepositRecorded(null, topicId);\n const events = await this._queryFilterChunked(escrow, topicFilter, startBlock, currentBlock);\n const txHashMap = new Map<string, { txHash: string; blockNumber: number }>();\n for (const evt of events as ethers.EventLog[]) {\n const id = evt.args.depositId.toString();\n txHashMap.set(id, { txHash: evt.transactionHash, blockNumber: evt.blockNumber });\n }\n\n // 4. Check response status for all deposits\n const responseStatuses = await Promise.all(\n depositIds.map(id => this.hasResponse(Number(id)).catch(() => false))\n );\n\n // 5. Fetch receipts and parse messages\n const nowSeconds = Math.floor(Date.now() / 1000);\n const enriched: EnrichedDeposit[] = [];\n\n for (let i = 0; i < deposits.length; i++) {\n const deposit = deposits[i];\n const idStr = deposit.id.toString();\n const eventInfo = txHashMap.get(idStr);\n const txHash = eventInfo?.txHash ?? '';\n const blockNumber = eventInfo?.blockNumber ?? 0;\n\n // Parse message from receipt\n let messageText: string | null = null;\n if (txHash) {\n try {\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (receipt) {\n const msg = await this._parseMessageFromReceipt(receipt);\n messageText = msg?.text ?? null;\n }\n } catch {\n // Non-fatal: message text stays null\n }\n }\n\n // Timer info\n const remaining = timeUntilRefund(deposit.depositedAt, deposit.timeout, nowSeconds);\n const expired = remaining === 0;\n\n // Format amount\n let formattedAmount: string | null = null;\n try {\n formattedAmount = await this.formatTokenAmount(deposit.token, deposit.amount);\n } catch {\n // Token contract might not exist\n }\n\n enriched.push({\n ...deposit,\n txHash,\n blockNumber,\n messageText,\n hasResponse: responseStatuses[i],\n remainingSeconds: remaining,\n formattedRemaining: formatTimeout(remaining),\n expired,\n formattedAmount,\n });\n }\n\n // Sort newest first\n enriched.sort((a, b) => Number(b.depositedAt - a.depositedAt));\n return enriched;\n }\n\n /**\n * Parse a MessageSent event from a transaction receipt and decrypt it.\n * Returns null if no MessageSent event is found.\n */\n private async _parseMessageFromReceipt(receipt: ethers.TransactionReceipt): Promise<Message | null> {\n const iface = this.registry.interface;\n for (const log of receipt.logs) {\n try {\n const parsed = iface.parseLog(log);\n if (parsed?.name === 'MessageSent') {\n const topicId = Number(parsed.args.topicId);\n const sender = parsed.args.sender as string;\n const payloadBytes = parsed.args.payload as string;\n const timestamp = Number(parsed.args.timestamp);\n\n let text = '[unable to decrypt]';\n try {\n const key = await this.getEncryptionKey(topicId);\n const payloadStr = ethers.toUtf8String(payloadBytes);\n const result = decryptMessage(payloadStr, key);\n if (result) text = result.text;\n } catch {\n // Decryption failed — private topic without key loaded\n }\n\n return {\n topicId,\n sender,\n text,\n replyTo: null,\n mentions: null,\n timestamp,\n txHash: receipt.hash,\n blockNumber: receipt.blockNumber,\n };\n }\n } catch { /* skip non-matching logs */ }\n }\n return null;\n }\n\n // ===== ECDH (Private Topics) =====\n\n /**\n * Derive ECDH keypair from wallet signature (deterministic).\n * Requires a signer capable of signing messages.\n */\n async deriveECDHFromWallet(appId: number = 1): Promise<{ publicKey: Uint8Array }> {\n this.requireSigner();\n\n const signer = this._signer!;\n const { privateKey, publicKey } = await deriveKeypairFromSignature(\n this.requireAddress(),\n (msg) => signer.signMessage(msg),\n appId\n );\n\n this.ecdhPrivateKey = privateKey;\n this.ecdhPublicKey = publicKey;\n return { publicKey };\n }\n\n /**\n * Load ECDH keypair from a hex private key (e.g. from credentials file).\n */\n loadECDHKeypair(privateKeyHex: string): void {\n const { privateKey, publicKey } = keypairFromPrivateKey(privateKeyHex);\n this.ecdhPrivateKey = privateKey;\n this.ecdhPublicKey = publicKey;\n }\n\n /**\n * Register ECDH public key on-chain.\n */\n async registerPublicKey(): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPublicKey) throw new Error('ECDH key not derived yet');\n\n const hasKey = await this.keyManager.hasPublicKey(this.requireAddress());\n if (hasKey) {\n throw new Error('Public key already registered on-chain');\n }\n\n return this.keyManager.registerPublicKey(this.ecdhPublicKey);\n }\n\n /**\n * Fetch and decrypt the topic symmetric key from an on-chain ECDH grant.\n */\n async fetchAndDecryptTopicKey(topicId: number): Promise<Uint8Array> {\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const grant = await this.keyManager.getMyKey(topicId);\n const encryptedKey = ethers.getBytes(grant.encryptedKey);\n const granterPubKey = ethers.getBytes(grant.granterPublicKey);\n\n // No grant exists yet (empty bytes) — cannot decrypt\n if (encryptedKey.length === 0 || granterPubKey.length === 0) {\n throw new Error(`No key grant found for topic ${topicId}. The topic key needs to be initialized first.`);\n }\n\n const topicKey = decryptTopicKey(encryptedKey, this.ecdhPrivateKey, granterPubKey);\n this.topicKeys.set(topicId, topicKey);\n return topicKey;\n }\n\n /**\n * Initialize a private topic's symmetric key by generating a random key and self-granting.\n * This should be called once by the topic owner after creating a PRIVATE topic.\n * Returns the generated topic key.\n */\n async initializeTopicKey(topicId: number): Promise<Uint8Array> {\n this.requireSigner();\n if (!this.ecdhPrivateKey || !this.ecdhPublicKey) {\n throw new Error('ECDH key not derived yet');\n }\n\n // Generate random 32-byte topic symmetric key\n const topicKey = randomBytes(32);\n\n // Encrypt for ourselves (self-grant)\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, this.ecdhPublicKey);\n\n // Store on-chain as a self-grant\n const tx = await this.keyManager.grantKeyAccess(topicId, this.requireAddress(), encrypted);\n await tx.wait();\n\n // Cache locally\n this.topicKeys.set(topicId, topicKey);\n return topicKey;\n }\n\n /**\n * Get the topic key, initializing it if the caller is the topic owner and no grant exists.\n * Tries fetchAndDecryptTopicKey first; if no grant exists and caller is topic owner,\n * auto-initializes with initializeTopicKey.\n */\n async getOrInitializeTopicKey(topicId: number): Promise<Uint8Array> {\n try {\n return await this.fetchAndDecryptTopicKey(topicId);\n } catch (err) {\n const isNoGrant = err instanceof Error && err.message.includes('No key grant found');\n if (!isNoGrant) throw err;\n\n // Check if we're the topic owner — only owners can initialize\n const topic = await this.getTopic(topicId);\n if (!this._signer || topic.owner.toLowerCase() !== this._address!.toLowerCase()) {\n throw new Error(\n `No key grant found for topic ${topicId}. Ask the topic owner to grant you access with: keys grant ${topicId} ${this._address ?? '<your-address>'}`\n );\n }\n\n // Auto-initialize as the topic owner\n return this.initializeTopicKey(topicId);\n }\n }\n\n /**\n * Grant a user access to a private topic's symmetric key.\n */\n async grantKeyAccess(\n topicId: number,\n userAddress: string,\n topicKey: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const hasKey = await this.keyManager.hasPublicKey(userAddress);\n if (!hasKey) {\n throw new Error(\n `User ${userAddress} has no ECDH public key registered. They must run 'keys register' first.`\n );\n }\n\n const userPubKeyBytes = ethers.getBytes(await this.keyManager.getPublicKey(userAddress));\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, userPubKeyBytes);\n return this.keyManager.grantKeyAccess(topicId, userAddress, encrypted);\n }\n\n /**\n * Store a pre-known topic key (e.g. loaded from credentials).\n */\n setTopicKey(topicId: number, key: Uint8Array): void {\n this.topicKeys.set(topicId, key);\n }\n\n /**\n * Check if an address has an ECDH public key registered on-chain.\n */\n async hasPublicKey(address: string): Promise<boolean> {\n return this.keyManager.hasPublicKey(address);\n }\n\n /**\n * Get an address's ECDH public key from chain.\n */\n async getPublicKey(address: string): Promise<Uint8Array> {\n const key = await this.keyManager.getPublicKey(address);\n return ethers.getBytes(key);\n }\n\n /**\n * Check if a user has key access for a topic.\n */\n async hasKeyAccess(topicId: number, address: string): Promise<boolean> {\n return this.keyManager.hasKeyAccess(topicId, address);\n }\n\n /**\n * Get members who have registered ECDH keys but haven't been granted access to a private topic.\n * Useful for topic owners to see who's waiting for a key grant.\n */\n async getPendingKeyGrants(topicId: number): Promise<{\n pending: Array<{ address: string; hasPublicKey: boolean }>;\n granted: string[];\n }> {\n const topic = await this.getTopic(topicId);\n const members = await this.getApplicationMembers(Number(topic.applicationId));\n\n // Filter out zero addresses and deduplicate\n const uniqueMembers = [...new Set(members)].filter(a => a !== ethers.ZeroAddress);\n\n const pending: Array<{ address: string; hasPublicKey: boolean }> = [];\n const granted: string[] = [];\n\n await Promise.all(\n uniqueMembers.map(async (addr) => {\n const [hasAccess, hasKey] = await Promise.all([\n this.hasKeyAccess(topicId, addr),\n this.hasPublicKey(addr),\n ]);\n\n if (hasAccess) {\n granted.push(addr);\n } else {\n pending.push({ address: addr, hasPublicKey: hasKey });\n }\n })\n );\n\n return { pending, granted };\n }\n\n /**\n * Get the key grant details for a user on a topic.\n */\n async getKeyGrant(topicId: number, address: string): Promise<{\n encryptedKey: Uint8Array;\n granterPublicKey: Uint8Array;\n granter: string;\n keyVersion: bigint;\n grantedAt: bigint;\n }> {\n const g = await this.keyManager.getKeyGrant(topicId, address);\n return {\n encryptedKey: ethers.getBytes(g.encryptedKey),\n granterPublicKey: ethers.getBytes(g.granterPublicKey),\n granter: g.granter,\n keyVersion: g.keyVersion,\n grantedAt: g.grantedAt,\n };\n }\n\n /**\n * Get the current key version for a topic.\n */\n async getKeyVersion(topicId: number): Promise<bigint> {\n return this.keyManager.keyVersions(topicId);\n }\n\n /**\n * Batch grant key access to multiple users at once (max 50).\n */\n async batchGrantKeyAccess(\n topicId: number,\n users: string[],\n topicKey: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const encryptedKeys: Uint8Array[] = [];\n for (const user of users) {\n const userPubKeyBytes = ethers.getBytes(await this.keyManager.getPublicKey(user));\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, userPubKeyBytes);\n encryptedKeys.push(encrypted);\n }\n\n return this.keyManager.batchGrantKeyAccess(topicId, users, encryptedKeys);\n }\n\n /**\n * Revoke a user's key access for a topic.\n */\n async revokeKeyAccess(topicId: number, address: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.keyManager.revokeKeyAccess(topicId, address);\n }\n\n /**\n * Rotate the key version for a topic. Existing grants become stale.\n */\n async rotateKey(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.keyManager.rotateKey(topicId);\n }\n\n // ===== SCHEMAS =====\n\n /**\n * Create a schema scoped to an application. Requires app admin role.\n */\n async createAppSchema(\n appId: number,\n name: string,\n description: string,\n body: string\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.createAppSchema(appId, name, description, body);\n }\n\n /**\n * Publish a new version of an existing schema.\n */\n async publishSchemaVersion(\n schemaId: number,\n body: string\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.publishSchemaVersion(schemaId, body);\n }\n\n /**\n * Deactivate a schema.\n */\n async deactivateSchema(schemaId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.deactivateSchema(schemaId);\n }\n\n /**\n * Get schema info including application scope.\n */\n async getSchema(schemaId: number): Promise<SchemaInfo> {\n const s = await this.schemaRegistry.getSchemaWithApp(schemaId);\n return {\n id: Number(s.id),\n name: s.name,\n description: s.description,\n creator: s.creator,\n createdAt: Number(s.createdAt),\n versionCount: Number(s.versionCount),\n active: s.active,\n applicationId: Number(s.applicationId),\n };\n }\n\n /**\n * Get all schemas scoped to an application.\n */\n async getApplicationSchemas(appId: number): Promise<SchemaInfo[]> {\n const ids: bigint[] = await this.schemaRegistry.getApplicationSchemas(appId);\n const schemas: SchemaInfo[] = [];\n for (const id of ids) {\n const s = await this.getSchema(Number(id));\n schemas.push(s);\n }\n return schemas;\n }\n\n /**\n * Get schema body for a specific version.\n */\n async getSchemaBody(schemaId: number, version: number): Promise<string> {\n return this.schemaRegistry.getSchemaBody(schemaId, version);\n }\n\n /**\n * Get the schema binding for a topic.\n */\n async getTopicSchema(topicId: number): Promise<TopicSchemaBinding> {\n const s = await this.schemaRegistry.getTopicSchema(topicId);\n return {\n schemaId: Number(s.schemaId),\n version: Number(s.version),\n body: s.body,\n };\n }\n\n /**\n * Bind a schema version to a topic. Requires topic admin.\n */\n async setTopicSchema(\n topicId: number,\n schemaId: number,\n version: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.setTopicSchema(topicId, schemaId, version);\n }\n\n /**\n * Remove schema binding from a topic.\n */\n async clearTopicSchema(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.clearTopicSchema(topicId);\n }\n\n // ===== AGENT IDENTITY (V5) =====\n\n /**\n * Register your ERC-8004 agent identity for an application (V5).\n * Verifies ownership via ownerOf on the identity registry.\n */\n async registerAgentIdentity(appId: number, tokenId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.registerAgentIdentity(appId, tokenId);\n }\n\n /**\n * Clear your agent identity registration for an application (V5).\n */\n async clearAgentIdentity(appId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.clearAgentIdentity(appId);\n }\n\n /**\n * Get the registered agent token ID for a user in an application (V5/V6).\n * Returns 0 if not registered. V6 validates ownership live via ownerOf.\n */\n async getAgentTokenId(appId: number, address: string): Promise<bigint> {\n return this.registry.getAgentTokenId(appId, address);\n }\n\n /**\n * Check if a user has a registered agent identity for an application (V5/V6).\n * V6 validates ownership live — returns false if the token was transferred.\n */\n async hasAgentIdentity(appId: number, address: string): Promise<boolean> {\n return this.registry.hasAgentIdentity(appId, address);\n }\n\n // ===== ERC-8004 IDENTITY REGISTRY =====\n\n private requireIdentityRegistry(): ethers.Contract {\n if (!this.identityRegistry) {\n throw new Error('ERC-8004 Identity Registry not available on this chain. Use Base.');\n }\n return this.identityRegistry;\n }\n\n /**\n * Register as an agent on the ERC-8004 Identity Registry.\n * Optionally provide a URI for the agent's metadata.\n */\n async registerAgent(agentURI?: string): Promise<{ agentId: bigint; tx: ethers.TransactionResponse }> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n\n const tx: ethers.TransactionResponse = agentURI\n ? await registry['register(string)'](agentURI)\n : await registry['register()']();\n\n const receipt = await tx.wait();\n let agentId = 0n;\n if (receipt) {\n for (const log of receipt.logs) {\n try {\n const parsed = registry.interface.parseLog(log);\n if (parsed?.name === 'Registered') {\n agentId = parsed.args.agentId;\n break;\n }\n } catch { /* skip non-matching logs */ }\n }\n }\n\n return { agentId, tx };\n }\n\n /**\n * Register as an agent with metadata entries.\n */\n async registerAgentWithMetadata(\n agentURI: string,\n metadata: Array<{ metadataKey: string; metadataValue: Uint8Array }>\n ): Promise<{ agentId: bigint; tx: ethers.TransactionResponse }> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n\n const tx: ethers.TransactionResponse = await registry['register(string,(string,bytes)[])'](agentURI, metadata);\n\n const receipt = await tx.wait();\n let agentId = 0n;\n if (receipt) {\n for (const log of receipt.logs) {\n try {\n const parsed = registry.interface.parseLog(log);\n if (parsed?.name === 'Registered') {\n agentId = parsed.args.agentId;\n break;\n }\n } catch { /* skip non-matching logs */ }\n }\n }\n\n return { agentId, tx };\n }\n\n /**\n * Check if an address has an ERC-8004 agent identity NFT.\n * Defaults to the connected wallet address.\n */\n async isRegisteredAgent(address?: string): Promise<boolean> {\n const registry = this.requireIdentityRegistry();\n const addr = address ?? this._address;\n if (!addr) throw new Error('Address required');\n\n const balance: bigint = await registry.balanceOf(addr);\n return balance > 0n;\n }\n\n /**\n * Get agent info by agent ID.\n */\n async getAgentInfo(agentId: number): Promise<{ owner: string; uri: string; wallet: string }> {\n const registry = this.requireIdentityRegistry();\n\n const [owner, uri, wallet] = await Promise.all([\n registry.ownerOf(agentId) as Promise<string>,\n registry.tokenURI(agentId) as Promise<string>,\n registry.getAgentWallet(agentId) as Promise<string>,\n ]);\n\n return { owner, uri, wallet };\n }\n\n /**\n * Set metadata for an agent.\n */\n async setAgentMetadata(\n agentId: number,\n key: string,\n value: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n return registry.setMetadata(agentId, key, value);\n }\n\n /**\n * Get metadata for an agent by key.\n */\n async getAgentMetadata(agentId: number, key: string): Promise<string> {\n const registry = this.requireIdentityRegistry();\n const data: string = await registry.getMetadata(agentId, key);\n return ethers.toUtf8String(data);\n }\n\n /**\n * Update the URI for an agent registration.\n */\n async setAgentURI(agentId: number, newURI: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n return registry.setAgentURI(agentId, newURI);\n }\n\n /**\n * Look up an agent by its wallet address using the V5/V6 on-chain registry mapping.\n * V6 validates ownership live — stale registrations (transferred tokens) return 0.\n * Returns registration status, token ID, owner, URI, wallet, and parsed metadata.\n */\n async getAgentByAddress(address: string, appId: number): Promise<\n | { registered: false }\n | { registered: true; agentId: number; owner: string; uri: string; wallet: string; metadata: Record<string, unknown> | null }\n > {\n const onChainTokenId: bigint = await this.registry.getAgentTokenId(appId, address);\n if (onChainTokenId === 0n) return { registered: false };\n\n const agentId = Number(onChainTokenId);\n const { owner, uri, wallet } = await this.getAgentInfo(agentId);\n let metadata: Record<string, unknown> | null = null;\n if (uri) {\n metadata = await this.parseTokenURI(uri);\n }\n return { registered: true, agentId, owner, uri, wallet, metadata };\n }\n\n /**\n * Parse a tokenURI into JSON metadata.\n * Handles data:application/json;base64, data:application/json, HTTP(S), and ipfs:// URIs.\n */\n private async parseTokenURI(uri: string): Promise<Record<string, unknown> | null> {\n try {\n if (uri.startsWith('data:application/json;base64,')) {\n const json = atob(uri.slice('data:application/json;base64,'.length));\n return JSON.parse(json);\n }\n if (uri.startsWith('data:application/json,')) {\n return JSON.parse(decodeURIComponent(uri.slice('data:application/json,'.length)));\n }\n let url = uri;\n if (url.startsWith('ipfs://')) {\n url = 'https://ipfs.io/ipfs/' + url.slice('ipfs://'.length);\n }\n const resp = await fetch(url);\n if (!resp.ok) return null;\n return await resp.json();\n } catch {\n return null;\n }\n }\n\n // ===== DATA EXPORT =====\n\n /**\n * Look up an application ID by its name.\n */\n async getApplicationByName(name: string): Promise<number> {\n const id = await this.registry.applicationNames(name);\n return Number(id);\n }\n\n /**\n * Get schema version details including body and publish timestamp.\n */\n async getSchemaVersion(schemaId: number, version: number): Promise<{ body: string; publishedAt: bigint }> {\n const [body, publishedAt] = await this.schemaRegistry.getSchemaVersion(schemaId, version);\n return { body, publishedAt };\n }\n\n /**\n * Export member data for a user in an application.\n */\n async exportMemberData(appId: number, user: string): Promise<string> {\n const data = await this.registry.exportMemberData(appId, user);\n return ethers.hexlify(data);\n }\n\n /**\n * Export all application data.\n */\n async exportApplicationData(appId: number): Promise<string> {\n const data = await this.registry.exportApplicationData(appId);\n return ethers.hexlify(data);\n }\n\n /**\n * Export user data from the key manager for specified topics.\n */\n async exportUserData(user: string, topicIds: number[]): Promise<string> {\n const data = await this.keyManager.exportUserData(user, topicIds);\n return ethers.hexlify(data);\n }\n\n // ===== INTERNAL =====\n\n /**\n * Get the encryption key for a topic, determining the type automatically.\n */\n private async getEncryptionKey(topicId: number): Promise<Uint8Array> {\n // Check for a stored private topic key first\n const storedKey = this.topicKeys.get(topicId);\n if (storedKey) return storedKey;\n\n // Fetch topic metadata to determine access level\n const topic = await this.getTopic(topicId);\n\n if (topic.accessLevel === AccessLevel.PRIVATE) {\n // Auto-fetch (or auto-initialize for owner) if ECDH keys are loaded\n if (this.ecdhPrivateKey) {\n return this.getOrInitializeTopicKey(topicId);\n }\n throw new Error(\n `Topic ${topicId} is PRIVATE. Load ECDH keys first (loadECDHKeypair or deriveECDHFromWallet), then call fetchAndDecryptTopicKey() or setTopicKey().`\n );\n }\n\n // Public or public_limited: derive deterministic key\n return derivePublicTopicKey(topicId);\n }\n}\n","import type { ChainConfig, ChainName } from './types.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n baseSepolia: {\n chainId: 84532,\n name: 'Base Sepolia',\n shortName: 'Sepolia',\n rpc: 'https://sepolia.base.org',\n explorer: 'https://sepolia.basescan.org',\n registry: '0xf39b193aedC1Ec9FD6C5ccc24fBAe58ba9f52413',\n keyManager: '0x5562B553a876CBdc8AA4B3fb0687f22760F4759e',\n schemaRegistry: '0xB7eB50e9058198b99b5b2589E6D70b2d99d5440a',\n identityRegistry: '0x8004AA63c570c570eBF15376c0dB199918BFe9Fb',\n escrow: '0x74e376C53f4afd5Cd32a77dDc627f477FcFC2333',\n defaultLookback: 200_000,\n },\n base: {\n chainId: 8453,\n name: 'Base',\n shortName: 'Base',\n rpc: 'https://mainnet.base.org',\n explorer: 'https://basescan.org',\n registry: '0x5fF6BF04F1B5A78ae884D977a3C80A0D8E2072bF',\n keyManager: '0xdc302ff43a34F6aEa19426D60C9D150e0661E4f4',\n schemaRegistry: '0x5c11d2eA4470eD9025D810A21a885FE16dC987Bd',\n identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',\n escrow: '0x04eC9a25C942192834F447eC9192831B56Ae2D7D',\n defaultLookback: 200_000,\n },\n avalanche: {\n chainId: 43114,\n name: 'Avalanche C-Chain',\n shortName: 'Avalanche',\n rpc: 'https://api.avax.network/ext/bc/C/rpc',\n explorer: 'https://snowtrace.io',\n registry: '0x3Ca2FF0bD1b3633513299EB5d3e2d63e058b0713',\n keyManager: '0x5a5ea9D408FBA984fFf6e243Dcc71ff6E00C73E4',\n schemaRegistry: '0x23D96e610E8E3DA5341a75B77F1BFF7EA9c3A62B',\n identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',\n escrow: '0x4068245c35a498Da4336aD1Ab0Fb71ef534bfd03',\n defaultLookback: 500_000,\n },\n};\n\nexport const CHAIN_IDS: Record<number, ChainName> = {\n 84532: 'baseSepolia',\n 8453: 'base',\n 43114: 'avalanche',\n};\n\nexport function getChain(nameOrId: ChainName | number): ChainConfig {\n if (typeof nameOrId === 'number') {\n const name = CHAIN_IDS[nameOrId];\n if (!name) throw new Error(`Unsupported chain ID: ${nameOrId}`);\n return CHAINS[name];\n }\n const chain = CHAINS[nameOrId];\n if (!chain) throw new Error(`Unsupported chain: ${nameOrId}`);\n return chain;\n}\n","export const REGISTRY_ABI = [\n // ===== READ FUNCTIONS =====\n\n // Applications\n 'function applications(uint256) view returns (uint256 id, string name, string description, string frontendUrl, address owner, uint64 createdAt, uint32 memberCount, uint32 topicCount, bool active, bool allowPublicTopicCreation)',\n 'function getApplication(uint256 appId) view returns (tuple(uint256 id, string name, string description, string frontendUrl, address owner, uint64 createdAt, uint32 memberCount, uint32 topicCount, bool active, bool allowPublicTopicCreation, address topicCreationFeeToken, uint256 topicCreationFeeAmount))',\n 'function applicationCount() view returns (uint256)',\n 'function applicationNames(string) view returns (uint256)',\n\n // Topics\n 'function topics(uint256) view returns (uint256 id, uint256 applicationId, string name, string description, address owner, address creator, uint64 createdAt, uint64 lastMessageAt, uint256 messageCount, uint8 accessLevel, bool active)',\n 'function getTopic(uint256 topicId) view returns (tuple(uint256 id, uint256 applicationId, string name, string description, address owner, address creator, uint64 createdAt, uint64 lastMessageAt, uint256 messageCount, uint8 accessLevel, bool active))',\n 'function topicCount() view returns (uint256)',\n 'function getApplicationTopics(uint256 appId) view returns (uint256[])',\n\n // Members\n 'function members(uint256 appId, address user) view returns (address account, string nickname, uint8 roles, uint64 joinedAt)',\n 'function getMember(uint256 appId, address account) view returns (tuple(address account, string nickname, uint8 roles, uint64 joinedAt))',\n 'function isMember(uint256 appId, address account) view returns (bool)',\n 'function getApplicationMembers(uint256 appId) view returns (address[])',\n\n // Permissions\n 'function canReadTopic(uint256 topicId, address user) view returns (bool)',\n 'function canWriteToTopic(uint256 topicId, address user) view returns (bool)',\n 'function getTopicPermission(uint256 topicId, address user) view returns (uint8)',\n 'function topicPermissions(uint256, address) view returns (uint8)',\n\n // Nicknames\n 'function getNickname(uint256 appId, address user) view returns (string)',\n 'function hasNickname(uint256 appId, address user) view returns (bool)',\n 'function canChangeNickname(uint256 appId, address user) view returns (bool canChange, uint256 timeRemaining)',\n 'function appNicknameCooldown(uint256 appId) view returns (uint256)',\n\n // Fees\n 'function getTopicMessageFee(uint256 topicId) view returns (address token, uint256 amount)',\n 'function PLATFORM_FEE_BPS() view returns (uint256)',\n 'function PLATFORM_FEE_BPS_V7() view returns (uint256)',\n 'function APP_OWNER_FEE_BPS() view returns (uint256)',\n 'function BPS_DENOMINATOR() view returns (uint256)',\n\n // ===== WRITE FUNCTIONS =====\n\n // Applications\n 'function createApplication(string name, string description, string frontendUrl, bool allowPublicTopicCreation) returns (uint256)',\n 'function updateApplicationFrontendUrl(uint256 appId, string frontendUrl)',\n\n // Topics\n 'function createTopic(uint256 appId, string name, string description, uint8 accessLevel) returns (uint256)',\n 'function setTopicPermission(uint256 topicId, address user, uint8 permission)',\n\n // Members\n 'function addMember(uint256 appId, address member, string nickname, uint8 roles)',\n 'function removeMember(uint256 appId, address member)',\n 'function updateMemberRoles(uint256 appId, address member, uint8 roles)',\n 'function updateMemberNickname(uint256 appId, string nickname)',\n\n // Nicknames (V3)\n 'function setNickname(uint256 appId, string nickname)',\n 'function clearNickname(uint256 appId)',\n 'function setNicknameCooldown(uint256 appId, uint256 cooldownSeconds)',\n\n // Messaging\n 'function sendMessage(uint256 topicId, bytes payload)',\n // V10 — deposit-bound response\n 'function respondToDeposits(uint256 topicId, bytes payload, uint256[] depositIds)',\n\n // Fees\n 'function setTopicCreationFee(uint256 appId, address feeTokenAddr, uint256 feeAmount)',\n 'function setTopicMessageFee(uint256 topicId, address feeTokenAddr, uint256 feeAmount)',\n\n // ===== EVENTS =====\n 'event ApplicationCreated(uint256 indexed applicationId, string name, address indexed owner)',\n 'event TopicCreated(uint256 indexed topicId, uint256 indexed applicationId, string name, address indexed creator, uint8 accessLevel)',\n 'event MemberAdded(uint256 indexed applicationId, address indexed member, string nickname, uint8 roles)',\n 'event MemberRemoved(uint256 indexed applicationId, address indexed member)',\n 'event MemberRolesUpdated(uint256 indexed applicationId, address indexed member, uint8 roles)',\n 'event NicknameUpdated(uint256 indexed applicationId, address indexed member, string nickname)',\n 'event UserNicknameSet(uint256 indexed applicationId, address indexed user, string nickname)',\n 'event TopicPermissionSet(uint256 indexed topicId, address indexed user, uint8 permission)',\n 'event MessageSent(uint256 indexed topicId, address indexed sender, bytes payload, uint256 timestamp)',\n 'event TopicMessageFeeUpdated(uint256 indexed topicId, address token, uint256 amount)',\n 'event FeeCollected(address indexed token, uint256 totalAmount, address indexed recipient, uint256 recipientAmount, address indexed appOwner, uint256 appOwnerAmount, uint256 platformAmount)',\n\n // Agent identity (V5)\n 'function registerAgentIdentity(uint256 appId, uint256 tokenId)',\n 'function clearAgentIdentity(uint256 appId)',\n 'function getAgentTokenId(uint256 appId, address user) view returns (uint256)',\n 'function hasAgentIdentity(uint256 appId, address user) view returns (bool)',\n 'event AgentIdentityRegistered(uint256 indexed applicationId, address indexed user, uint256 tokenId)',\n 'event AgentIdentityCleared(uint256 indexed applicationId, address indexed user)',\n\n // Data export\n 'function exportMemberData(uint256 appId, address user) view returns (bytes)',\n 'function exportApplicationData(uint256 appId) view returns (bytes)',\n] as const;\n\nexport const SCHEMA_REGISTRY_ABI = [\n // ===== READ FUNCTIONS =====\n\n // Schema queries\n 'function schemaCount() view returns (uint256)',\n 'function getSchema(uint256 schemaId) view returns (uint256 id, string name, string description, address creator, uint64 createdAt, uint256 versionCount, bool active)',\n 'function getSchemaWithApp(uint256 schemaId) view returns (uint256 id, string name, string description, address creator, uint64 createdAt, uint256 versionCount, bool active, uint256 applicationId)',\n 'function getSchemaBody(uint256 schemaId, uint256 version) view returns (string)',\n 'function getSchemaVersion(uint256 schemaId, uint256 version) view returns (string body, uint64 publishedAt)',\n 'function schemaApplicationId(uint256 schemaId) view returns (uint256)',\n\n // App-scoped queries (V2)\n 'function getApplicationSchemas(uint256 applicationId) view returns (uint256[])',\n 'function getApplicationSchemaCount(uint256 applicationId) view returns (uint256)',\n\n // Topic binding\n 'function getTopicSchema(uint256 topicId) view returns (uint256 schemaId, uint256 version, string body)',\n\n // Version\n 'function contractVersion() view returns (string)',\n\n // ===== WRITE FUNCTIONS =====\n\n // Schema creation (V2 app-scoped)\n 'function createAppSchema(uint256 applicationId, string name, string description, string body) returns (uint256)',\n 'function publishSchemaVersion(uint256 schemaId, string body) returns (uint256)',\n 'function deactivateSchema(uint256 schemaId)',\n\n // Topic binding\n 'function setTopicSchema(uint256 topicId, uint256 schemaId, uint256 version)',\n 'function clearTopicSchema(uint256 topicId)',\n\n // ===== EVENTS =====\n 'event AppSchemaCreated(uint256 indexed schemaId, uint256 indexed applicationId, string name, address indexed creator)',\n 'event SchemaVersionPublished(uint256 indexed schemaId, uint256 version)',\n 'event SchemaDeactivated(uint256 indexed schemaId)',\n 'event TopicSchemaSet(uint256 indexed topicId, uint256 indexed schemaId, uint256 version)',\n 'event TopicSchemaCleared(uint256 indexed topicId)',\n 'event SchemaAssignedToApp(uint256 indexed schemaId, uint256 indexed applicationId)',\n] as const;\n\nexport const IDENTITY_REGISTRY_ABI = [\n 'function register() returns (uint256)',\n 'function register(string agentURI) returns (uint256)',\n 'function register(string agentURI, tuple(string metadataKey, bytes metadataValue)[] metadata) returns (uint256)',\n 'function getMetadata(uint256 agentId, string metadataKey) view returns (bytes)',\n 'function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)',\n 'function setAgentURI(uint256 agentId, string newURI)',\n 'function getAgentWallet(uint256 agentId) view returns (address)',\n 'function setAgentWallet(uint256 agentId, address newWallet, uint256 deadline, bytes signature)',\n 'function unsetAgentWallet(uint256 agentId)',\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)',\n 'function tokenURI(uint256 tokenId) view returns (string)',\n 'function isAuthorizedOrOwner(address spender, uint256 agentId) view returns (bool)',\n 'function getVersion() pure returns (string)',\n 'event Registered(uint256 indexed agentId, string agentURI, address indexed owner)',\n] as const;\n\nexport const ESCROW_ABI = [\n // ===== READ FUNCTIONS =====\n 'function getVersion() pure returns (string)',\n 'function registry() view returns (address)',\n 'function treasury() view returns (address)',\n 'function depositCount() view returns (uint256)',\n 'function isEscrowEnabled(uint256 topicId) view returns (bool)',\n 'function topicEscrowEnabled(uint256 topicId) view returns (bool)',\n 'function topicEscrowTimeout(uint256 topicId) view returns (uint64)',\n 'function getDeposit(uint256 depositId) view returns (uint256 id, uint256 topicId, address sender, address recipient, address token, uint256 amount, address appOwner, uint64 depositedAt, uint64 timeout, uint8 status)',\n 'function getDepositStatus(uint256 depositId) view returns (uint8)',\n 'function getPendingDeposits(uint256 topicId) view returns (uint256[])',\n 'function canClaimRefund(uint256 depositId) view returns (bool)',\n\n // V3\n 'function depositMessageRef(uint256 depositId) view returns (uint256)',\n 'function getDepositMessageRef(uint256 depositId) view returns (uint256)',\n 'function depositResponseRecorded(uint256 depositId) view returns (bool)',\n 'function hasResponse(uint256 depositId) view returns (bool)',\n\n // ===== WRITE FUNCTIONS =====\n 'function enableEscrow(uint256 topicId, uint64 timeoutSeconds)',\n 'function disableEscrow(uint256 topicId)',\n 'function claimRefund(uint256 depositId)',\n 'function batchClaimRefunds(uint256[] depositIds)',\n // V3 — per-deposit release\n 'function releaseDeposit(uint256 depositId, uint256 messageRef)',\n 'function batchReleaseDeposits(uint256[] depositIds, uint256[] messageRefs)',\n\n // ===== EVENTS =====\n 'event EscrowEnabled(uint256 indexed topicId, uint64 timeout)',\n 'event EscrowDisabled(uint256 indexed topicId)',\n 'event DepositRecorded(uint256 indexed depositId, uint256 indexed topicId, address indexed sender, uint256 amount)',\n 'event DepositReleased(uint256 indexed depositId, uint256 indexed topicId, uint256 recipientAmount, uint256 appOwnerAmount, uint256 platformAmount)',\n 'event DepositRefunded(uint256 indexed depositId, uint256 indexed topicId, address indexed sender, uint256 amount)',\n // V3\n 'event DepositReleasedByOwner(uint256 indexed depositId, uint256 indexed topicId, address indexed releasedBy, uint256 messageRef)',\n 'event DepositResponseRecorded(uint256 indexed depositId, uint256 indexed topicId, address indexed respondedBy)',\n\n // V4 — on-chain accumulators + credibility\n 'function getRecipientStats(address wallet) view returns (tuple(uint64 depositsReceived, uint64 depositsReleased, uint64 depositsRefunded, uint64 depositsExpired))',\n 'function getResponseRate(address wallet) view returns (uint256)',\n 'function getCredibility(address wallet) view returns (uint256 responseRate, uint64 depositsReceived, uint64 depositsReleased, uint64 depositsRefunded, uint256 totalEarned, uint256 totalRefunded)',\n 'function amountEarned(address wallet) view returns (uint256)',\n 'function amountRefunded(address wallet) view returns (uint256)',\n 'event RecipientStatsUpdated(address indexed wallet, uint64 received, uint64 released, uint64 refunded)',\n] as const;\n\nexport const KEY_MANAGER_ABI = [\n // ===== READ FUNCTIONS =====\n 'function hasPublicKey(address user) view returns (bool)',\n 'function getPublicKey(address user) view returns (bytes)',\n 'function publicKeys(address) view returns (bytes)',\n 'function hasKeyAccess(uint256 topicId, address user) view returns (bool)',\n 'function getMyKey(uint256 topicId) view returns (bytes encryptedKey, bytes granterPublicKey, address granter, uint256 keyVersion, uint256 currentVersion)',\n 'function getKeyGrant(uint256 topicId, address user) view returns (tuple(bytes encryptedKey, bytes granterPublicKey, address granter, uint256 keyVersion, uint64 grantedAt))',\n 'function keyVersions(uint256 topicId) view returns (uint256)',\n\n // ===== WRITE FUNCTIONS =====\n 'function registerPublicKey(bytes publicKey)',\n 'function grantKeyAccess(uint256 topicId, address user, bytes encryptedKey)',\n 'function batchGrantKeyAccess(uint256 topicId, address[] users, bytes[] encryptedKeys)',\n 'function revokeKeyAccess(uint256 topicId, address user)',\n 'function rotateKey(uint256 topicId)',\n\n // Data export\n 'function exportUserData(address user, uint256[] topicIds) view returns (bytes)',\n\n // ===== EVENTS =====\n 'event PublicKeyRegistered(address indexed user, bytes publicKey)',\n 'event PublicKeyUpdated(address indexed user, bytes publicKey)',\n 'event KeyAccessGranted(uint256 indexed topicId, address indexed user, address indexed granter, uint256 version)',\n 'event KeyAccessRevoked(uint256 indexed topicId, address indexed user)',\n 'event KeyRotated(uint256 indexed topicId, uint256 newVersion)',\n] as const;\n","import { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/hashes/utils';\nimport {\n PUBLIC_KEY_MATERIAL_PREFIX,\n SALT_PREFIX,\n PBKDF2_ITERATIONS,\n} from '../constants.js';\nimport type { EncryptedPayload, MessageContent } from '../types.js';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Derive AES-256 key for a public/public_limited topic.\n * Uses PBKDF2 with SHA-256, matching the web frontend exactly.\n */\nexport function derivePublicTopicKey(topicId: number | bigint): Uint8Array {\n const keyMaterial = PUBLIC_KEY_MATERIAL_PREFIX + topicId;\n const salt = encoder.encode(SALT_PREFIX + topicId);\n return pbkdf2(sha256, keyMaterial, salt, { c: PBKDF2_ITERATIONS, dkLen: 32 });\n}\n\n/**\n * Derive AES-256 key from arbitrary passphrase (for private topics with manual passphrase).\n */\nexport function deriveKeyFromPassphrase(passphrase: string, topicId: number | bigint): Uint8Array {\n const salt = encoder.encode(SALT_PREFIX + topicId);\n return pbkdf2(sha256, passphrase, salt, { c: PBKDF2_ITERATIONS, dkLen: 32 });\n}\n\n/**\n * Encrypt a message payload with AES-256-GCM.\n * Output format: `{ e: true, v: 2, iv: base64, ct: base64 }`\n * The ciphertext includes the GCM auth tag (last 16 bytes).\n */\nexport function encrypt(plaintext: string, key: Uint8Array): string {\n const iv = randomBytes(12);\n const aes = gcm(key, iv);\n const ciphertext = aes.encrypt(encoder.encode(plaintext));\n\n const payload: EncryptedPayload = {\n e: true,\n v: 2,\n iv: toBase64(iv),\n ct: toBase64(ciphertext),\n };\n return JSON.stringify(payload);\n}\n\n/**\n * Decrypt a message payload. Handles both v1 and v2 formats.\n * Returns the decrypted string or null on failure.\n */\nexport function decrypt(jsonStr: string, key: Uint8Array): string | null {\n try {\n const data = JSON.parse(jsonStr) as EncryptedPayload;\n if (!data.e) {\n // Not encrypted — return raw for caller to parse\n return jsonStr;\n }\n\n const iv = fromBase64(data.iv);\n const ct = fromBase64(data.ct);\n\n const aes = gcm(key, iv);\n const decrypted = aes.decrypt(ct);\n return decoder.decode(decrypted);\n } catch {\n return null;\n }\n}\n\n/**\n * Encrypt a structured message (text + optional replyTo/mentions).\n */\nexport function encryptMessage(\n text: string,\n key: Uint8Array,\n options?: { replyTo?: string; replyText?: string; replyAuthor?: string; mentions?: string[] }\n): string {\n const content: MessageContent = { text };\n if (options?.replyTo) content.replyTo = options.replyTo;\n if (options?.replyText) content.replyText = options.replyText;\n if (options?.replyAuthor) content.replyAuthor = options.replyAuthor;\n if (options?.mentions) content.mentions = options.mentions;\n return encrypt(JSON.stringify(content), key);\n}\n\n/**\n * Decrypt and parse a message payload into structured content.\n */\nexport function decryptMessage(\n jsonStr: string,\n key: Uint8Array\n): { text: string; replyTo: string | null; replyText: string | null; replyAuthor: string | null; mentions: string[] | null } | null {\n const decrypted = decrypt(jsonStr, key);\n if (!decrypted) return null;\n\n try {\n const content = JSON.parse(decrypted);\n if (typeof content === 'object' && content.text) {\n return {\n text: content.text,\n replyTo: content.replyTo || null,\n replyText: content.replyText || null,\n replyAuthor: content.replyAuthor || null,\n mentions: content.mentions || null,\n };\n }\n // Plain text string was JSON-stringified\n return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };\n } catch {\n // Raw string, not JSON\n return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };\n }\n}\n\n// ===== Base64 helpers (isomorphic) =====\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n return btoa(String.fromCharCode(...bytes));\n}\n\nfunction fromBase64(str: string): Uint8Array {\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(str, 'base64'));\n }\n return Uint8Array.from(atob(str), (c) => c.charCodeAt(0));\n}\n","// ===== Enums =====\n\nexport enum AccessLevel {\n PUBLIC = 0,\n PUBLIC_LIMITED = 1,\n PRIVATE = 2,\n}\n\nexport enum Permission {\n NONE = 0,\n READ = 1,\n WRITE = 2,\n READ_WRITE = 3,\n ADMIN = 4,\n}\n\nexport enum Role {\n MEMBER = 1,\n SUPPORT_MANAGER = 2,\n TOPIC_MANAGER = 4,\n ADMIN = 8,\n OWNER_DELEGATE = 16,\n}\n\n// ===== Chain types =====\n\nexport interface ChainConfig {\n chainId: number;\n name: string;\n shortName: string;\n rpc: string;\n explorer: string;\n registry: string;\n keyManager: string;\n schemaRegistry: string;\n identityRegistry?: string;\n escrow?: string;\n defaultLookback: number;\n}\n\nexport type ChainName = 'base' | 'avalanche' | 'baseSepolia';\n\n// ===== Contract return types =====\n\nexport interface Application {\n id: bigint;\n name: string;\n description: string;\n frontendUrl: string;\n owner: string;\n createdAt: bigint;\n memberCount: number;\n topicCount: number;\n active: boolean;\n allowPublicTopicCreation: boolean;\n topicCreationFeeToken?: string;\n topicCreationFeeAmount?: bigint;\n}\n\nexport interface Topic {\n id: bigint;\n applicationId: bigint;\n name: string;\n description: string;\n owner: string;\n creator: string;\n createdAt: bigint;\n lastMessageAt: bigint;\n messageCount: bigint;\n accessLevel: number;\n active: boolean;\n}\n\nexport interface Member {\n account: string;\n nickname: string;\n roles: number;\n joinedAt: bigint;\n}\n\nexport interface KeyGrant {\n encryptedKey: Uint8Array;\n granterPublicKey: Uint8Array;\n granter: string;\n keyVersion: bigint;\n grantedAt?: bigint;\n currentVersion?: bigint;\n}\n\n// ===== Message types =====\n\nexport interface MessageContent {\n text: string;\n replyTo?: string;\n replyText?: string;\n replyAuthor?: string;\n mentions?: string[];\n}\n\nexport interface EncryptedPayload {\n e: boolean;\n v: number;\n iv: string;\n ct: string;\n}\n\nexport interface Message {\n topicId: number;\n sender: string;\n text: string;\n replyTo: string | null;\n mentions: string[] | null;\n timestamp: number;\n txHash: string;\n blockNumber: number;\n}\n\nexport interface TopicMessageFee {\n token: string;\n amount: bigint;\n}\n\nexport interface SchemaInfo {\n id: number;\n name: string;\n description: string;\n creator: string;\n createdAt: number;\n versionCount: number;\n active: boolean;\n applicationId: number;\n}\n\nexport interface TopicSchemaBinding {\n schemaId: number;\n version: number;\n body: string;\n}\n\nexport enum DepositStatus {\n Pending = 0,\n Released = 1,\n Refunded = 2,\n}\n\nexport interface EscrowDeposit {\n id: bigint;\n topicId: bigint;\n sender: string;\n recipient: string;\n token: string;\n amount: bigint;\n appOwner: string;\n depositedAt: bigint;\n timeout: bigint;\n status: DepositStatus;\n}\n\nexport interface EscrowConfig {\n enabled: boolean;\n timeout: bigint;\n}\n\nexport interface DepositTimer {\n depositId: bigint;\n expired: boolean;\n remainingSeconds: number;\n deadline: number;\n formattedRemaining: string;\n canClaim: boolean;\n}\n\nexport interface EnrichedDeposit extends EscrowDeposit {\n txHash: string;\n blockNumber: number;\n messageText: string | null;\n hasResponse: boolean;\n remainingSeconds: number;\n formattedRemaining: string;\n expired: boolean;\n formattedAmount: string | null;\n}\n\n// ===== Credibility (V4) =====\n\nexport interface RecipientStats {\n depositsReceived: bigint;\n depositsReleased: bigint;\n depositsRefunded: bigint;\n depositsExpired: bigint;\n}\n\nexport interface WalletCredibility {\n responseRate: number; // 0-100 (percentage, converted from basis points)\n depositsReceived: bigint;\n depositsReleased: bigint;\n depositsRefunded: bigint;\n totalEarned: bigint;\n totalRefunded: bigint;\n formattedEarned: string | null;\n formattedRefunded: string | null;\n}\n\n// ===== Client options =====\n\nexport interface ClawtennaOptions {\n chain?: ChainName;\n chainId?: number;\n rpcUrl?: string;\n privateKey?: string;\n registryAddress?: string;\n keyManagerAddress?: string;\n schemaRegistryAddress?: string;\n escrowAddress?: string;\n}\n\nexport interface ReadOptions {\n limit?: number;\n fromBlock?: number;\n}\n\nexport interface SendOptions {\n replyTo?: string;\n replyText?: string;\n replyAuthor?: string;\n mentions?: string[];\n skipRefundCheck?: boolean;\n}\n\n// ===== Credentials =====\n\nexport interface Credentials {\n version: 2;\n wallet: {\n address: string;\n privateKey: string;\n };\n chains: Record<string, CredentialChain>;\n}\n\nexport interface CredentialChain {\n name: string;\n ecdh: {\n privateKey: string;\n publicKey: string;\n registered: boolean;\n } | null;\n apps: Record<string, CredentialApp>;\n}\n\nexport interface CredentialApp {\n name: string;\n nickname: string;\n agentTokenId: number | null;\n topicKeys: Record<string, string>;\n}\n\n// Legacy v1 format for migration\nexport interface CredentialsV1 {\n wallet: {\n address: string;\n privateKey: string;\n };\n apps: Record<string, {\n name: string;\n nickname: string;\n ecdh: {\n privateKey: string;\n publicKey: string;\n registeredOnChain: boolean;\n topicKeys: Record<string, string>;\n } | null;\n }>;\n}\n","import { AccessLevel, Permission, Role } from './types.js';\n\n// Re-export enums as individual constants for convenience\nexport const ACCESS_PUBLIC = AccessLevel.PUBLIC;\nexport const ACCESS_PUBLIC_LIMITED = AccessLevel.PUBLIC_LIMITED;\nexport const ACCESS_PRIVATE = AccessLevel.PRIVATE;\n\nexport const PERMISSION_NONE = Permission.NONE;\nexport const PERMISSION_READ = Permission.READ;\nexport const PERMISSION_WRITE = Permission.WRITE;\nexport const PERMISSION_READ_WRITE = Permission.READ_WRITE;\nexport const PERMISSION_ADMIN = Permission.ADMIN;\n\nexport const ROLE_MEMBER = Role.MEMBER;\nexport const ROLE_SUPPORT_MANAGER = Role.SUPPORT_MANAGER;\nexport const ROLE_TOPIC_MANAGER = Role.TOPIC_MANAGER;\nexport const ROLE_ADMIN = Role.ADMIN;\nexport const ROLE_OWNER_DELEGATE = Role.OWNER_DELEGATE;\n\n// Encryption constants\nexport const PUBLIC_KEY_MATERIAL_PREFIX = 'antenna-public-topic-';\nexport const SALT_PREFIX = 'antenna-v2-salt-';\nexport const PBKDF2_ITERATIONS = 100_000;\nexport const ECDH_HKDF_SALT = 'antenna-ecdh-v1';\nexport const ECDH_HKDF_INFO = 'topic-key-encryption';\nexport const ECDH_DERIVATION_MESSAGE = (address: string, appId: number) =>\n `Clawntenna ECDH Key Derivation\\n\\nThis signature generates your encryption key.\\nIt never leaves your device.\\n\\nWallet: ${address}\\nApp: ${appId}\\nChain: Base (8453)`;\n","import { secp256k1 } from '@noble/curves/secp256k1';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { ECDH_HKDF_SALT, ECDH_HKDF_INFO, ECDH_DERIVATION_MESSAGE } from '../constants.js';\n\nconst encoder = new TextEncoder();\n\n/**\n * Derive an ECDH keypair deterministically from a wallet signature.\n * This produces the same keypair as the web frontend for the same wallet + app.\n */\nexport async function deriveKeypairFromSignature(\n walletAddress: string,\n signMessage: (message: string) => Promise<string>,\n appId: number = 1\n): Promise<{ privateKey: Uint8Array; publicKey: Uint8Array }> {\n const message = ECDH_DERIVATION_MESSAGE(walletAddress, appId);\n const signature = await signMessage(message);\n\n // Hash the signature string (as UTF-8 bytes) to get private key\n const sigBytes = encoder.encode(signature);\n const hashBuffer = sha256(sigBytes);\n const privateKey = new Uint8Array(hashBuffer);\n\n // Derive compressed public key\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n return { privateKey, publicKey };\n}\n\n/**\n * Derive ECDH keypair from a raw private key (e.g. from stored credentials).\n */\nexport function keypairFromPrivateKey(privateKeyHex: string): {\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n} {\n const cleaned = privateKeyHex.startsWith('0x') ? privateKeyHex.slice(2) : privateKeyHex;\n const privateKey = hexToBytes(cleaned);\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n return { privateKey, publicKey };\n}\n\n/**\n * Compute ECDH shared secret (x-coordinate of shared point).\n */\nexport function computeSharedSecret(\n ourPrivateKey: Uint8Array,\n theirPublicKey: Uint8Array\n): Uint8Array {\n const sharedPoint = secp256k1.getSharedSecret(ourPrivateKey, theirPublicKey);\n // Return x-coordinate only (skip the 0x04 prefix byte)\n return sharedPoint.slice(1, 33);\n}\n\n/**\n * Derive AES-256 key from an ECDH shared secret using HKDF.\n * Matches the web frontend: salt='antenna-ecdh-v1', info='topic-key-encryption'.\n */\nexport function deriveAESKeyFromSecret(\n sharedSecret: Uint8Array,\n info: string = ECDH_HKDF_INFO\n): Uint8Array {\n return hkdf(sha256, sharedSecret, encoder.encode(ECDH_HKDF_SALT), info, 32);\n}\n\n/**\n * Encrypt a topic symmetric key for a recipient using ECDH.\n * Returns IV (12 bytes) + ciphertext (includes GCM auth tag).\n */\nexport function encryptTopicKeyForUser(\n topicKey: Uint8Array,\n ourPrivateKey: Uint8Array,\n recipientPublicKey: Uint8Array\n): Uint8Array {\n const shared = computeSharedSecret(ourPrivateKey, recipientPublicKey);\n const aesKey = deriveAESKeyFromSecret(shared);\n const iv = randomBytes(12);\n const aes = gcm(aesKey, iv);\n const ciphertext = aes.encrypt(topicKey);\n\n // Combine: IV + ciphertext\n const result = new Uint8Array(iv.length + ciphertext.length);\n result.set(iv);\n result.set(ciphertext, iv.length);\n return result;\n}\n\n/**\n * Decrypt a topic symmetric key received via ECDH grant.\n * Input format: IV (12 bytes) + ciphertext (includes GCM auth tag).\n */\nexport function decryptTopicKey(\n encryptedKey: Uint8Array,\n ourPrivateKey: Uint8Array,\n granterPublicKey: Uint8Array\n): Uint8Array {\n const shared = computeSharedSecret(ourPrivateKey, granterPublicKey);\n const aesKey = deriveAESKeyFromSecret(shared);\n const iv = encryptedKey.slice(0, 12);\n const ciphertext = encryptedKey.slice(12);\n const aes = gcm(aesKey, iv);\n return aes.decrypt(ciphertext);\n}\n\n// ===== Hex helpers =====\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return '0x' + Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function hexToBytes(hex: string): Uint8Array {\n const cleaned = hex.startsWith('0x') ? hex.slice(2) : hex;\n return new Uint8Array(cleaned.match(/.{1,2}/g)!.map((b) => parseInt(b, 16)));\n}\n","/**\n * Pure escrow timer utilities — no ethers.js dependency.\n */\n\nexport const ESCROW_MIN_TIMEOUT = 60;\nexport const ESCROW_MAX_TIMEOUT = 604800;\n\nexport const ESCROW_TIMEOUT_OPTIONS = [\n { value: 300, label: '5 minutes' },\n { value: 3600, label: '1 hour' },\n { value: 21600, label: '6 hours' },\n { value: 86400, label: '1 day' },\n { value: 259200, label: '3 days' },\n { value: 604800, label: '7 days' },\n] as const;\n\nexport const DEPOSIT_STATUS_LABELS = ['Pending', 'Released', 'Refunded'] as const;\n\n/**\n * Format a timeout in seconds into a human-readable string.\n * Examples: 300 → \"5m\", 3600 → \"1h\", 86400 → \"1d\", 5400 → \"1h 30m\"\n */\nexport function formatTimeout(seconds: number): string {\n if (seconds <= 0) return '0s';\n\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const secs = seconds % 60;\n\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (secs > 0 && days === 0 && hours === 0) parts.push(`${secs}s`);\n\n return parts.join(' ') || '0s';\n}\n\n/**\n * Check whether a deposit has expired (eligible for refund).\n */\nexport function isDepositExpired(depositedAt: bigint, timeout: bigint, nowSeconds?: number): boolean {\n const now = BigInt(nowSeconds ?? Math.floor(Date.now() / 1000));\n return now >= depositedAt + timeout;\n}\n\n/**\n * Seconds remaining until a deposit becomes refundable. Returns 0 if already expired.\n */\nexport function timeUntilRefund(depositedAt: bigint, timeout: bigint, nowSeconds?: number): number {\n const now = BigInt(nowSeconds ?? Math.floor(Date.now() / 1000));\n const deadline = depositedAt + timeout;\n if (now >= deadline) return 0;\n return Number(deadline - now);\n}\n\n/**\n * Get the absolute deadline timestamp (seconds since epoch) when a deposit becomes refundable.\n */\nexport function getDepositDeadline(depositedAt: bigint, timeout: bigint): number {\n return Number(depositedAt + timeout);\n}\n\n/**\n * Validate that a timeout value is within allowed bounds.\n */\nexport function isValidTimeout(seconds: number): boolean {\n return Number.isInteger(seconds) && seconds >= ESCROW_MIN_TIMEOUT && seconds <= ESCROW_MAX_TIMEOUT;\n}\n","/**\n * Classify common RPC errors into human-readable hints.\n * Returns an enhanced message string, or null if the error is unrecognized.\n */\nexport function classifyRpcError(\n err: Error,\n ctx: { method: string; chainName: string }\n): string | null {\n const msg = err.message ?? '';\n\n if (msg.includes('BAD_DATA') || msg.includes('could not decode result data')) {\n return `${ctx.method} failed: contract may not be deployed on ${ctx.chainName}, or the RPC returned an empty response. Check that the correct chain and RPC URL are configured.`;\n }\n\n if (\n msg.includes('NETWORK_ERROR') ||\n msg.includes('ECONNREFUSED') ||\n msg.includes('fetch failed') ||\n msg.includes('getaddrinfo')\n ) {\n return `${ctx.method} failed: network error connecting to ${ctx.chainName} RPC. Check your RPC URL and network connectivity.`;\n }\n\n if (\n msg.includes('429') ||\n msg.includes('rate limit') ||\n msg.includes('too many requests') ||\n msg.includes('exceeded') ||\n msg.includes('throttl')\n ) {\n return `${ctx.method} failed: RPC rate limit hit on ${ctx.chainName}. The request was retried but the limit persists. Try again later or use a different RPC endpoint.`;\n }\n\n return null;\n}\n","export interface RetryOptions {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nexport const DEFAULT_RETRY: RetryOptions = {\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 10_000,\n};\n\nconst RETRYABLE_PATTERNS = [\n '429',\n 'rate limit',\n 'too many requests',\n 'timeout',\n 'econnreset',\n '502',\n '503',\n '504',\n 'server error',\n];\n\nexport function isRetryableError(err: Error): boolean {\n const msg = (err.message ?? '').toLowerCase();\n return RETRYABLE_PATTERNS.some((p) => msg.includes(p));\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: Partial<RetryOptions>,\n): Promise<T> {\n const opts = { ...DEFAULT_RETRY, ...options };\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n\n if (attempt === opts.maxRetries) break;\n if (!(err instanceof Error) || !isRetryableError(err)) break;\n\n const delay = Math.min(opts.baseDelayMs * 2 ** attempt, opts.maxDelayMs);\n const jitter = Math.random() * 0.25 * delay;\n await new Promise((r) => setTimeout(r, delay + jitter));\n }\n }\n\n throw lastError;\n}\n","import type { Message } from './types.js';\n\n/**\n * Convert a Message to a plain object safe for JSON.stringify().\n * All fields are already JSON-safe (number, string, string[], null),\n * so this is primarily a convenience function for consumers.\n */\nexport function serializeMessage(msg: Message): Record<string, unknown> {\n return {\n topicId: msg.topicId,\n sender: msg.sender,\n text: msg.text,\n replyTo: msg.replyTo,\n mentions: msg.mentions,\n timestamp: msg.timestamp,\n txHash: msg.txHash,\n blockNumber: msg.blockNumber,\n };\n}\n"],"mappings":"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","names":["AccessLevel","Permission","Role","DepositStatus","sha256","gcm","randomBytes","encoder","sha256","randomBytes","gcm","randomBytes","randomBytes"]}
1
+ {"version":3,"sources":["../src/client.ts","../src/chains.ts","../src/contracts.ts","../src/crypto/encrypt.ts","../src/types.ts","../src/constants.ts","../src/crypto/ecdh.ts","../src/escrow.ts","../src/rpc-errors.ts","../src/retry.ts","../src/serialize.ts"],"sourcesContent":["import { ethers } from 'ethers';\nimport { CHAINS } from './chains.js';\nimport { REGISTRY_ABI, KEY_MANAGER_ABI, SCHEMA_REGISTRY_ABI, IDENTITY_REGISTRY_ABI, ESCROW_ABI } from './contracts.js';\nimport {\n derivePublicTopicKey,\n deriveKeyFromPassphrase,\n encryptMessage,\n decryptMessage,\n} from './crypto/encrypt.js';\nimport {\n deriveKeypairFromSignature,\n keypairFromPrivateKey,\n computeSharedSecret,\n deriveAESKeyFromSecret,\n encryptTopicKeyForUser,\n decryptTopicKey,\n bytesToHex,\n hexToBytes,\n} from './crypto/ecdh.js';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { AccessLevel, DepositStatus, Permission, Role } from './types.js';\nimport type {\n ClawtennaOptions,\n ReadOptions,\n SendOptions,\n Message,\n Topic,\n Application,\n Member,\n TopicMessageFee,\n SchemaInfo,\n TopicSchemaBinding,\n ChainName,\n EscrowDeposit,\n EscrowConfig,\n DepositTimer,\n EnrichedDeposit,\n RecipientStats,\n WalletCredibility,\n} from './types.js';\nimport {\n formatTimeout,\n isDepositExpired,\n timeUntilRefund,\n getDepositDeadline,\n} from './escrow.js';\nimport { classifyRpcError } from './rpc-errors.js';\nimport { withRetry } from './retry.js';\n\nexport class Clawntenna {\n readonly provider: ethers.JsonRpcProvider;\n readonly chainName: ChainName;\n\n private _signer: ethers.Signer | null;\n private _address: string | null;\n private _registry: ethers.Contract;\n private _keyManager: ethers.Contract;\n private _schemaRegistry: ethers.Contract;\n private _identityRegistry: ethers.Contract | null;\n private _escrow: ethers.Contract | null;\n\n /** @deprecated Use `signer` instead. */\n get wallet(): ethers.Signer | null { return this._signer; }\n get signer(): ethers.Signer | null { return this._signer; }\n get registry(): ethers.Contract { return this._registry; }\n get keyManager(): ethers.Contract { return this._keyManager; }\n get schemaRegistry(): ethers.Contract { return this._schemaRegistry; }\n get identityRegistry(): ethers.Contract | null { return this._identityRegistry; }\n get escrow(): ethers.Contract | null { return this._escrow; }\n\n // In-memory ECDH state\n private ecdhPrivateKey: Uint8Array | null = null;\n private ecdhPublicKey: Uint8Array | null = null;\n private topicKeys: Map<number, Uint8Array> = new Map();\n\n // Token decimals cache (ERC-20 decimals never change)\n private tokenDecimalsCache: Map<string, number> = new Map();\n private static ERC20_DECIMALS_ABI = ['function decimals() view returns (uint8)'];\n\n constructor(options: ClawtennaOptions = {}) {\n const chainName = options.chain ?? 'base';\n const chain = CHAINS[chainName];\n if (!chain) throw new Error(`Unsupported chain: ${chainName}`);\n this.chainName = chainName;\n\n const rpcUrl = options.rpcUrl ?? chain.rpc;\n this.provider = new ethers.JsonRpcProvider(rpcUrl);\n\n const registryAddr = options.registryAddress ?? chain.registry;\n const keyManagerAddr = options.keyManagerAddress ?? chain.keyManager;\n const schemaRegistryAddr = options.schemaRegistryAddress ?? chain.schemaRegistry;\n const escrowAddr = options.escrowAddress ?? chain.escrow;\n\n const wallet = options.privateKey\n ? new ethers.Wallet(options.privateKey, this.provider)\n : null;\n const runner = wallet ?? this.provider;\n\n this._signer = wallet;\n this._address = wallet?.address ?? null;\n this._registry = new ethers.Contract(registryAddr, REGISTRY_ABI, runner);\n this._keyManager = new ethers.Contract(keyManagerAddr, KEY_MANAGER_ABI, runner);\n this._schemaRegistry = new ethers.Contract(schemaRegistryAddr, SCHEMA_REGISTRY_ABI, runner);\n this._identityRegistry = chain.identityRegistry\n ? new ethers.Contract(chain.identityRegistry, IDENTITY_REGISTRY_ABI, runner)\n : null;\n this._escrow = escrowAddr\n ? new ethers.Contract(escrowAddr, ESCROW_ABI, runner)\n : null;\n }\n\n /**\n * Connect an external signer (e.g. from BrowserProvider).\n * Reconnects all contract instances to the new signer.\n */\n async connectSigner(signer: ethers.Signer): Promise<void> {\n this._address = await signer.getAddress();\n this._signer = signer;\n this._registry = this._registry.connect(signer) as ethers.Contract;\n this._keyManager = this._keyManager.connect(signer) as ethers.Contract;\n this._schemaRegistry = this._schemaRegistry.connect(signer) as ethers.Contract;\n if (this._identityRegistry) {\n this._identityRegistry = this._identityRegistry.connect(signer) as ethers.Contract;\n }\n if (this._escrow) {\n this._escrow = this._escrow.connect(signer) as ethers.Contract;\n }\n }\n\n private requireSigner(): ethers.Signer {\n if (!this._signer) {\n throw new Error('Signer required. Pass privateKey in constructor or call connectSigner().');\n }\n return this._signer;\n }\n\n private requireAddress(): string {\n if (!this._address) {\n throw new Error('Signer required. Pass privateKey in constructor or call connectSigner().');\n }\n return this._address;\n }\n\n private async _wrapRpcError<T>(fn: () => Promise<T>, method: string): Promise<T> {\n try {\n return await withRetry(fn);\n } catch (err) {\n if (err instanceof Error) {\n const hint = classifyRpcError(err, { method, chainName: this.chainName });\n if (hint) throw new Error(hint, { cause: err });\n }\n throw err;\n }\n }\n\n get address(): string | null {\n return this._address;\n }\n\n // ===== MESSAGING =====\n\n /**\n * Send an encrypted message to a topic.\n * Automatically determines encryption key based on topic access level.\n */\n async sendMessage(topicId: number, text: string, options?: SendOptions): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n\n // Auto-check: refuse to reply to a message whose escrow deposit was refunded\n if (options?.replyTo && this.escrow && !options?.skipRefundCheck) {\n const refunded = await this.isMessageRefunded(options.replyTo);\n if (refunded) {\n throw new Error(`Cannot reply: escrow deposit was refunded (tx: ${options.replyTo})`);\n }\n }\n\n let replyText = options?.replyText;\n let replyAuthor = options?.replyAuthor;\n\n // Auto-resolve reply metadata if replyTo is set but text/author aren't\n if (options?.replyTo && (!replyText || !replyAuthor)) {\n try {\n const messages = await this.readMessages(topicId, { limit: 50 });\n const original = messages.find(m => m.txHash === options.replyTo);\n if (original) {\n replyText = replyText || original.text.slice(0, 100);\n replyAuthor = replyAuthor || original.sender;\n }\n } catch {\n // Non-fatal: reply will still work, just without cached text/author\n }\n }\n\n const key = await this.getEncryptionKey(topicId);\n const encrypted = encryptMessage(text, key, {\n replyTo: options?.replyTo,\n replyText,\n replyAuthor,\n mentions: options?.mentions,\n });\n\n // Resolve message fee and attach msg.value for native ETH fees\n const txOverrides: { value?: bigint } = {};\n try {\n const fee = await this.getTopicMessageFee(topicId);\n if (fee.amount > BigInt(0)) {\n const exempt = await this._isFeeExempt(topicId);\n if (!exempt) {\n if (fee.token === ethers.ZeroAddress) {\n txOverrides.value = fee.amount;\n } else {\n // ERC-20: ensure allowance (auto-approve for the exact amount)\n const token = new ethers.Contract(fee.token, [\n 'function allowance(address,address) view returns (uint256)',\n 'function approve(address,uint256) returns (bool)',\n ], this._signer!);\n const registryAddr = await this._registry.getAddress();\n const allowance: bigint = await token.allowance(this._address!, registryAddr);\n if (allowance < fee.amount) {\n const approveTx = await token.approve(registryAddr, fee.amount);\n await approveTx.wait();\n }\n }\n }\n }\n } catch {\n // Non-fatal: if fee check fails, let the contract revert with a clear error\n }\n\n return this.registry.sendMessage(topicId, ethers.toUtf8Bytes(encrypted), txOverrides);\n }\n\n /**\n * Check if the current signer is exempt from message fees on a topic.\n * Mirrors contract logic: topic owner, app owner, ROLE_ADMIN, PERMISSION_ADMIN.\n */\n private async _isFeeExempt(topicId: number): Promise<boolean> {\n const addr = this._address!.toLowerCase();\n const topic = await this.getTopic(topicId);\n\n if (topic.owner.toLowerCase() === addr) return true;\n\n const app = await this.getApplication(Number(topic.applicationId));\n if (app.owner.toLowerCase() === addr) return true;\n\n try {\n const member = await this.getMember(Number(topic.applicationId), this._address!);\n if ((member.roles & Role.ADMIN) !== 0) return true;\n } catch {\n // Not a member — not exempt via role\n }\n\n try {\n const perm = await this.getTopicPermission(topicId, this._address!);\n if (perm === Permission.ADMIN) return true;\n } catch {\n // No permission set\n }\n\n return false;\n }\n\n /**\n * Read and decrypt recent messages from a topic.\n */\n async readMessages(topicId: number, options?: ReadOptions): Promise<Message[]> {\n const limit = options?.limit ?? 50;\n const key = await this.getEncryptionKey(topicId);\n const filter = this.registry.filters.MessageSent(topicId);\n\n // Chunked log fetching to stay within RPC limits (e.g. Avalanche 2048 block cap)\n const CHUNK_SIZE = 2000;\n const currentBlock = await this.provider.getBlockNumber();\n const chain = CHAINS[this.chainName];\n const maxRange = options?.fromBlock != null ? currentBlock - options.fromBlock : chain.defaultLookback;\n const startBlock = currentBlock - maxRange;\n\n const allEvents: ethers.EventLog[] = [];\n let toBlock = currentBlock;\n\n while (toBlock > startBlock && allEvents.length < limit) {\n const chunkFrom = Math.max(toBlock - CHUNK_SIZE + 1, startBlock);\n const events = await this._wrapRpcError(\n () => this.registry.queryFilter(filter, chunkFrom, toBlock),\n 'readMessages',\n );\n // Prepend since we're walking backwards\n allEvents.unshift(...(events as ethers.EventLog[]));\n toBlock = chunkFrom - 1;\n }\n\n const recent = allEvents.slice(-limit);\n const messages: Message[] = [];\n\n for (const log of recent) {\n const payloadStr = ethers.toUtf8String(log.args.payload);\n const parsed = decryptMessage(payloadStr, key);\n\n messages.push({\n topicId,\n sender: log.args.sender,\n text: parsed?.text ?? '[decryption failed]',\n replyTo: parsed?.replyTo ?? null,\n mentions: parsed?.mentions ?? null,\n timestamp: Number(log.args.timestamp),\n txHash: log.transactionHash,\n blockNumber: log.blockNumber,\n });\n }\n\n return messages;\n }\n\n /**\n * Subscribe to real-time messages on a topic.\n * Returns an unsubscribe function.\n */\n onMessage(\n topicId: number,\n callback: (msg: Message) => void\n ): () => void {\n let key: Uint8Array | null = null;\n\n // Pre-derive key, then start listening\n this.getEncryptionKey(topicId).then((k) => {\n key = k;\n });\n\n const handler = (\n tId: bigint,\n sender: string,\n payload: string,\n timestamp: bigint,\n event: ethers.EventLog\n ) => {\n if (!key) return;\n const payloadStr = ethers.toUtf8String(payload);\n const parsed = decryptMessage(payloadStr, key);\n\n callback({\n topicId: Number(tId),\n sender,\n text: parsed?.text ?? '[decryption failed]',\n replyTo: parsed?.replyTo ?? null,\n mentions: parsed?.mentions ?? null,\n timestamp: Number(timestamp),\n txHash: event.transactionHash,\n blockNumber: event.blockNumber,\n });\n };\n\n this.registry.on(this.registry.filters.MessageSent(topicId), handler);\n return () => {\n this.registry.off(this.registry.filters.MessageSent(topicId), handler);\n };\n }\n\n // ===== NICKNAMES =====\n\n async setNickname(appId: number, nickname: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setNickname(appId, nickname);\n }\n\n async getNickname(appId: number, address: string): Promise<string> {\n return this.registry.getNickname(appId, address);\n }\n\n async hasNickname(appId: number, address: string): Promise<boolean> {\n return this.registry.hasNickname(appId, address);\n }\n\n async canChangeNickname(appId: number, address: string): Promise<{ canChange: boolean; timeRemaining: bigint }> {\n const [canChange, timeRemaining] = await this.registry.canChangeNickname(appId, address);\n return { canChange, timeRemaining };\n }\n\n async clearNickname(appId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.clearNickname(appId);\n }\n\n async setNicknameCooldown(appId: number, cooldownSeconds: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setNicknameCooldown(appId, cooldownSeconds);\n }\n\n async getNicknameCooldown(appId: number): Promise<bigint> {\n return this.registry.appNicknameCooldown(appId);\n }\n\n // ===== TOPICS =====\n\n async createTopic(\n appId: number,\n name: string,\n description: string,\n accessLevel: AccessLevel\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n\n // Resolve topic creation fee and attach msg.value for native ETH\n const txOverrides: { value?: bigint } = {};\n try {\n const app = await this.getApplication(appId);\n const feeAmount = app.topicCreationFeeAmount ?? BigInt(0);\n const feeToken = app.topicCreationFeeToken ?? ethers.ZeroAddress;\n if (feeAmount > BigInt(0) && feeToken === ethers.ZeroAddress) {\n txOverrides.value = feeAmount;\n } else if (feeAmount > BigInt(0)) {\n // ERC-20: auto-approve\n const token = new ethers.Contract(feeToken, [\n 'function allowance(address,address) view returns (uint256)',\n 'function approve(address,uint256) returns (bool)',\n ], this._signer!);\n const registryAddr = await this._registry.getAddress();\n const allowance: bigint = await token.allowance(this._address!, registryAddr);\n if (allowance < feeAmount) {\n const approveTx = await token.approve(registryAddr, feeAmount);\n await approveTx.wait();\n }\n }\n } catch {\n // Non-fatal\n }\n\n return this.registry.createTopic(appId, name, description, accessLevel, txOverrides);\n }\n\n async getTopic(topicId: number): Promise<Topic> {\n return this._wrapRpcError(async () => {\n const t = await this.registry.getTopic(topicId);\n return {\n id: t.id,\n applicationId: t.applicationId,\n name: t.name,\n description: t.description,\n owner: t.owner,\n creator: t.creator,\n createdAt: t.createdAt,\n lastMessageAt: t.lastMessageAt,\n messageCount: t.messageCount,\n accessLevel: Number(t.accessLevel),\n active: t.active,\n };\n }, 'getTopic');\n }\n\n async getApplicationTopics(appId: number): Promise<bigint[]> {\n return this.registry.getApplicationTopics(appId);\n }\n\n async getTopicCount(): Promise<number> {\n const count = await this.registry.topicCount();\n return Number(count);\n }\n\n async setTopicPermission(\n topicId: number,\n user: string,\n permission: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.setTopicPermission(topicId, user, permission);\n }\n\n async getTopicPermission(topicId: number, user: string): Promise<number> {\n const perm = await this.registry.getTopicPermission(topicId, user);\n return Number(perm);\n }\n\n // ===== MEMBERS =====\n\n async addMember(\n appId: number,\n address: string,\n nickname: string,\n roles: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.addMember(appId, address, nickname, roles);\n }\n\n async removeMember(appId: number, address: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.removeMember(appId, address);\n }\n\n async updateMemberRoles(\n appId: number,\n address: string,\n roles: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.updateMemberRoles(appId, address, roles);\n }\n\n async getMember(appId: number, address: string): Promise<Member> {\n const m = await this.registry.getMember(appId, address);\n return {\n account: m.account,\n nickname: m.nickname,\n roles: Number(m.roles),\n joinedAt: m.joinedAt,\n };\n }\n\n async isMember(appId: number, address: string): Promise<boolean> {\n return this.registry.isMember(appId, address);\n }\n\n async getApplicationMembers(appId: number): Promise<string[]> {\n return this.registry.getApplicationMembers(appId);\n }\n\n // ===== ACCESS CHECKS =====\n\n async canRead(topicId: number, address: string): Promise<boolean> {\n return this.registry.canReadTopic(topicId, address);\n }\n\n async canWrite(topicId: number, address: string): Promise<boolean> {\n return this.registry.canWriteToTopic(topicId, address);\n }\n\n // ===== APPLICATIONS =====\n\n async createApplication(\n name: string,\n description: string,\n frontendUrl: string,\n allowPublicTopicCreation: boolean\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.createApplication(name, description, frontendUrl, allowPublicTopicCreation);\n }\n\n async getApplicationCount(): Promise<number> {\n const count = await this.registry.applicationCount();\n return Number(count);\n }\n\n async updateFrontendUrl(appId: number, frontendUrl: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.updateApplicationFrontendUrl(appId, frontendUrl);\n }\n\n async getApplication(appId: number): Promise<Application> {\n return this._wrapRpcError(async () => {\n const a = await this.registry.getApplication(appId);\n return {\n id: a.id,\n name: a.name,\n description: a.description,\n frontendUrl: a.frontendUrl,\n owner: a.owner,\n createdAt: a.createdAt,\n memberCount: Number(a.memberCount),\n topicCount: Number(a.topicCount),\n active: a.active,\n allowPublicTopicCreation: a.allowPublicTopicCreation,\n topicCreationFeeToken: a.topicCreationFeeToken,\n topicCreationFeeAmount: a.topicCreationFeeAmount,\n };\n }, 'getApplication');\n }\n\n // ===== FEES =====\n\n async getTopicMessageFee(topicId: number): Promise<TopicMessageFee> {\n const [token, amount] = await this.registry.getTopicMessageFee(topicId);\n return { token, amount };\n }\n\n /**\n * Set topic creation fee for an application (app admin only).\n * feeAmount accepts:\n * - bigint: raw token units (e.g. 150000n for 0.15 USDC)\n * - string | number: human-readable amount — decimals are auto-resolved from the token contract\n * (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)\n */\n async setTopicCreationFee(\n appId: number,\n feeToken: string,\n feeAmount: bigint | string | number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const rawAmount = typeof feeAmount === 'bigint'\n ? feeAmount\n : await this.parseTokenAmount(feeToken, feeAmount);\n return this.registry.setTopicCreationFee(appId, feeToken, rawAmount);\n }\n\n /**\n * Set per-message fee for a topic (topic admin only).\n * feeAmount accepts:\n * - bigint: raw token units (e.g. 150000n for 0.15 USDC)\n * - string | number: human-readable amount — decimals are auto-resolved from the token contract\n * (e.g. '0.15' or 0.15 with USDC → 150000n, '0.01' with native ETH → 10000000000000000n)\n */\n async setTopicMessageFee(\n topicId: number,\n feeToken: string,\n feeAmount: bigint | string | number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const rawAmount = typeof feeAmount === 'bigint'\n ? feeAmount\n : await this.parseTokenAmount(feeToken, feeAmount);\n return this.registry.setTopicMessageFee(topicId, feeToken, rawAmount);\n }\n\n // ===== TOKEN AMOUNTS =====\n\n /**\n * Get the number of decimals for an ERC-20 token.\n * Returns 18 for native ETH (address(0)).\n * Results are cached per token address.\n */\n async getTokenDecimals(tokenAddress: string): Promise<number> {\n if (tokenAddress === ethers.ZeroAddress) return 18;\n\n const key = tokenAddress.toLowerCase();\n const cached = this.tokenDecimalsCache.get(key);\n if (cached !== undefined) return cached;\n\n const erc20 = new ethers.Contract(tokenAddress, Clawntenna.ERC20_DECIMALS_ABI, this.provider);\n const decimals = Number(await erc20.decimals());\n this.tokenDecimalsCache.set(key, decimals);\n return decimals;\n }\n\n /**\n * Convert a human-readable token amount to raw units (bigint).\n * Looks up the token's on-chain decimals automatically.\n *\n * Examples:\n * parseTokenAmount('0xUSDC...', '0.15') → 150000n (USDC = 6 decimals)\n * parseTokenAmount('0xUSDC...', 10) → 10000000n (USDC = 6 decimals)\n * parseTokenAmount(ZeroAddress, '0.01') → 10000000000000000n (native ETH = 18 decimals)\n */\n async parseTokenAmount(tokenAddress: string, amount: string | number): Promise<bigint> {\n const decimals = await this.getTokenDecimals(tokenAddress);\n return ethers.parseUnits(String(amount), decimals);\n }\n\n /**\n * Convert raw token units (bigint) to a human-readable string.\n * Looks up the token's on-chain decimals automatically.\n *\n * Examples:\n * formatTokenAmount('0xUSDC...', 150000n) → '0.15'\n * formatTokenAmount(ZeroAddress, 10000000000000000n) → '0.01'\n */\n async formatTokenAmount(tokenAddress: string, amount: bigint): Promise<string> {\n const decimals = await this.getTokenDecimals(tokenAddress);\n return ethers.formatUnits(amount, decimals);\n }\n\n // ===== ESCROW =====\n\n private requireEscrow(): ethers.Contract {\n if (!this.escrow) {\n throw new Error('Escrow not available on this chain. Use baseSepolia or pass escrowAddress.');\n }\n return this.escrow;\n }\n\n /**\n * Enable escrow for a topic (topic owner only).\n */\n async enableEscrow(topicId: number, timeout: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().enableEscrow(topicId, timeout);\n }\n\n /**\n * Disable escrow for a topic (topic owner only).\n */\n async disableEscrow(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().disableEscrow(topicId);\n }\n\n /**\n * Check if escrow is enabled for a topic.\n */\n async isEscrowEnabled(topicId: number): Promise<boolean> {\n return this.requireEscrow().isEscrowEnabled(topicId);\n }\n\n /**\n * Get escrow config for a topic (enabled + timeout).\n */\n async getEscrowConfig(topicId: number): Promise<EscrowConfig> {\n const escrow = this.requireEscrow();\n const [enabled, timeout] = await Promise.all([\n escrow.isEscrowEnabled(topicId) as Promise<boolean>,\n escrow.topicEscrowTimeout(topicId) as Promise<bigint>,\n ]);\n return { enabled, timeout };\n }\n\n /**\n * Get full deposit details by ID.\n */\n async getDeposit(depositId: number): Promise<EscrowDeposit> {\n const d = await this.requireEscrow().getDeposit(depositId);\n return {\n id: d.id,\n topicId: d.topicId,\n sender: d.sender,\n recipient: d.recipient,\n token: d.token,\n amount: d.amount,\n appOwner: d.appOwner,\n depositedAt: d.depositedAt,\n timeout: d.timeout,\n status: Number(d.status) as DepositStatus,\n };\n }\n\n /**\n * Get deposit status (0=Pending, 1=Released, 2=Refunded).\n */\n async getDepositStatus(depositId: number): Promise<DepositStatus> {\n const status = await this.requireEscrow().getDepositStatus(depositId);\n return Number(status) as DepositStatus;\n }\n\n /**\n * Get pending deposit IDs for a topic.\n */\n async getPendingDeposits(topicId: number): Promise<bigint[]> {\n return this.requireEscrow().getPendingDeposits(topicId);\n }\n\n /**\n * Check if a deposit can be refunded (timeout expired and still pending).\n */\n async canClaimRefund(depositId: number): Promise<boolean> {\n return this.requireEscrow().canClaimRefund(depositId);\n }\n\n /**\n * Claim a refund for a single deposit.\n */\n async claimRefund(depositId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().claimRefund(depositId);\n }\n\n /**\n * Batch claim refunds for multiple deposits.\n */\n async batchClaimRefunds(depositIds: number[]): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().batchClaimRefunds(depositIds);\n }\n\n /**\n * Respond to specific deposits by sending a message and binding it on-chain (topic owner only).\n * This creates an auditable record: \"at block X, owner sent message Y for deposits [a, b, c]\".\n * Each deposit must have a recorded response before it can be released.\n * @param topicId Topic ID\n * @param payload Message payload (encrypted response)\n * @param depositIds Array of deposit IDs being responded to\n */\n async respondToDeposits(topicId: number, payload: string | Uint8Array, depositIds: number[]): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.respondToDeposits(topicId, payload, depositIds);\n }\n\n /**\n * Release a single escrow deposit (topic owner only).\n * Requires a prior respondToDeposits() call for this deposit.\n * @param depositId Deposit ID to release\n * @param messageRef Optional off-chain message reference (default 0)\n */\n async releaseDeposit(depositId: number, messageRef: number = 0): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().releaseDeposit(depositId, messageRef);\n }\n\n /**\n * Batch release escrow deposits (topic owner only, max 50).\n * Requires a prior respondToDeposits() call for each deposit.\n * @param depositIds Array of deposit IDs to release\n * @param messageRefs Optional array of off-chain references (empty or same length)\n */\n async batchReleaseDeposits(depositIds: number[], messageRefs: number[] = []): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.requireEscrow().batchReleaseDeposits(depositIds, messageRefs);\n }\n\n /**\n * Get the message reference for a released deposit.\n */\n async getDepositMessageRef(depositId: number): Promise<bigint> {\n return this.requireEscrow().getDepositMessageRef(depositId);\n }\n\n /**\n * Check if a deposit has a recorded owner response.\n */\n async hasResponse(depositId: number): Promise<boolean> {\n return this.requireEscrow().hasResponse(depositId);\n }\n\n /**\n * Get lifetime escrow stats for a wallet (V4).\n */\n async getRecipientStats(wallet: string): Promise<RecipientStats> {\n const s = await this.requireEscrow().getRecipientStats(wallet);\n return {\n depositsReceived: BigInt(s.depositsReceived),\n depositsReleased: BigInt(s.depositsReleased),\n depositsRefunded: BigInt(s.depositsRefunded),\n depositsExpired: BigInt(s.depositsExpired),\n };\n }\n\n /**\n * Get credibility snapshot for a wallet (V4).\n * Returns response rate as 0-100 percentage and lifetime escrow totals.\n */\n async getWalletCredibility(wallet: string): Promise<WalletCredibility> {\n const escrow = this.requireEscrow();\n const cred = await escrow.getCredibility(wallet);\n\n // Convert basis points to percentage\n const responseRate = Number(cred.responseRate) / 100;\n\n // Try to format amounts using the first deposit's token, fall back to null\n let formattedEarned: string | null = null;\n let formattedRefunded: string | null = null;\n try {\n // For native ETH (most common), format as ether\n formattedEarned = ethers.formatEther(cred.totalEarned);\n formattedRefunded = ethers.formatEther(cred.totalRefunded);\n } catch {\n // Non-fatal\n }\n\n return {\n responseRate,\n depositsReceived: BigInt(cred.depositsReceived),\n depositsReleased: BigInt(cred.depositsReleased),\n depositsRefunded: BigInt(cred.depositsRefunded),\n totalEarned: BigInt(cred.totalEarned),\n totalRefunded: BigInt(cred.totalRefunded),\n formattedEarned,\n formattedRefunded,\n };\n }\n\n /**\n * Get the on-chain total amount earned by a wallet via escrow releases (V4).\n */\n async getAmountEarned(wallet: string): Promise<bigint> {\n return this.requireEscrow().amountEarned(wallet);\n }\n\n /**\n * Get the on-chain total amount lost to refunds for a wallet (V4).\n */\n async getAmountRefunded(wallet: string): Promise<bigint> {\n return this.requireEscrow().amountRefunded(wallet);\n }\n\n /**\n * Get response rate for a wallet as basis points (0-10000) (V4).\n */\n async getResponseRate(wallet: string): Promise<number> {\n const rate = await this.requireEscrow().getResponseRate(wallet);\n return Number(rate);\n }\n\n /**\n * Parse a transaction receipt to extract the depositId from a DepositRecorded event.\n * Returns null if no DepositRecorded event is found (e.g. no escrow on this tx).\n */\n async getMessageDepositId(txHash: string): Promise<bigint | null> {\n if (!this.escrow) return null;\n\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (!receipt) return null;\n\n const iface = this.escrow.interface;\n for (const log of receipt.logs) {\n try {\n const parsed = iface.parseLog(log);\n if (parsed?.name === 'DepositRecorded') {\n return parsed.args.depositId;\n }\n } catch { /* skip non-matching logs */ }\n }\n return null;\n }\n\n /**\n * Get the deposit status for a message by its transaction hash.\n * Returns null if the message has no associated escrow deposit.\n */\n async getMessageDepositStatus(txHash: string): Promise<DepositStatus | null> {\n const depositId = await this.getMessageDepositId(txHash);\n if (depositId === null) return null;\n return this.getDepositStatus(Number(depositId));\n }\n\n /**\n * Check if a message's escrow deposit was refunded.\n * Returns false if no escrow deposit exists for the tx.\n */\n async isMessageRefunded(txHash: string): Promise<boolean> {\n const status = await this.getMessageDepositStatus(txHash);\n return status === DepositStatus.Refunded;\n }\n\n /**\n * Get timer info for a deposit — remaining time, expiry status, and claimability.\n * Useful for building countdown UIs.\n */\n async getDepositTimer(depositId: number): Promise<DepositTimer> {\n const d = await this.getDeposit(depositId);\n const nowSeconds = Math.floor(Date.now() / 1000);\n const remaining = timeUntilRefund(d.depositedAt, d.timeout, nowSeconds);\n const expired = remaining === 0;\n const canClaim = expired && d.status === DepositStatus.Pending\n ? await this.canClaimRefund(depositId)\n : false;\n\n return {\n depositId: d.id,\n expired,\n remainingSeconds: remaining,\n deadline: getDepositDeadline(d.depositedAt, d.timeout),\n formattedRemaining: formatTimeout(remaining),\n canClaim,\n };\n }\n\n // ===== PRIVATE HELPERS =====\n\n /**\n * Query contract events in chunked ranges to stay within public RPC limits.\n */\n private async _queryFilterChunked(\n contract: ethers.BaseContract,\n filter: ethers.ContractEventName,\n fromBlock: number,\n toBlock: number,\n chunkSize = 10_000,\n ): Promise<ethers.EventLog[]> {\n const results: ethers.EventLog[] = [];\n for (let start = fromBlock; start <= toBlock; start += chunkSize) {\n const end = Math.min(start + chunkSize - 1, toBlock);\n const chunk = await this._wrapRpcError(\n () => contract.queryFilter(filter, start, end),\n 'queryFilterChunked',\n );\n results.push(...(chunk as ethers.EventLog[]));\n }\n return results;\n }\n\n // ===== ESCROW INBOX (deposit → message bridge) =====\n\n /**\n * Reverse lookup: find the transaction hash that created a deposit.\n * Queries DepositRecorded events filtered by depositId (first indexed param).\n */\n async getDepositTxHash(depositId: number): Promise<string | null> {\n const escrow = this.requireEscrow();\n const chain = CHAINS[this.chainName];\n const currentBlock = await this.provider.getBlockNumber();\n const startBlock = currentBlock - chain.defaultLookback;\n\n const filter = escrow.filters.DepositRecorded(depositId);\n const events = await this._queryFilterChunked(escrow, filter, startBlock, currentBlock);\n\n if (events.length === 0) return null;\n return (events[0] as ethers.EventLog).transactionHash;\n }\n\n /**\n * Full reverse lookup: deposit → tx hash → tx receipt → parse MessageSent → decrypt.\n * Returns the tx hash and decoded message, or null if the deposit event isn't found.\n */\n async getDepositMessage(depositId: number): Promise<{ txHash: string; message: Message } | null> {\n const txHash = await this.getDepositTxHash(depositId);\n if (!txHash) return null;\n\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (!receipt) return null;\n\n const msg = await this._parseMessageFromReceipt(receipt);\n if (!msg) return null;\n\n return { txHash, message: msg };\n }\n\n /**\n * Get the \"inbox\" — all pending deposits for a topic, enriched with their linked messages.\n * Sorted newest-first by depositedAt.\n */\n async getEscrowInbox(topicId: number): Promise<EnrichedDeposit[]> {\n const escrow = this.requireEscrow();\n const chain = CHAINS[this.chainName];\n\n // 1. Get pending deposit IDs\n const depositIds = await this.getPendingDeposits(topicId);\n if (depositIds.length === 0) return [];\n\n // 2. Fetch deposit structs\n const deposits = await Promise.all(\n depositIds.map(id => this.getDeposit(Number(id)))\n );\n\n // 3. Single event query to build depositId → txHash map\n const currentBlock = await this.provider.getBlockNumber();\n const startBlock = currentBlock - chain.defaultLookback;\n const topicFilter = escrow.filters.DepositRecorded(null, topicId);\n const events = await this._queryFilterChunked(escrow, topicFilter, startBlock, currentBlock);\n const txHashMap = new Map<string, { txHash: string; blockNumber: number }>();\n for (const evt of events as ethers.EventLog[]) {\n const id = evt.args.depositId.toString();\n txHashMap.set(id, { txHash: evt.transactionHash, blockNumber: evt.blockNumber });\n }\n\n // 4. Check response status for all deposits\n const responseStatuses = await Promise.all(\n depositIds.map(id => this.hasResponse(Number(id)).catch(() => false))\n );\n\n // 5. Fetch receipts and parse messages\n const nowSeconds = Math.floor(Date.now() / 1000);\n const enriched: EnrichedDeposit[] = [];\n\n for (let i = 0; i < deposits.length; i++) {\n const deposit = deposits[i];\n const idStr = deposit.id.toString();\n const eventInfo = txHashMap.get(idStr);\n const txHash = eventInfo?.txHash ?? '';\n const blockNumber = eventInfo?.blockNumber ?? 0;\n\n // Parse message from receipt\n let messageText: string | null = null;\n if (txHash) {\n try {\n const receipt = await this.provider.getTransactionReceipt(txHash);\n if (receipt) {\n const msg = await this._parseMessageFromReceipt(receipt);\n messageText = msg?.text ?? null;\n }\n } catch {\n // Non-fatal: message text stays null\n }\n }\n\n // Timer info\n const remaining = timeUntilRefund(deposit.depositedAt, deposit.timeout, nowSeconds);\n const expired = remaining === 0;\n\n // Format amount\n let formattedAmount: string | null = null;\n try {\n formattedAmount = await this.formatTokenAmount(deposit.token, deposit.amount);\n } catch {\n // Token contract might not exist\n }\n\n enriched.push({\n ...deposit,\n txHash,\n blockNumber,\n messageText,\n hasResponse: responseStatuses[i],\n remainingSeconds: remaining,\n formattedRemaining: formatTimeout(remaining),\n expired,\n formattedAmount,\n });\n }\n\n // Sort newest first\n enriched.sort((a, b) => Number(b.depositedAt - a.depositedAt));\n return enriched;\n }\n\n /**\n * Parse a MessageSent event from a transaction receipt and decrypt it.\n * Returns null if no MessageSent event is found.\n */\n private async _parseMessageFromReceipt(receipt: ethers.TransactionReceipt): Promise<Message | null> {\n const iface = this.registry.interface;\n for (const log of receipt.logs) {\n try {\n const parsed = iface.parseLog(log);\n if (parsed?.name === 'MessageSent') {\n const topicId = Number(parsed.args.topicId);\n const sender = parsed.args.sender as string;\n const payloadBytes = parsed.args.payload as string;\n const timestamp = Number(parsed.args.timestamp);\n\n let text = '[unable to decrypt]';\n try {\n const key = await this.getEncryptionKey(topicId);\n const payloadStr = ethers.toUtf8String(payloadBytes);\n const result = decryptMessage(payloadStr, key);\n if (result) text = result.text;\n } catch {\n // Decryption failed — private topic without key loaded\n }\n\n return {\n topicId,\n sender,\n text,\n replyTo: null,\n mentions: null,\n timestamp,\n txHash: receipt.hash,\n blockNumber: receipt.blockNumber,\n };\n }\n } catch { /* skip non-matching logs */ }\n }\n return null;\n }\n\n // ===== ECDH (Private Topics) =====\n\n /**\n * Derive ECDH keypair from wallet signature (deterministic).\n * Requires a signer capable of signing messages.\n */\n async deriveECDHFromWallet(appId: number = 1): Promise<{ publicKey: Uint8Array }> {\n this.requireSigner();\n\n const signer = this._signer!;\n const { privateKey, publicKey } = await deriveKeypairFromSignature(\n this.requireAddress(),\n (msg) => signer.signMessage(msg),\n appId\n );\n\n this.ecdhPrivateKey = privateKey;\n this.ecdhPublicKey = publicKey;\n return { publicKey };\n }\n\n /**\n * Load ECDH keypair from a hex private key (e.g. from credentials file).\n */\n loadECDHKeypair(privateKeyHex: string): void {\n const { privateKey, publicKey } = keypairFromPrivateKey(privateKeyHex);\n this.ecdhPrivateKey = privateKey;\n this.ecdhPublicKey = publicKey;\n }\n\n /**\n * Register ECDH public key on-chain.\n */\n async registerPublicKey(): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPublicKey) throw new Error('ECDH key not derived yet');\n\n const hasKey = await this.keyManager.hasPublicKey(this.requireAddress());\n if (hasKey) {\n throw new Error('Public key already registered on-chain');\n }\n\n return this.keyManager.registerPublicKey(this.ecdhPublicKey);\n }\n\n /**\n * Fetch and decrypt the topic symmetric key from an on-chain ECDH grant.\n */\n async fetchAndDecryptTopicKey(topicId: number): Promise<Uint8Array> {\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const grant = await this.keyManager.getMyKey(topicId);\n const encryptedKey = ethers.getBytes(grant.encryptedKey);\n const granterPubKey = ethers.getBytes(grant.granterPublicKey);\n\n // No grant exists yet (empty bytes) — cannot decrypt\n if (encryptedKey.length === 0 || granterPubKey.length === 0) {\n throw new Error(`No key grant found for topic ${topicId}. The topic key needs to be initialized first.`);\n }\n\n const topicKey = decryptTopicKey(encryptedKey, this.ecdhPrivateKey, granterPubKey);\n this.topicKeys.set(topicId, topicKey);\n return topicKey;\n }\n\n /**\n * Initialize a private topic's symmetric key by generating a random key and self-granting.\n * This should be called once by the topic owner after creating a PRIVATE topic.\n * Returns the generated topic key.\n */\n async initializeTopicKey(topicId: number): Promise<Uint8Array> {\n this.requireSigner();\n if (!this.ecdhPrivateKey || !this.ecdhPublicKey) {\n throw new Error('ECDH key not derived yet');\n }\n\n // Generate random 32-byte topic symmetric key\n const topicKey = randomBytes(32);\n\n // Encrypt for ourselves (self-grant)\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, this.ecdhPublicKey);\n\n // Store on-chain as a self-grant\n const tx = await this.keyManager.grantKeyAccess(topicId, this.requireAddress(), encrypted);\n await tx.wait();\n\n // Cache locally\n this.topicKeys.set(topicId, topicKey);\n return topicKey;\n }\n\n /**\n * Get the topic key, initializing it if the caller is the topic owner and no grant exists.\n * Tries fetchAndDecryptTopicKey first; if no grant exists and caller is topic owner,\n * auto-initializes with initializeTopicKey.\n */\n async getOrInitializeTopicKey(topicId: number): Promise<Uint8Array> {\n try {\n return await this.fetchAndDecryptTopicKey(topicId);\n } catch (err) {\n const isNoGrant = err instanceof Error && err.message.includes('No key grant found');\n if (!isNoGrant) throw err;\n\n // Check if we're the topic owner — only owners can initialize\n const topic = await this.getTopic(topicId);\n if (!this._signer || topic.owner.toLowerCase() !== this._address!.toLowerCase()) {\n throw new Error(\n `No key grant found for topic ${topicId}. Ask the topic owner to grant you access with: keys grant ${topicId} ${this._address ?? '<your-address>'}`\n );\n }\n\n // Auto-initialize as the topic owner\n return this.initializeTopicKey(topicId);\n }\n }\n\n /**\n * Grant a user access to a private topic's symmetric key.\n */\n async grantKeyAccess(\n topicId: number,\n userAddress: string,\n topicKey: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const hasKey = await this.keyManager.hasPublicKey(userAddress);\n if (!hasKey) {\n throw new Error(\n `User ${userAddress} has no ECDH public key registered. They must run 'keys register' first.`\n );\n }\n\n const userPubKeyBytes = ethers.getBytes(await this.keyManager.getPublicKey(userAddress));\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, userPubKeyBytes);\n return this.keyManager.grantKeyAccess(topicId, userAddress, encrypted);\n }\n\n /**\n * Store a pre-known topic key (e.g. loaded from credentials).\n */\n setTopicKey(topicId: number, key: Uint8Array): void {\n this.topicKeys.set(topicId, key);\n }\n\n /**\n * Check if an address has an ECDH public key registered on-chain.\n */\n async hasPublicKey(address: string): Promise<boolean> {\n return this.keyManager.hasPublicKey(address);\n }\n\n /**\n * Get an address's ECDH public key from chain.\n */\n async getPublicKey(address: string): Promise<Uint8Array> {\n const key = await this.keyManager.getPublicKey(address);\n return ethers.getBytes(key);\n }\n\n /**\n * Check if a user has key access for a topic.\n */\n async hasKeyAccess(topicId: number, address: string): Promise<boolean> {\n return this.keyManager.hasKeyAccess(topicId, address);\n }\n\n /**\n * Get members who have registered ECDH keys but haven't been granted access to a private topic.\n * Useful for topic owners to see who's waiting for a key grant.\n */\n async getPendingKeyGrants(topicId: number): Promise<{\n pending: Array<{ address: string; hasPublicKey: boolean }>;\n granted: string[];\n }> {\n const topic = await this.getTopic(topicId);\n const members = await this.getApplicationMembers(Number(topic.applicationId));\n\n // Filter out zero addresses and deduplicate\n const uniqueMembers = [...new Set(members)].filter(a => a !== ethers.ZeroAddress);\n\n const pending: Array<{ address: string; hasPublicKey: boolean }> = [];\n const granted: string[] = [];\n\n await Promise.all(\n uniqueMembers.map(async (addr) => {\n const [hasAccess, hasKey] = await Promise.all([\n this.hasKeyAccess(topicId, addr),\n this.hasPublicKey(addr),\n ]);\n\n if (hasAccess) {\n granted.push(addr);\n } else {\n pending.push({ address: addr, hasPublicKey: hasKey });\n }\n })\n );\n\n return { pending, granted };\n }\n\n /**\n * Get the key grant details for a user on a topic.\n */\n async getKeyGrant(topicId: number, address: string): Promise<{\n encryptedKey: Uint8Array;\n granterPublicKey: Uint8Array;\n granter: string;\n keyVersion: bigint;\n grantedAt: bigint;\n }> {\n const g = await this.keyManager.getKeyGrant(topicId, address);\n return {\n encryptedKey: ethers.getBytes(g.encryptedKey),\n granterPublicKey: ethers.getBytes(g.granterPublicKey),\n granter: g.granter,\n keyVersion: g.keyVersion,\n grantedAt: g.grantedAt,\n };\n }\n\n /**\n * Get the current key version for a topic.\n */\n async getKeyVersion(topicId: number): Promise<bigint> {\n return this.keyManager.keyVersions(topicId);\n }\n\n /**\n * Batch grant key access to multiple users at once (max 50).\n */\n async batchGrantKeyAccess(\n topicId: number,\n users: string[],\n topicKey: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n if (!this.ecdhPrivateKey) throw new Error('ECDH key not derived yet');\n\n const encryptedKeys: Uint8Array[] = [];\n for (const user of users) {\n const userPubKeyBytes = ethers.getBytes(await this.keyManager.getPublicKey(user));\n const encrypted = encryptTopicKeyForUser(topicKey, this.ecdhPrivateKey, userPubKeyBytes);\n encryptedKeys.push(encrypted);\n }\n\n return this.keyManager.batchGrantKeyAccess(topicId, users, encryptedKeys);\n }\n\n /**\n * Revoke a user's key access for a topic.\n */\n async revokeKeyAccess(topicId: number, address: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.keyManager.revokeKeyAccess(topicId, address);\n }\n\n /**\n * Rotate the key version for a topic. Existing grants become stale.\n */\n async rotateKey(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.keyManager.rotateKey(topicId);\n }\n\n // ===== SCHEMAS =====\n\n /**\n * Create a schema scoped to an application. Requires app admin role.\n */\n async createAppSchema(\n appId: number,\n name: string,\n description: string,\n body: string\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.createAppSchema(appId, name, description, body);\n }\n\n /**\n * Publish a new version of an existing schema.\n */\n async publishSchemaVersion(\n schemaId: number,\n body: string\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.publishSchemaVersion(schemaId, body);\n }\n\n /**\n * Deactivate a schema.\n */\n async deactivateSchema(schemaId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.deactivateSchema(schemaId);\n }\n\n /**\n * Get schema info including application scope.\n */\n async getSchema(schemaId: number): Promise<SchemaInfo> {\n const s = await this.schemaRegistry.getSchemaWithApp(schemaId);\n return {\n id: Number(s.id),\n name: s.name,\n description: s.description,\n creator: s.creator,\n createdAt: Number(s.createdAt),\n versionCount: Number(s.versionCount),\n active: s.active,\n applicationId: Number(s.applicationId),\n };\n }\n\n /**\n * Get all schemas scoped to an application.\n */\n async getApplicationSchemas(appId: number): Promise<SchemaInfo[]> {\n const ids: bigint[] = await this.schemaRegistry.getApplicationSchemas(appId);\n const schemas: SchemaInfo[] = [];\n for (const id of ids) {\n const s = await this.getSchema(Number(id));\n schemas.push(s);\n }\n return schemas;\n }\n\n /**\n * Get schema body for a specific version.\n */\n async getSchemaBody(schemaId: number, version: number): Promise<string> {\n return this.schemaRegistry.getSchemaBody(schemaId, version);\n }\n\n /**\n * Get the schema binding for a topic.\n */\n async getTopicSchema(topicId: number): Promise<TopicSchemaBinding> {\n const s = await this.schemaRegistry.getTopicSchema(topicId);\n return {\n schemaId: Number(s.schemaId),\n version: Number(s.version),\n body: s.body,\n };\n }\n\n /**\n * Bind a schema version to a topic. Requires topic admin.\n */\n async setTopicSchema(\n topicId: number,\n schemaId: number,\n version: number\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.setTopicSchema(topicId, schemaId, version);\n }\n\n /**\n * Remove schema binding from a topic.\n */\n async clearTopicSchema(topicId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.schemaRegistry.clearTopicSchema(topicId);\n }\n\n // ===== AGENT IDENTITY (V5) =====\n\n /**\n * Register your ERC-8004 agent identity for an application (V5).\n * Verifies ownership via ownerOf on the identity registry.\n */\n async registerAgentIdentity(appId: number, tokenId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.registerAgentIdentity(appId, tokenId);\n }\n\n /**\n * Clear your agent identity registration for an application (V5).\n */\n async clearAgentIdentity(appId: number): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n return this.registry.clearAgentIdentity(appId);\n }\n\n /**\n * Get the registered agent token ID for a user in an application (V5/V6).\n * Returns 0 if not registered. V6 validates ownership live via ownerOf.\n */\n async getAgentTokenId(appId: number, address: string): Promise<bigint> {\n return this.registry.getAgentTokenId(appId, address);\n }\n\n /**\n * Check if a user has a registered agent identity for an application (V5/V6).\n * V6 validates ownership live — returns false if the token was transferred.\n */\n async hasAgentIdentity(appId: number, address: string): Promise<boolean> {\n return this.registry.hasAgentIdentity(appId, address);\n }\n\n // ===== ERC-8004 IDENTITY REGISTRY =====\n\n private requireIdentityRegistry(): ethers.Contract {\n if (!this.identityRegistry) {\n throw new Error('ERC-8004 Identity Registry not available on this chain. Use Base.');\n }\n return this.identityRegistry;\n }\n\n /**\n * Register as an agent on the ERC-8004 Identity Registry.\n * Optionally provide a URI for the agent's metadata.\n */\n async registerAgent(agentURI?: string): Promise<{ agentId: bigint; tx: ethers.TransactionResponse }> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n\n const tx: ethers.TransactionResponse = agentURI\n ? await registry['register(string)'](agentURI)\n : await registry['register()']();\n\n const receipt = await tx.wait();\n let agentId = 0n;\n if (receipt) {\n for (const log of receipt.logs) {\n try {\n const parsed = registry.interface.parseLog(log);\n if (parsed?.name === 'Registered') {\n agentId = parsed.args.agentId;\n break;\n }\n } catch { /* skip non-matching logs */ }\n }\n }\n\n return { agentId, tx };\n }\n\n /**\n * Register as an agent with metadata entries.\n */\n async registerAgentWithMetadata(\n agentURI: string,\n metadata: Array<{ metadataKey: string; metadataValue: Uint8Array }>\n ): Promise<{ agentId: bigint; tx: ethers.TransactionResponse }> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n\n const tx: ethers.TransactionResponse = await registry['register(string,(string,bytes)[])'](agentURI, metadata);\n\n const receipt = await tx.wait();\n let agentId = 0n;\n if (receipt) {\n for (const log of receipt.logs) {\n try {\n const parsed = registry.interface.parseLog(log);\n if (parsed?.name === 'Registered') {\n agentId = parsed.args.agentId;\n break;\n }\n } catch { /* skip non-matching logs */ }\n }\n }\n\n return { agentId, tx };\n }\n\n /**\n * Check if an address has an ERC-8004 agent identity NFT.\n * Defaults to the connected wallet address.\n */\n async isRegisteredAgent(address?: string): Promise<boolean> {\n const registry = this.requireIdentityRegistry();\n const addr = address ?? this._address;\n if (!addr) throw new Error('Address required');\n\n const balance: bigint = await registry.balanceOf(addr);\n return balance > 0n;\n }\n\n /**\n * Get agent info by agent ID.\n */\n async getAgentInfo(agentId: number): Promise<{ owner: string; uri: string; wallet: string }> {\n const registry = this.requireIdentityRegistry();\n\n const [owner, uri, wallet] = await Promise.all([\n registry.ownerOf(agentId) as Promise<string>,\n registry.tokenURI(agentId) as Promise<string>,\n registry.getAgentWallet(agentId) as Promise<string>,\n ]);\n\n return { owner, uri, wallet };\n }\n\n /**\n * Set metadata for an agent.\n */\n async setAgentMetadata(\n agentId: number,\n key: string,\n value: Uint8Array\n ): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n return registry.setMetadata(agentId, key, value);\n }\n\n /**\n * Get metadata for an agent by key.\n */\n async getAgentMetadata(agentId: number, key: string): Promise<string> {\n const registry = this.requireIdentityRegistry();\n const data: string = await registry.getMetadata(agentId, key);\n return ethers.toUtf8String(data);\n }\n\n /**\n * Update the URI for an agent registration.\n */\n async setAgentURI(agentId: number, newURI: string): Promise<ethers.TransactionResponse> {\n this.requireSigner();\n const registry = this.requireIdentityRegistry();\n return registry.setAgentURI(agentId, newURI);\n }\n\n /**\n * Look up an agent by its wallet address using the V5/V6 on-chain registry mapping.\n * V6 validates ownership live — stale registrations (transferred tokens) return 0.\n * Returns registration status, token ID, owner, URI, wallet, and parsed metadata.\n */\n async getAgentByAddress(address: string, appId: number): Promise<\n | { registered: false }\n | { registered: true; agentId: number; owner: string; uri: string; wallet: string; metadata: Record<string, unknown> | null }\n > {\n const onChainTokenId: bigint = await this.registry.getAgentTokenId(appId, address);\n if (onChainTokenId === 0n) return { registered: false };\n\n const agentId = Number(onChainTokenId);\n const { owner, uri, wallet } = await this.getAgentInfo(agentId);\n let metadata: Record<string, unknown> | null = null;\n if (uri) {\n metadata = await this.parseTokenURI(uri);\n }\n return { registered: true, agentId, owner, uri, wallet, metadata };\n }\n\n /**\n * Parse a tokenURI into JSON metadata.\n * Handles data:application/json;base64, data:application/json, HTTP(S), and ipfs:// URIs.\n */\n private async parseTokenURI(uri: string): Promise<Record<string, unknown> | null> {\n try {\n if (uri.startsWith('data:application/json;base64,')) {\n const json = atob(uri.slice('data:application/json;base64,'.length));\n return JSON.parse(json);\n }\n if (uri.startsWith('data:application/json,')) {\n return JSON.parse(decodeURIComponent(uri.slice('data:application/json,'.length)));\n }\n let url = uri;\n if (url.startsWith('ipfs://')) {\n url = 'https://ipfs.io/ipfs/' + url.slice('ipfs://'.length);\n }\n const resp = await fetch(url);\n if (!resp.ok) return null;\n return await resp.json();\n } catch {\n return null;\n }\n }\n\n // ===== DATA EXPORT =====\n\n /**\n * Look up an application ID by its name.\n */\n async getApplicationByName(name: string): Promise<number> {\n const id = await this.registry.applicationNames(name);\n return Number(id);\n }\n\n /**\n * Get schema version details including body and publish timestamp.\n */\n async getSchemaVersion(schemaId: number, version: number): Promise<{ body: string; publishedAt: bigint }> {\n const [body, publishedAt] = await this.schemaRegistry.getSchemaVersion(schemaId, version);\n return { body, publishedAt };\n }\n\n /**\n * Export member data for a user in an application.\n */\n async exportMemberData(appId: number, user: string): Promise<string> {\n const data = await this.registry.exportMemberData(appId, user);\n return ethers.hexlify(data);\n }\n\n /**\n * Export all application data.\n */\n async exportApplicationData(appId: number): Promise<string> {\n const data = await this.registry.exportApplicationData(appId);\n return ethers.hexlify(data);\n }\n\n /**\n * Export user data from the key manager for specified topics.\n */\n async exportUserData(user: string, topicIds: number[]): Promise<string> {\n const data = await this.keyManager.exportUserData(user, topicIds);\n return ethers.hexlify(data);\n }\n\n // ===== INTERNAL =====\n\n /**\n * Get the encryption key for a topic, determining the type automatically.\n */\n private async getEncryptionKey(topicId: number): Promise<Uint8Array> {\n // Check for a stored private topic key first\n const storedKey = this.topicKeys.get(topicId);\n if (storedKey) return storedKey;\n\n // Fetch topic metadata to determine access level\n const topic = await this.getTopic(topicId);\n\n if (topic.accessLevel === AccessLevel.PRIVATE) {\n // Auto-fetch (or auto-initialize for owner) if ECDH keys are loaded\n if (this.ecdhPrivateKey) {\n return this.getOrInitializeTopicKey(topicId);\n }\n throw new Error(\n `Topic ${topicId} is PRIVATE. Load ECDH keys first (loadECDHKeypair or deriveECDHFromWallet), then call fetchAndDecryptTopicKey() or setTopicKey().`\n );\n }\n\n // Public or public_limited: derive deterministic key\n return derivePublicTopicKey(topicId);\n }\n}\n","import type { ChainConfig, ChainName } from './types.js';\n\nexport const CHAINS: Record<ChainName, ChainConfig> = {\n baseSepolia: {\n chainId: 84532,\n name: 'Base Sepolia',\n shortName: 'Sepolia',\n rpc: 'https://sepolia.base.org',\n explorer: 'https://sepolia.basescan.org',\n registry: '0xf39b193aedC1Ec9FD6C5ccc24fBAe58ba9f52413',\n keyManager: '0x5562B553a876CBdc8AA4B3fb0687f22760F4759e',\n schemaRegistry: '0xB7eB50e9058198b99b5b2589E6D70b2d99d5440a',\n identityRegistry: '0x8004AA63c570c570eBF15376c0dB199918BFe9Fb',\n escrow: '0x74e376C53f4afd5Cd32a77dDc627f477FcFC2333',\n defaultLookback: 200_000,\n },\n base: {\n chainId: 8453,\n name: 'Base',\n shortName: 'Base',\n rpc: 'https://mainnet.base.org',\n explorer: 'https://basescan.org',\n registry: '0x5fF6BF04F1B5A78ae884D977a3C80A0D8E2072bF',\n keyManager: '0xdc302ff43a34F6aEa19426D60C9D150e0661E4f4',\n schemaRegistry: '0x5c11d2eA4470eD9025D810A21a885FE16dC987Bd',\n identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',\n escrow: '0x04eC9a25C942192834F447eC9192831B56Ae2D7D',\n defaultLookback: 200_000,\n },\n avalanche: {\n chainId: 43114,\n name: 'Avalanche C-Chain',\n shortName: 'Avalanche',\n rpc: 'https://api.avax.network/ext/bc/C/rpc',\n explorer: 'https://snowtrace.io',\n registry: '0x3Ca2FF0bD1b3633513299EB5d3e2d63e058b0713',\n keyManager: '0x5a5ea9D408FBA984fFf6e243Dcc71ff6E00C73E4',\n schemaRegistry: '0x23D96e610E8E3DA5341a75B77F1BFF7EA9c3A62B',\n identityRegistry: '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432',\n escrow: '0x4068245c35a498Da4336aD1Ab0Fb71ef534bfd03',\n defaultLookback: 500_000,\n },\n};\n\nexport const CHAIN_IDS: Record<number, ChainName> = {\n 84532: 'baseSepolia',\n 8453: 'base',\n 43114: 'avalanche',\n};\n\nexport function getChain(nameOrId: ChainName | number): ChainConfig {\n if (typeof nameOrId === 'number') {\n const name = CHAIN_IDS[nameOrId];\n if (!name) throw new Error(`Unsupported chain ID: ${nameOrId}`);\n return CHAINS[name];\n }\n const chain = CHAINS[nameOrId];\n if (!chain) throw new Error(`Unsupported chain: ${nameOrId}`);\n return chain;\n}\n","export const REGISTRY_ABI = [\n // ===== READ FUNCTIONS =====\n\n // Applications\n 'function applications(uint256) view returns (uint256 id, string name, string description, string frontendUrl, address owner, uint64 createdAt, uint32 memberCount, uint32 topicCount, bool active, bool allowPublicTopicCreation)',\n 'function getApplication(uint256 appId) view returns (tuple(uint256 id, string name, string description, string frontendUrl, address owner, uint64 createdAt, uint32 memberCount, uint32 topicCount, bool active, bool allowPublicTopicCreation, address topicCreationFeeToken, uint256 topicCreationFeeAmount))',\n 'function applicationCount() view returns (uint256)',\n 'function applicationNames(string) view returns (uint256)',\n\n // Topics\n 'function topics(uint256) view returns (uint256 id, uint256 applicationId, string name, string description, address owner, address creator, uint64 createdAt, uint64 lastMessageAt, uint256 messageCount, uint8 accessLevel, bool active)',\n 'function getTopic(uint256 topicId) view returns (tuple(uint256 id, uint256 applicationId, string name, string description, address owner, address creator, uint64 createdAt, uint64 lastMessageAt, uint256 messageCount, uint8 accessLevel, bool active))',\n 'function topicCount() view returns (uint256)',\n 'function getApplicationTopics(uint256 appId) view returns (uint256[])',\n\n // Members\n 'function members(uint256 appId, address user) view returns (address account, string nickname, uint8 roles, uint64 joinedAt)',\n 'function getMember(uint256 appId, address account) view returns (tuple(address account, string nickname, uint8 roles, uint64 joinedAt))',\n 'function isMember(uint256 appId, address account) view returns (bool)',\n 'function getApplicationMembers(uint256 appId) view returns (address[])',\n\n // Permissions\n 'function canReadTopic(uint256 topicId, address user) view returns (bool)',\n 'function canWriteToTopic(uint256 topicId, address user) view returns (bool)',\n 'function getTopicPermission(uint256 topicId, address user) view returns (uint8)',\n 'function topicPermissions(uint256, address) view returns (uint8)',\n\n // Nicknames\n 'function getNickname(uint256 appId, address user) view returns (string)',\n 'function hasNickname(uint256 appId, address user) view returns (bool)',\n 'function canChangeNickname(uint256 appId, address user) view returns (bool canChange, uint256 timeRemaining)',\n 'function appNicknameCooldown(uint256 appId) view returns (uint256)',\n\n // Fees\n 'function getTopicMessageFee(uint256 topicId) view returns (address token, uint256 amount)',\n 'function PLATFORM_FEE_BPS() view returns (uint256)',\n 'function PLATFORM_FEE_BPS_V7() view returns (uint256)',\n 'function APP_OWNER_FEE_BPS() view returns (uint256)',\n 'function BPS_DENOMINATOR() view returns (uint256)',\n\n // ===== WRITE FUNCTIONS =====\n\n // Applications\n 'function createApplication(string name, string description, string frontendUrl, bool allowPublicTopicCreation) returns (uint256)',\n 'function updateApplicationFrontendUrl(uint256 appId, string frontendUrl)',\n\n // Topics\n 'function createTopic(uint256 appId, string name, string description, uint8 accessLevel) returns (uint256)',\n 'function setTopicPermission(uint256 topicId, address user, uint8 permission)',\n\n // Members\n 'function addMember(uint256 appId, address member, string nickname, uint8 roles)',\n 'function removeMember(uint256 appId, address member)',\n 'function updateMemberRoles(uint256 appId, address member, uint8 roles)',\n 'function updateMemberNickname(uint256 appId, string nickname)',\n\n // Nicknames (V3)\n 'function setNickname(uint256 appId, string nickname)',\n 'function clearNickname(uint256 appId)',\n 'function setNicknameCooldown(uint256 appId, uint256 cooldownSeconds)',\n\n // Messaging\n 'function sendMessage(uint256 topicId, bytes payload)',\n // V10 — deposit-bound response\n 'function respondToDeposits(uint256 topicId, bytes payload, uint256[] depositIds)',\n\n // Fees\n 'function setTopicCreationFee(uint256 appId, address feeTokenAddr, uint256 feeAmount)',\n 'function setTopicMessageFee(uint256 topicId, address feeTokenAddr, uint256 feeAmount)',\n\n // ===== EVENTS =====\n 'event ApplicationCreated(uint256 indexed applicationId, string name, address indexed owner)',\n 'event TopicCreated(uint256 indexed topicId, uint256 indexed applicationId, string name, address indexed creator, uint8 accessLevel)',\n 'event MemberAdded(uint256 indexed applicationId, address indexed member, string nickname, uint8 roles)',\n 'event MemberRemoved(uint256 indexed applicationId, address indexed member)',\n 'event MemberRolesUpdated(uint256 indexed applicationId, address indexed member, uint8 roles)',\n 'event NicknameUpdated(uint256 indexed applicationId, address indexed member, string nickname)',\n 'event UserNicknameSet(uint256 indexed applicationId, address indexed user, string nickname)',\n 'event TopicPermissionSet(uint256 indexed topicId, address indexed user, uint8 permission)',\n 'event MessageSent(uint256 indexed topicId, address indexed sender, bytes payload, uint256 timestamp)',\n 'event TopicMessageFeeUpdated(uint256 indexed topicId, address token, uint256 amount)',\n 'event FeeCollected(address indexed token, uint256 totalAmount, address indexed recipient, uint256 recipientAmount, address indexed appOwner, uint256 appOwnerAmount, uint256 platformAmount)',\n\n // Agent identity (V5)\n 'function registerAgentIdentity(uint256 appId, uint256 tokenId)',\n 'function clearAgentIdentity(uint256 appId)',\n 'function getAgentTokenId(uint256 appId, address user) view returns (uint256)',\n 'function hasAgentIdentity(uint256 appId, address user) view returns (bool)',\n 'event AgentIdentityRegistered(uint256 indexed applicationId, address indexed user, uint256 tokenId)',\n 'event AgentIdentityCleared(uint256 indexed applicationId, address indexed user)',\n\n // Data export\n 'function exportMemberData(uint256 appId, address user) view returns (bytes)',\n 'function exportApplicationData(uint256 appId) view returns (bytes)',\n] as const;\n\nexport const SCHEMA_REGISTRY_ABI = [\n // ===== READ FUNCTIONS =====\n\n // Schema queries\n 'function schemaCount() view returns (uint256)',\n 'function getSchema(uint256 schemaId) view returns (uint256 id, string name, string description, address creator, uint64 createdAt, uint256 versionCount, bool active)',\n 'function getSchemaWithApp(uint256 schemaId) view returns (uint256 id, string name, string description, address creator, uint64 createdAt, uint256 versionCount, bool active, uint256 applicationId)',\n 'function getSchemaBody(uint256 schemaId, uint256 version) view returns (string)',\n 'function getSchemaVersion(uint256 schemaId, uint256 version) view returns (string body, uint64 publishedAt)',\n 'function schemaApplicationId(uint256 schemaId) view returns (uint256)',\n\n // App-scoped queries (V2)\n 'function getApplicationSchemas(uint256 applicationId) view returns (uint256[])',\n 'function getApplicationSchemaCount(uint256 applicationId) view returns (uint256)',\n\n // Topic binding\n 'function getTopicSchema(uint256 topicId) view returns (uint256 schemaId, uint256 version, string body)',\n\n // Version\n 'function contractVersion() view returns (string)',\n\n // ===== WRITE FUNCTIONS =====\n\n // Schema creation (V2 app-scoped)\n 'function createAppSchema(uint256 applicationId, string name, string description, string body) returns (uint256)',\n 'function publishSchemaVersion(uint256 schemaId, string body) returns (uint256)',\n 'function deactivateSchema(uint256 schemaId)',\n\n // Topic binding\n 'function setTopicSchema(uint256 topicId, uint256 schemaId, uint256 version)',\n 'function clearTopicSchema(uint256 topicId)',\n\n // ===== EVENTS =====\n 'event AppSchemaCreated(uint256 indexed schemaId, uint256 indexed applicationId, string name, address indexed creator)',\n 'event SchemaVersionPublished(uint256 indexed schemaId, uint256 version)',\n 'event SchemaDeactivated(uint256 indexed schemaId)',\n 'event TopicSchemaSet(uint256 indexed topicId, uint256 indexed schemaId, uint256 version)',\n 'event TopicSchemaCleared(uint256 indexed topicId)',\n 'event SchemaAssignedToApp(uint256 indexed schemaId, uint256 indexed applicationId)',\n] as const;\n\nexport const IDENTITY_REGISTRY_ABI = [\n 'function register() returns (uint256)',\n 'function register(string agentURI) returns (uint256)',\n 'function register(string agentURI, tuple(string metadataKey, bytes metadataValue)[] metadata) returns (uint256)',\n 'function getMetadata(uint256 agentId, string metadataKey) view returns (bytes)',\n 'function setMetadata(uint256 agentId, string metadataKey, bytes metadataValue)',\n 'function setAgentURI(uint256 agentId, string newURI)',\n 'function getAgentWallet(uint256 agentId) view returns (address)',\n 'function setAgentWallet(uint256 agentId, address newWallet, uint256 deadline, bytes signature)',\n 'function unsetAgentWallet(uint256 agentId)',\n 'function ownerOf(uint256 tokenId) view returns (address)',\n 'function balanceOf(address owner) view returns (uint256)',\n 'function tokenOfOwnerByIndex(address owner, uint256 index) view returns (uint256)',\n 'function tokenURI(uint256 tokenId) view returns (string)',\n 'function isAuthorizedOrOwner(address spender, uint256 agentId) view returns (bool)',\n 'function getVersion() pure returns (string)',\n 'event Registered(uint256 indexed agentId, string agentURI, address indexed owner)',\n] as const;\n\nexport const ESCROW_ABI = [\n // ===== READ FUNCTIONS =====\n 'function getVersion() pure returns (string)',\n 'function registry() view returns (address)',\n 'function treasury() view returns (address)',\n 'function depositCount() view returns (uint256)',\n 'function isEscrowEnabled(uint256 topicId) view returns (bool)',\n 'function topicEscrowEnabled(uint256 topicId) view returns (bool)',\n 'function topicEscrowTimeout(uint256 topicId) view returns (uint64)',\n 'function getDeposit(uint256 depositId) view returns (uint256 id, uint256 topicId, address sender, address recipient, address token, uint256 amount, address appOwner, uint64 depositedAt, uint64 timeout, uint8 status)',\n 'function getDepositStatus(uint256 depositId) view returns (uint8)',\n 'function getPendingDeposits(uint256 topicId) view returns (uint256[])',\n 'function canClaimRefund(uint256 depositId) view returns (bool)',\n\n // V3\n 'function depositMessageRef(uint256 depositId) view returns (uint256)',\n 'function getDepositMessageRef(uint256 depositId) view returns (uint256)',\n 'function depositResponseRecorded(uint256 depositId) view returns (bool)',\n 'function hasResponse(uint256 depositId) view returns (bool)',\n\n // ===== WRITE FUNCTIONS =====\n 'function enableEscrow(uint256 topicId, uint64 timeoutSeconds)',\n 'function disableEscrow(uint256 topicId)',\n 'function claimRefund(uint256 depositId)',\n 'function batchClaimRefunds(uint256[] depositIds)',\n // V3 — per-deposit release\n 'function releaseDeposit(uint256 depositId, uint256 messageRef)',\n 'function batchReleaseDeposits(uint256[] depositIds, uint256[] messageRefs)',\n\n // ===== EVENTS =====\n 'event EscrowEnabled(uint256 indexed topicId, uint64 timeout)',\n 'event EscrowDisabled(uint256 indexed topicId)',\n 'event DepositRecorded(uint256 indexed depositId, uint256 indexed topicId, address indexed sender, uint256 amount)',\n 'event DepositReleased(uint256 indexed depositId, uint256 indexed topicId, uint256 recipientAmount, uint256 appOwnerAmount, uint256 platformAmount)',\n 'event DepositRefunded(uint256 indexed depositId, uint256 indexed topicId, address indexed sender, uint256 amount)',\n // V3\n 'event DepositReleasedByOwner(uint256 indexed depositId, uint256 indexed topicId, address indexed releasedBy, uint256 messageRef)',\n 'event DepositResponseRecorded(uint256 indexed depositId, uint256 indexed topicId, address indexed respondedBy)',\n\n // V4 — on-chain accumulators + credibility\n 'function getRecipientStats(address wallet) view returns (tuple(uint64 depositsReceived, uint64 depositsReleased, uint64 depositsRefunded, uint64 depositsExpired))',\n 'function getResponseRate(address wallet) view returns (uint256)',\n 'function getCredibility(address wallet) view returns (uint256 responseRate, uint64 depositsReceived, uint64 depositsReleased, uint64 depositsRefunded, uint256 totalEarned, uint256 totalRefunded)',\n 'function amountEarned(address wallet) view returns (uint256)',\n 'function amountRefunded(address wallet) view returns (uint256)',\n 'event RecipientStatsUpdated(address indexed wallet, uint64 received, uint64 released, uint64 refunded)',\n] as const;\n\nexport const KEY_MANAGER_ABI = [\n // ===== READ FUNCTIONS =====\n 'function hasPublicKey(address user) view returns (bool)',\n 'function getPublicKey(address user) view returns (bytes)',\n 'function publicKeys(address) view returns (bytes)',\n 'function hasKeyAccess(uint256 topicId, address user) view returns (bool)',\n 'function getMyKey(uint256 topicId) view returns (bytes encryptedKey, bytes granterPublicKey, address granter, uint256 keyVersion, uint256 currentVersion)',\n 'function getKeyGrant(uint256 topicId, address user) view returns (tuple(bytes encryptedKey, bytes granterPublicKey, address granter, uint256 keyVersion, uint64 grantedAt))',\n 'function keyVersions(uint256 topicId) view returns (uint256)',\n\n // ===== WRITE FUNCTIONS =====\n 'function registerPublicKey(bytes publicKey)',\n 'function grantKeyAccess(uint256 topicId, address user, bytes encryptedKey)',\n 'function batchGrantKeyAccess(uint256 topicId, address[] users, bytes[] encryptedKeys)',\n 'function revokeKeyAccess(uint256 topicId, address user)',\n 'function rotateKey(uint256 topicId)',\n\n // Data export\n 'function exportUserData(address user, uint256[] topicIds) view returns (bytes)',\n\n // ===== EVENTS =====\n 'event PublicKeyRegistered(address indexed user, bytes publicKey)',\n 'event PublicKeyUpdated(address indexed user, bytes publicKey)',\n 'event KeyAccessGranted(uint256 indexed topicId, address indexed user, address indexed granter, uint256 version)',\n 'event KeyAccessRevoked(uint256 indexed topicId, address indexed user)',\n 'event KeyRotated(uint256 indexed topicId, uint256 newVersion)',\n] as const;\n","import { pbkdf2 } from '@noble/hashes/pbkdf2';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/hashes/utils';\nimport {\n PUBLIC_KEY_MATERIAL_PREFIX,\n SALT_PREFIX,\n PBKDF2_ITERATIONS,\n} from '../constants.js';\nimport type { EncryptedPayload, MessageContent } from '../types.js';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\n/**\n * Derive AES-256 key for a public/public_limited topic.\n * Uses PBKDF2 with SHA-256, matching the web frontend exactly.\n */\nexport function derivePublicTopicKey(topicId: number | bigint): Uint8Array {\n const keyMaterial = PUBLIC_KEY_MATERIAL_PREFIX + topicId;\n const salt = encoder.encode(SALT_PREFIX + topicId);\n return pbkdf2(sha256, keyMaterial, salt, { c: PBKDF2_ITERATIONS, dkLen: 32 });\n}\n\n/**\n * Derive AES-256 key from arbitrary passphrase (for private topics with manual passphrase).\n */\nexport function deriveKeyFromPassphrase(passphrase: string, topicId: number | bigint): Uint8Array {\n const salt = encoder.encode(SALT_PREFIX + topicId);\n return pbkdf2(sha256, passphrase, salt, { c: PBKDF2_ITERATIONS, dkLen: 32 });\n}\n\n/**\n * Encrypt a message payload with AES-256-GCM.\n * Output format: `{ e: true, v: 2, iv: base64, ct: base64 }`\n * The ciphertext includes the GCM auth tag (last 16 bytes).\n */\nexport function encrypt(plaintext: string, key: Uint8Array): string {\n const iv = randomBytes(12);\n const aes = gcm(key, iv);\n const ciphertext = aes.encrypt(encoder.encode(plaintext));\n\n const payload: EncryptedPayload = {\n e: true,\n v: 2,\n iv: toBase64(iv),\n ct: toBase64(ciphertext),\n };\n return JSON.stringify(payload);\n}\n\n/**\n * Decrypt a message payload. Handles both v1 and v2 formats.\n * Returns the decrypted string or null on failure.\n */\nexport function decrypt(jsonStr: string, key: Uint8Array): string | null {\n try {\n const data = JSON.parse(jsonStr) as EncryptedPayload;\n if (!data.e) {\n // Not encrypted — return raw for caller to parse\n return jsonStr;\n }\n\n const iv = fromBase64(data.iv);\n const ct = fromBase64(data.ct);\n\n const aes = gcm(key, iv);\n const decrypted = aes.decrypt(ct);\n return decoder.decode(decrypted);\n } catch {\n return null;\n }\n}\n\n/**\n * Encrypt a structured message (text + optional replyTo/mentions).\n */\nexport function encryptMessage(\n text: string,\n key: Uint8Array,\n options?: { replyTo?: string; replyText?: string; replyAuthor?: string; mentions?: string[] }\n): string {\n const content: MessageContent = { text };\n if (options?.replyTo) content.replyTo = options.replyTo;\n if (options?.replyText) content.replyText = options.replyText;\n if (options?.replyAuthor) content.replyAuthor = options.replyAuthor;\n if (options?.mentions) content.mentions = options.mentions;\n return encrypt(JSON.stringify(content), key);\n}\n\n/**\n * Decrypt and parse a message payload into structured content.\n */\nexport function decryptMessage(\n jsonStr: string,\n key: Uint8Array\n): { text: string; replyTo: string | null; replyText: string | null; replyAuthor: string | null; mentions: string[] | null } | null {\n const decrypted = decrypt(jsonStr, key);\n if (!decrypted) return null;\n\n try {\n const content = JSON.parse(decrypted);\n if (typeof content === 'object' && content.text) {\n return {\n text: content.text,\n replyTo: content.replyTo || null,\n replyText: content.replyText || null,\n replyAuthor: content.replyAuthor || null,\n mentions: content.mentions || null,\n };\n }\n // Plain text string was JSON-stringified\n return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };\n } catch {\n // Raw string, not JSON\n return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };\n }\n}\n\n// ===== Base64 helpers (isomorphic) =====\n\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n return btoa(String.fromCharCode(...bytes));\n}\n\nfunction fromBase64(str: string): Uint8Array {\n if (typeof Buffer !== 'undefined') {\n return new Uint8Array(Buffer.from(str, 'base64'));\n }\n return Uint8Array.from(atob(str), (c) => c.charCodeAt(0));\n}\n","// ===== Enums =====\n\nexport enum AccessLevel {\n PUBLIC = 0,\n PUBLIC_LIMITED = 1,\n PRIVATE = 2,\n}\n\nexport enum Permission {\n NONE = 0,\n READ = 1,\n WRITE = 2,\n READ_WRITE = 3,\n ADMIN = 4,\n}\n\nexport enum Role {\n MEMBER = 1,\n SUPPORT_MANAGER = 2,\n TOPIC_MANAGER = 4,\n ADMIN = 8,\n OWNER_DELEGATE = 16,\n}\n\n// ===== Chain types =====\n\nexport interface ChainConfig {\n chainId: number;\n name: string;\n shortName: string;\n rpc: string;\n explorer: string;\n registry: string;\n keyManager: string;\n schemaRegistry: string;\n identityRegistry?: string;\n escrow?: string;\n defaultLookback: number;\n}\n\nexport type ChainName = 'base' | 'avalanche' | 'baseSepolia';\n\n// ===== Contract return types =====\n\nexport interface Application {\n id: bigint;\n name: string;\n description: string;\n frontendUrl: string;\n owner: string;\n createdAt: bigint;\n memberCount: number;\n topicCount: number;\n active: boolean;\n allowPublicTopicCreation: boolean;\n topicCreationFeeToken?: string;\n topicCreationFeeAmount?: bigint;\n}\n\nexport interface Topic {\n id: bigint;\n applicationId: bigint;\n name: string;\n description: string;\n owner: string;\n creator: string;\n createdAt: bigint;\n lastMessageAt: bigint;\n messageCount: bigint;\n accessLevel: number;\n active: boolean;\n}\n\nexport interface Member {\n account: string;\n nickname: string;\n roles: number;\n joinedAt: bigint;\n}\n\nexport interface KeyGrant {\n encryptedKey: Uint8Array;\n granterPublicKey: Uint8Array;\n granter: string;\n keyVersion: bigint;\n grantedAt?: bigint;\n currentVersion?: bigint;\n}\n\n// ===== Message types =====\n\nexport interface MessageContent {\n text: string;\n replyTo?: string;\n replyText?: string;\n replyAuthor?: string;\n mentions?: string[];\n}\n\nexport interface EncryptedPayload {\n e: boolean;\n v: number;\n iv: string;\n ct: string;\n}\n\nexport interface Message {\n topicId: number;\n sender: string;\n text: string;\n replyTo: string | null;\n mentions: string[] | null;\n timestamp: number;\n txHash: string;\n blockNumber: number;\n}\n\nexport interface TopicMessageFee {\n token: string;\n amount: bigint;\n}\n\nexport interface SchemaInfo {\n id: number;\n name: string;\n description: string;\n creator: string;\n createdAt: number;\n versionCount: number;\n active: boolean;\n applicationId: number;\n}\n\nexport interface TopicSchemaBinding {\n schemaId: number;\n version: number;\n body: string;\n}\n\nexport enum DepositStatus {\n Pending = 0,\n Released = 1,\n Refunded = 2,\n}\n\nexport interface EscrowDeposit {\n id: bigint;\n topicId: bigint;\n sender: string;\n recipient: string;\n token: string;\n amount: bigint;\n appOwner: string;\n depositedAt: bigint;\n timeout: bigint;\n status: DepositStatus;\n}\n\nexport interface EscrowConfig {\n enabled: boolean;\n timeout: bigint;\n}\n\nexport interface DepositTimer {\n depositId: bigint;\n expired: boolean;\n remainingSeconds: number;\n deadline: number;\n formattedRemaining: string;\n canClaim: boolean;\n}\n\nexport interface EnrichedDeposit extends EscrowDeposit {\n txHash: string;\n blockNumber: number;\n messageText: string | null;\n hasResponse: boolean;\n remainingSeconds: number;\n formattedRemaining: string;\n expired: boolean;\n formattedAmount: string | null;\n}\n\n// ===== Credibility (V4) =====\n\nexport interface RecipientStats {\n depositsReceived: bigint;\n depositsReleased: bigint;\n depositsRefunded: bigint;\n depositsExpired: bigint;\n}\n\nexport interface WalletCredibility {\n responseRate: number; // 0-100 (percentage, converted from basis points)\n depositsReceived: bigint;\n depositsReleased: bigint;\n depositsRefunded: bigint;\n totalEarned: bigint;\n totalRefunded: bigint;\n formattedEarned: string | null;\n formattedRefunded: string | null;\n}\n\n// ===== Client options =====\n\nexport interface ClawtennaOptions {\n chain?: ChainName;\n chainId?: number;\n rpcUrl?: string;\n privateKey?: string;\n registryAddress?: string;\n keyManagerAddress?: string;\n schemaRegistryAddress?: string;\n escrowAddress?: string;\n}\n\nexport interface ReadOptions {\n limit?: number;\n fromBlock?: number;\n}\n\nexport interface SendOptions {\n replyTo?: string;\n replyText?: string;\n replyAuthor?: string;\n mentions?: string[];\n skipRefundCheck?: boolean;\n}\n\n// ===== Credentials =====\n\nexport interface Credentials {\n version: 2;\n wallet: {\n address: string;\n privateKey: string;\n };\n chains: Record<string, CredentialChain>;\n}\n\nexport interface CredentialChain {\n name: string;\n ecdh: {\n privateKey: string;\n publicKey: string;\n registered: boolean;\n } | null;\n apps: Record<string, CredentialApp>;\n}\n\nexport interface CredentialApp {\n name: string;\n nickname: string;\n agentTokenId: number | null;\n topicKeys: Record<string, string>;\n}\n\n// Legacy v1 format for migration\nexport interface CredentialsV1 {\n wallet: {\n address: string;\n privateKey: string;\n };\n apps: Record<string, {\n name: string;\n nickname: string;\n ecdh: {\n privateKey: string;\n publicKey: string;\n registeredOnChain: boolean;\n topicKeys: Record<string, string>;\n } | null;\n }>;\n}\n","import { AccessLevel, Permission, Role } from './types.js';\n\n// Re-export enums as individual constants for convenience\nexport const ACCESS_PUBLIC = AccessLevel.PUBLIC;\nexport const ACCESS_PUBLIC_LIMITED = AccessLevel.PUBLIC_LIMITED;\nexport const ACCESS_PRIVATE = AccessLevel.PRIVATE;\n\nexport const PERMISSION_NONE = Permission.NONE;\nexport const PERMISSION_READ = Permission.READ;\nexport const PERMISSION_WRITE = Permission.WRITE;\nexport const PERMISSION_READ_WRITE = Permission.READ_WRITE;\nexport const PERMISSION_ADMIN = Permission.ADMIN;\n\nexport const ROLE_MEMBER = Role.MEMBER;\nexport const ROLE_SUPPORT_MANAGER = Role.SUPPORT_MANAGER;\nexport const ROLE_TOPIC_MANAGER = Role.TOPIC_MANAGER;\nexport const ROLE_ADMIN = Role.ADMIN;\nexport const ROLE_OWNER_DELEGATE = Role.OWNER_DELEGATE;\n\n// Encryption constants\nexport const PUBLIC_KEY_MATERIAL_PREFIX = 'antenna-public-topic-';\nexport const SALT_PREFIX = 'antenna-v2-salt-';\nexport const PBKDF2_ITERATIONS = 100_000;\nexport const ECDH_HKDF_SALT = 'antenna-ecdh-v1';\nexport const ECDH_HKDF_INFO = 'topic-key-encryption';\nexport const ECDH_DERIVATION_MESSAGE = (address: string, appId: number) =>\n `Clawntenna ECDH Key Derivation\\n\\nThis signature generates your encryption key.\\nIt never leaves your device.\\n\\nWallet: ${address}\\nApp: ${appId}\\nChain: Base (8453)`;\n","import { secp256k1 } from '@noble/curves/secp256k1';\nimport { hkdf } from '@noble/hashes/hkdf';\nimport { sha256 } from '@noble/hashes/sha256';\nimport { gcm } from '@noble/ciphers/aes';\nimport { randomBytes } from '@noble/hashes/utils';\nimport { ECDH_HKDF_SALT, ECDH_HKDF_INFO, ECDH_DERIVATION_MESSAGE } from '../constants.js';\n\nconst encoder = new TextEncoder();\n\n/**\n * Derive an ECDH keypair deterministically from a wallet signature.\n * This produces the same keypair as the web frontend for the same wallet + app.\n */\nexport async function deriveKeypairFromSignature(\n walletAddress: string,\n signMessage: (message: string) => Promise<string>,\n appId: number = 1\n): Promise<{ privateKey: Uint8Array; publicKey: Uint8Array }> {\n const message = ECDH_DERIVATION_MESSAGE(walletAddress, appId);\n const signature = await signMessage(message);\n\n // Hash the signature string (as UTF-8 bytes) to get private key\n const sigBytes = encoder.encode(signature);\n const hashBuffer = sha256(sigBytes);\n const privateKey = new Uint8Array(hashBuffer);\n\n // Derive compressed public key\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n\n return { privateKey, publicKey };\n}\n\n/**\n * Derive ECDH keypair from a raw private key (e.g. from stored credentials).\n */\nexport function keypairFromPrivateKey(privateKeyHex: string): {\n privateKey: Uint8Array;\n publicKey: Uint8Array;\n} {\n const cleaned = privateKeyHex.startsWith('0x') ? privateKeyHex.slice(2) : privateKeyHex;\n const privateKey = hexToBytes(cleaned);\n const publicKey = secp256k1.getPublicKey(privateKey, true);\n return { privateKey, publicKey };\n}\n\n/**\n * Compute ECDH shared secret (x-coordinate of shared point).\n */\nexport function computeSharedSecret(\n ourPrivateKey: Uint8Array,\n theirPublicKey: Uint8Array\n): Uint8Array {\n const sharedPoint = secp256k1.getSharedSecret(ourPrivateKey, theirPublicKey);\n // Return x-coordinate only (skip the 0x04 prefix byte)\n return sharedPoint.slice(1, 33);\n}\n\n/**\n * Derive AES-256 key from an ECDH shared secret using HKDF.\n * Matches the web frontend: salt='antenna-ecdh-v1', info='topic-key-encryption'.\n */\nexport function deriveAESKeyFromSecret(\n sharedSecret: Uint8Array,\n info: string = ECDH_HKDF_INFO\n): Uint8Array {\n return hkdf(sha256, sharedSecret, encoder.encode(ECDH_HKDF_SALT), info, 32);\n}\n\n/**\n * Encrypt a topic symmetric key for a recipient using ECDH.\n * Returns IV (12 bytes) + ciphertext (includes GCM auth tag).\n */\nexport function encryptTopicKeyForUser(\n topicKey: Uint8Array,\n ourPrivateKey: Uint8Array,\n recipientPublicKey: Uint8Array\n): Uint8Array {\n const shared = computeSharedSecret(ourPrivateKey, recipientPublicKey);\n const aesKey = deriveAESKeyFromSecret(shared);\n const iv = randomBytes(12);\n const aes = gcm(aesKey, iv);\n const ciphertext = aes.encrypt(topicKey);\n\n // Combine: IV + ciphertext\n const result = new Uint8Array(iv.length + ciphertext.length);\n result.set(iv);\n result.set(ciphertext, iv.length);\n return result;\n}\n\n/**\n * Decrypt a topic symmetric key received via ECDH grant.\n * Input format: IV (12 bytes) + ciphertext (includes GCM auth tag).\n */\nexport function decryptTopicKey(\n encryptedKey: Uint8Array,\n ourPrivateKey: Uint8Array,\n granterPublicKey: Uint8Array\n): Uint8Array {\n const shared = computeSharedSecret(ourPrivateKey, granterPublicKey);\n const aesKey = deriveAESKeyFromSecret(shared);\n const iv = encryptedKey.slice(0, 12);\n const ciphertext = encryptedKey.slice(12);\n const aes = gcm(aesKey, iv);\n return aes.decrypt(ciphertext);\n}\n\n// ===== Hex helpers =====\n\nexport function bytesToHex(bytes: Uint8Array): string {\n return '0x' + Array.from(bytes).map((b) => b.toString(16).padStart(2, '0')).join('');\n}\n\nexport function hexToBytes(hex: string): Uint8Array {\n const cleaned = hex.startsWith('0x') ? hex.slice(2) : hex;\n return new Uint8Array(cleaned.match(/.{1,2}/g)!.map((b) => parseInt(b, 16)));\n}\n","/**\n * Pure escrow timer utilities — no ethers.js dependency.\n */\n\nexport const ESCROW_MIN_TIMEOUT = 60;\nexport const ESCROW_MAX_TIMEOUT = 604800;\n\nexport const ESCROW_TIMEOUT_OPTIONS = [\n { value: 300, label: '5 minutes' },\n { value: 3600, label: '1 hour' },\n { value: 21600, label: '6 hours' },\n { value: 86400, label: '1 day' },\n { value: 259200, label: '3 days' },\n { value: 604800, label: '7 days' },\n] as const;\n\nexport const DEPOSIT_STATUS_LABELS = ['Pending', 'Released', 'Refunded'] as const;\n\n/**\n * Format a timeout in seconds into a human-readable string.\n * Examples: 300 → \"5m\", 3600 → \"1h\", 86400 → \"1d\", 5400 → \"1h 30m\"\n */\nexport function formatTimeout(seconds: number): string {\n if (seconds <= 0) return '0s';\n\n const days = Math.floor(seconds / 86400);\n const hours = Math.floor((seconds % 86400) / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n const secs = seconds % 60;\n\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (secs > 0 && days === 0 && hours === 0) parts.push(`${secs}s`);\n\n return parts.join(' ') || '0s';\n}\n\n/**\n * Check whether a deposit has expired (eligible for refund).\n */\nexport function isDepositExpired(depositedAt: bigint, timeout: bigint, nowSeconds?: number): boolean {\n const now = BigInt(nowSeconds ?? Math.floor(Date.now() / 1000));\n return now >= depositedAt + timeout;\n}\n\n/**\n * Seconds remaining until a deposit becomes refundable. Returns 0 if already expired.\n */\nexport function timeUntilRefund(depositedAt: bigint, timeout: bigint, nowSeconds?: number): number {\n const now = BigInt(nowSeconds ?? Math.floor(Date.now() / 1000));\n const deadline = depositedAt + timeout;\n if (now >= deadline) return 0;\n return Number(deadline - now);\n}\n\n/**\n * Get the absolute deadline timestamp (seconds since epoch) when a deposit becomes refundable.\n */\nexport function getDepositDeadline(depositedAt: bigint, timeout: bigint): number {\n return Number(depositedAt + timeout);\n}\n\n/**\n * Validate that a timeout value is within allowed bounds.\n */\nexport function isValidTimeout(seconds: number): boolean {\n return Number.isInteger(seconds) && seconds >= ESCROW_MIN_TIMEOUT && seconds <= ESCROW_MAX_TIMEOUT;\n}\n","/**\n * Classify common RPC errors into human-readable hints.\n * Returns an enhanced message string, or null if the error is unrecognized.\n */\nexport function classifyRpcError(\n err: Error,\n ctx: { method: string; chainName: string }\n): string | null {\n const msg = err.message ?? '';\n\n if (msg.includes('BAD_DATA') || msg.includes('could not decode result data')) {\n return `${ctx.method} failed: contract may not be deployed on ${ctx.chainName}, or the RPC returned an empty response. Check that the correct chain and RPC URL are configured.`;\n }\n\n if (\n msg.includes('NETWORK_ERROR') ||\n msg.includes('ECONNREFUSED') ||\n msg.includes('fetch failed') ||\n msg.includes('getaddrinfo')\n ) {\n return `${ctx.method} failed: network error connecting to ${ctx.chainName} RPC. Check your RPC URL and network connectivity.`;\n }\n\n if (\n msg.includes('429') ||\n msg.includes('rate limit') ||\n msg.includes('too many requests') ||\n msg.includes('exceeded') ||\n msg.includes('throttl')\n ) {\n return `${ctx.method} failed: RPC rate limit hit on ${ctx.chainName}. The request was retried but the limit persists. Try again later or use a different RPC endpoint.`;\n }\n\n return null;\n}\n","export interface RetryOptions {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nexport const DEFAULT_RETRY: RetryOptions = {\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 10_000,\n};\n\nconst RETRYABLE_PATTERNS = [\n '429',\n 'rate limit',\n 'too many requests',\n 'timeout',\n 'econnreset',\n '502',\n '503',\n '504',\n 'server error',\n];\n\nexport function isRetryableError(err: Error): boolean {\n const msg = (err.message ?? '').toLowerCase();\n return RETRYABLE_PATTERNS.some((p) => msg.includes(p));\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: Partial<RetryOptions>,\n): Promise<T> {\n const opts = { ...DEFAULT_RETRY, ...options };\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n\n if (attempt === opts.maxRetries) break;\n if (!(err instanceof Error) || !isRetryableError(err)) break;\n\n const delay = Math.min(opts.baseDelayMs * 2 ** attempt, opts.maxDelayMs);\n const jitter = Math.random() * 0.25 * delay;\n await new Promise((r) => setTimeout(r, delay + jitter));\n }\n }\n\n throw lastError;\n}\n","import type { Message } from './types.js';\n\n/**\n * Convert a Message to a plain object safe for JSON.stringify().\n * All fields are already JSON-safe (number, string, string[], null),\n * so this is primarily a convenience function for consumers.\n */\nexport function serializeMessage(msg: Message): Record<string, unknown> {\n return {\n topicId: msg.topicId,\n sender: msg.sender,\n text: msg.text,\n replyTo: msg.replyTo,\n mentions: msg.mentions,\n timestamp: msg.timestamp,\n txHash: msg.txHash,\n blockNumber: msg.blockNumber,\n };\n}\n"],"mappings":"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","names":["AccessLevel","Permission","Role","DepositStatus","sha256","gcm","randomBytes","encoder","sha256","randomBytes","gcm","randomBytes","randomBytes"]}