@veridex/agentic-payments 0.1.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/MIGRATION.md +307 -0
  3. package/README.md +395 -0
  4. package/dist/index.d.mts +2327 -0
  5. package/dist/index.d.ts +2327 -0
  6. package/dist/index.js +5815 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.mjs +5759 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/examples/basic-agent.ts +126 -0
  11. package/examples/mcp-claude.ts +75 -0
  12. package/examples/ucp-checkout.ts +92 -0
  13. package/examples/x402-integration.ts +75 -0
  14. package/package.json +36 -0
  15. package/src/AgentWallet.ts +432 -0
  16. package/src/chains/AptosChainClient.ts +29 -0
  17. package/src/chains/ChainClient.ts +73 -0
  18. package/src/chains/ChainClientFactory.ts +113 -0
  19. package/src/chains/EVMChainClient.ts +39 -0
  20. package/src/chains/SolanaChainClient.ts +37 -0
  21. package/src/chains/StarknetChainClient.ts +36 -0
  22. package/src/chains/SuiChainClient.ts +28 -0
  23. package/src/index.ts +83 -0
  24. package/src/mcp/MCPServer.ts +73 -0
  25. package/src/mcp/schemas.ts +60 -0
  26. package/src/monitoring/AlertManager.ts +258 -0
  27. package/src/monitoring/AuditLogger.ts +86 -0
  28. package/src/monitoring/BalanceCache.ts +44 -0
  29. package/src/monitoring/ComplianceExporter.ts +52 -0
  30. package/src/oracle/PythFeeds.ts +60 -0
  31. package/src/oracle/PythOracle.ts +121 -0
  32. package/src/performance/ConnectionPool.ts +217 -0
  33. package/src/performance/NonceManager.ts +91 -0
  34. package/src/performance/ParallelRouteFinder.ts +438 -0
  35. package/src/performance/TransactionPoller.ts +201 -0
  36. package/src/performance/TransactionQueue.ts +565 -0
  37. package/src/performance/index.ts +46 -0
  38. package/src/react/hooks.ts +298 -0
  39. package/src/routing/BridgeOrchestrator.ts +18 -0
  40. package/src/routing/CrossChainRouter.ts +501 -0
  41. package/src/routing/DEXAggregator.ts +448 -0
  42. package/src/routing/FeeEstimator.ts +43 -0
  43. package/src/session/SessionKeyManager.ts +312 -0
  44. package/src/session/SessionStorage.ts +80 -0
  45. package/src/session/SpendingTracker.ts +71 -0
  46. package/src/types/agent.ts +105 -0
  47. package/src/types/errors.ts +115 -0
  48. package/src/types/mcp.ts +22 -0
  49. package/src/types/ucp.ts +47 -0
  50. package/src/types/x402.ts +170 -0
  51. package/src/ucp/CapabilityNegotiator.ts +44 -0
  52. package/src/ucp/CredentialProvider.ts +73 -0
  53. package/src/ucp/PaymentTokenizer.ts +169 -0
  54. package/src/ucp/TransportAdapter.ts +18 -0
  55. package/src/ucp/UCPClient.ts +143 -0
  56. package/src/x402/NonceManager.ts +26 -0
  57. package/src/x402/PaymentParser.ts +225 -0
  58. package/src/x402/PaymentSigner.ts +305 -0
  59. package/src/x402/X402Client.ts +364 -0
  60. package/src/x402/adapters/CronosFacilitatorAdapter.ts +109 -0
  61. package/tests/alerts.test.ts +208 -0
  62. package/tests/chains.test.ts +242 -0
  63. package/tests/integration.test.ts +315 -0
  64. package/tests/monitoring.test.ts +435 -0
  65. package/tests/performance.test.ts +303 -0
  66. package/tests/property.test.ts +186 -0
  67. package/tests/react-hooks.test.ts +262 -0
  68. package/tests/session.test.ts +376 -0
  69. package/tests/ucp.test.ts +253 -0
  70. package/tests/x402.test.ts +385 -0
  71. package/tsconfig.json +26 -0
  72. package/tsup.config.ts +10 -0
  73. package/vitest.config.ts +16 -0
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module SolanaChainClient
4
+ * @description
5
+ * Agent adapter for the Solana blockchain.
6
+ *
7
+ * This class extends the core `SolanaClient` to enable agentic operations on Solana.
8
+ *
9
+ * Key Features:
10
+ * - Manages Solana specific transaction instructions.
11
+ * - Handles SPL Token transfers.
12
+ * - Integrates with Wormhole for cross-chain messages.
13
+ */
14
+ import { SolanaClient as CoreSolanaClient, SolanaClientConfig as CoreSolanaClientConfig } from '@veridex/sdk/chains/solana';
15
+ import { BaseAgentChainClient } from './ChainClient';
16
+
17
+ /**
18
+ * Agent-specific Solana chain client.
19
+ * Extends the core Solana client with agent-centric features.
20
+ */
21
+ export class SolanaChainClient extends BaseAgentChainClient {
22
+ private solanaCore: CoreSolanaClient;
23
+
24
+ constructor(config: CoreSolanaClientConfig) {
25
+ const core = new CoreSolanaClient(config);
26
+ super(core);
27
+ this.solanaCore = core;
28
+ }
29
+
30
+
31
+ /**
32
+ * Helper to get the underlying connection
33
+ */
34
+ getConnection() {
35
+ return this.solanaCore.getConnection();
36
+ }
37
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module StarknetChainClient
4
+ * @description
5
+ * Agent adapter for the Starknet Validity Rollup.
6
+ *
7
+ * This class handles the specific requirements of Starknet's Account Abstraction model (SNIP-12).
8
+ * It ensures that agent signatures generated for x402 payments are compatible with
9
+ * Starknet's native account contracts.
10
+ *
11
+ * Key Features:
12
+ * - Generates SNIP-12 typed data signatures.
13
+ * - Manages nonce abstraction for Starknet accounts.
14
+ * - Interfaces with Starknet RPC providers.
15
+ */
16
+ import { StarknetClient as CoreStarknetClient, StarknetClientConfig as CoreStarknetClientConfig } from '@veridex/sdk/chains/starknet';
17
+ import { BaseAgentChainClient } from './ChainClient';
18
+ import { RpcProvider } from 'starknet';
19
+
20
+ /**
21
+ * Agent-specific Starknet chain client.
22
+ */
23
+ export class StarknetChainClient extends BaseAgentChainClient {
24
+ private starknetCore: CoreStarknetClient;
25
+
26
+ constructor(config: CoreStarknetClientConfig) {
27
+ const core = new CoreStarknetClient(config);
28
+ super(core);
29
+ this.starknetCore = core;
30
+ }
31
+
32
+
33
+ getClient(): RpcProvider {
34
+ return this.starknetCore.getProvider();
35
+ }
36
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module SuiChainClient
4
+ * @description
5
+ * Agent adapter for the Sui blockchain (Move VM).
6
+ *
7
+ * Extends the core SDK to support agent operations on Sui.
8
+ */
9
+ import { SuiClient as CoreSuiClient, SuiClientConfig as CoreSuiClientConfig } from '@veridex/sdk/chains/sui';
10
+ import { BaseAgentChainClient } from './ChainClient';
11
+
12
+ /**
13
+ * Agent-specific Sui chain client.
14
+ */
15
+ export class SuiChainClient extends BaseAgentChainClient {
16
+ private suiCore: CoreSuiClient;
17
+
18
+ constructor(config: CoreSuiClientConfig) {
19
+ const core = new CoreSuiClient(config);
20
+ super(core);
21
+ this.suiCore = core;
22
+ }
23
+
24
+
25
+ getClient() {
26
+ return this.suiCore.getClient();
27
+ }
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module AgentSDK
4
+ * @description
5
+ * The main entry point for the Veridex Agent SDK (@veridex/agentic-payments).
6
+ *
7
+ * This package provides a high-level, autonomous payment layer for AI agents, built on top of the
8
+ * core Veridex SDK. It enables agents to manage spending limits, negotiate payments via x402,
9
+ * and issue Universal Commerce Protocol (UCP) credentials.
10
+ *
11
+ * Exports:
12
+ * - **createAgentWallet**: Factory function to initialize the agent.
13
+ * - **AgentWallet**: The main class for agent operations.
14
+ * - **Types**: Comprehensive type definitions for sessions, payments, and protocols.
15
+ */
16
+ import { AgentWallet } from './AgentWallet';
17
+ import { AgentWalletConfig } from './types/agent';
18
+
19
+ export async function createAgentWallet(config: AgentWalletConfig): Promise<AgentWallet> {
20
+ const wallet = new AgentWallet(config);
21
+ await wallet.init();
22
+ return wallet;
23
+ }
24
+
25
+ export * from './AgentWallet';
26
+ export * from './types/agent';
27
+ export * from './types/x402';
28
+ export * from './types/ucp';
29
+ export * from './types/mcp';
30
+ export * from './types/errors';
31
+
32
+ export * from './session/SessionKeyManager';
33
+ export * from './session/SpendingTracker';
34
+ export * from './session/SessionStorage';
35
+
36
+ export * from './x402/X402Client';
37
+ export * from './x402/PaymentParser';
38
+ export * from './x402/PaymentSigner';
39
+ export * from './x402/adapters/CronosFacilitatorAdapter';
40
+
41
+ export * from './ucp/CredentialProvider';
42
+ export * from './ucp/CapabilityNegotiator';
43
+
44
+ export * from './mcp/MCPServer';
45
+
46
+ export * from './routing/CrossChainRouter';
47
+ export * from './routing/FeeEstimator';
48
+ export * from './chains/ChainClient';
49
+ export * from './chains/EVMChainClient';
50
+ export * from './chains/SolanaChainClient';
51
+ export * from './chains/AptosChainClient';
52
+ export * from './chains/SuiChainClient';
53
+ export * from './chains/StarknetChainClient';
54
+ export * from './chains/ChainClientFactory';
55
+ export * from './routing/BridgeOrchestrator';
56
+
57
+ export * from './monitoring/AuditLogger';
58
+ export * from './monitoring/AlertManager';
59
+ export * from './monitoring/ComplianceExporter';
60
+ export * from './monitoring/BalanceCache';
61
+
62
+ export * from './ucp/PaymentTokenizer';
63
+
64
+ export * from './react/hooks';
65
+
66
+ // Performance optimizations
67
+ export * from './performance';
68
+
69
+ // Oracle
70
+ export * from './oracle/PythOracle';
71
+ export * from './oracle/PythFeeds';
72
+
73
+ // DEX
74
+ export * from './routing/DEXAggregator';
75
+
76
+ // Re-export core SDK functions for frontend convenience and to avoid dual-package usage
77
+ export {
78
+ createSDK,
79
+ generateSecp256k1KeyPair,
80
+ computeSessionKeyHash,
81
+ deriveEncryptionKey,
82
+ encrypt
83
+ } from '@veridex/sdk';
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module MCPServer
4
+ * @description
5
+ * Implements the Model Context Protocol (MCP) Server for AI Agent Tools.
6
+ *
7
+ * This server exposes the specific capabilities of the Agent SDK (paying, balance checking, etc.)
8
+ * as standard MCP Tools that can be discovered and executed by LLMs (e.g., Claude, Gemini).
9
+ *
10
+ * Exposed Tools:
11
+ * - `veridex_create_session_key`: Initialize a new constrained wallet.
12
+ * - `veridex_pay`: Execute a cross-chain transaction.
13
+ * - `veridex_check_balance`: Query unified portfolio balance.
14
+ */
15
+ import { AgentWallet } from '../AgentWallet';
16
+ import { MCPTool, MCPToolResult } from '../types/mcp';
17
+ import * as schemas from './schemas';
18
+
19
+ export class MCPServer {
20
+ constructor(private agentWallet: AgentWallet) { }
21
+
22
+ getTools(): MCPTool[] {
23
+ return [
24
+ {
25
+ name: 'veridex_create_session_key',
26
+ description: 'Create a bounded wallet for an AI agent',
27
+ inputSchema: schemas.CREATE_SESSION_SCHEMA,
28
+ handler: (params) => this.agentWallet.createSession(params),
29
+ },
30
+ {
31
+ name: 'veridex_pay',
32
+ description: 'Execute a payment across chains',
33
+ inputSchema: schemas.PAY_SCHEMA,
34
+ handler: (params) => this.agentWallet.pay(params),
35
+ },
36
+ {
37
+ name: 'veridex_check_balance',
38
+ description: 'Query wallet balances across all chains',
39
+ inputSchema: schemas.CHECK_BALANCE_SCHEMA,
40
+ handler: (params) => this.agentWallet.getBalance(params.chain),
41
+ },
42
+ {
43
+ name: 'veridex_revoke_session',
44
+ description: 'Revoke agent wallet access',
45
+ inputSchema: schemas.REVOKE_SESSION_SCHEMA,
46
+ handler: () => this.agentWallet.revokeSession(),
47
+ },
48
+ {
49
+ name: 'veridex_get_payment_history',
50
+ description: 'Retrieve transaction history',
51
+ inputSchema: schemas.GET_HISTORY_SCHEMA,
52
+ handler: (params) => this.agentWallet.getPaymentHistory(params),
53
+ },
54
+ ];
55
+ }
56
+
57
+ async executeTool(toolName: string, params: any): Promise<MCPToolResult> {
58
+ const tool = this.getTools().find(t => t.name === toolName);
59
+ if (!tool) throw new Error(`Tool ${toolName} not found`);
60
+
61
+ try {
62
+ const result = await tool.handler(params);
63
+ return {
64
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
65
+ };
66
+ } catch (error: any) {
67
+ return {
68
+ content: [{ type: 'text', text: `Error: ${error.message}` }],
69
+ isError: true,
70
+ };
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module MCPSchemas
4
+ * @description
5
+ * JSON Schema definitions for MCP Tool inputs.
6
+ *
7
+ * These schemas validate the arguments passed by LLMs when invoking Agent tools
8
+ * (e.g., 'amount' must be a string, 'chainId' must be a known number).
9
+ *
10
+ * Defined Schemas:
11
+ * - `CREATE_SESSION_SCHEMA`: Configuration for new session keys.
12
+ * - `PAY_SCHEMA`: Parameters for cross-chain payments.
13
+ * - `CHECK_BALANCE_SCHEMA`: Arguments for balance queries.
14
+ * - `REVOKE_SESSION_SCHEMA`: Arguments for session revocation.
15
+ */
16
+ export const CREATE_SESSION_SCHEMA = {
17
+ type: 'object',
18
+ properties: {
19
+ dailyLimitUSD: { type: 'number' },
20
+ perTransactionLimitUSD: { type: 'number' },
21
+ expiryHours: { type: 'number' },
22
+ allowedChains: { type: 'array', items: { type: 'number' } }
23
+ },
24
+ required: ['dailyLimitUSD', 'perTransactionLimitUSD']
25
+ };
26
+
27
+ export const PAY_SCHEMA = {
28
+ type: 'object',
29
+ properties: {
30
+ amount: { type: 'string', description: 'Amount in ATOMIC UNITS (wei). E.g. 10 USDC = 10000000 (6 decimals), 1 ETH = 10^18.' },
31
+ token: { type: 'string', description: 'Token symbol (e.g. "usdc", "eth", "native")' },
32
+ recipient: { type: 'string', description: 'Recipient wallet address (0x...)' },
33
+ chain: { type: 'number', description: 'Wormhole Chain ID. Use: 10004=Base Sepolia, 10002=Ethereum Sepolia, 10003=Arbitrum Sepolia, 10005=Optimism Sepolia. Do NOT use native chain IDs like 11155111.' }
34
+ },
35
+ required: ['amount', 'recipient', 'chain']
36
+ };
37
+
38
+ export const CHECK_BALANCE_SCHEMA = {
39
+ type: 'object',
40
+ properties: {
41
+ chain: { type: 'number' }
42
+ }
43
+ };
44
+
45
+ export const REVOKE_SESSION_SCHEMA = {
46
+ type: 'object',
47
+ properties: {
48
+ sessionKeyHash: { type: 'string' }
49
+ },
50
+ required: ['sessionKeyHash']
51
+ };
52
+
53
+ export const GET_HISTORY_SCHEMA = {
54
+ type: 'object',
55
+ properties: {
56
+ limit: { type: 'number' },
57
+ offset: { type: 'number' },
58
+ chain: { type: 'number' }
59
+ }
60
+ };
@@ -0,0 +1,258 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module AlertManager
4
+ * @description
5
+ * Real-time monitoring and alerting system for agent spending.
6
+ *
7
+ * Capabilites:
8
+ * - **Threshold Alerts**: Triggers warnings when spending hits 50%, 80%, 90% of daily limits.
9
+ * - **High Value Approval**: Pauses large transactions (> $1000) for human approval.
10
+ * - **Anomaly Detection**: Uses heuristics to detect unusual spending patterns (frequency/amount spikes).
11
+ * - **Webhooks**: Dispatches critical alerts to external systems (Slack, PagerDuty).
12
+ */
13
+ import { SpendingAlert } from '../types/agent';
14
+ import { PaymentRecord } from './AuditLogger';
15
+
16
+ export interface AlertConfig {
17
+ spendingThresholds: number[]; // e.g., [0.5, 0.8, 0.9, 1.0]
18
+ highValueThresholdUSD: number; // e.g., 1000
19
+ anomalyDetectionEnabled: boolean;
20
+ webhookUrl?: string;
21
+ }
22
+
23
+ export interface HighValueApproval {
24
+ transactionId: string;
25
+ amountUSD: number;
26
+ requestedAt: number;
27
+ expiresAt: number;
28
+ approved: boolean;
29
+ approvedBy?: string;
30
+ }
31
+
32
+ const DEFAULT_CONFIG: AlertConfig = {
33
+ spendingThresholds: [0.5, 0.8, 0.9, 1.0],
34
+ highValueThresholdUSD: 1000,
35
+ anomalyDetectionEnabled: true,
36
+ };
37
+
38
+ export class AlertManager {
39
+ private config: AlertConfig;
40
+ private triggeredAlerts: Set<string> = new Set();
41
+ private callbacks: ((alert: SpendingAlert) => void)[] = [];
42
+ private transactionHistory: PaymentRecord[] = [];
43
+ private pendingApprovals: Map<string, HighValueApproval> = new Map();
44
+ private readonly APPROVAL_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
45
+
46
+ constructor(config: Partial<AlertConfig> = {}) {
47
+ this.config = { ...DEFAULT_CONFIG, ...config };
48
+ }
49
+
50
+ onAlert(callback: (alert: SpendingAlert) => void) {
51
+ this.callbacks.push(callback);
52
+ }
53
+
54
+ /**
55
+ * Check spending against thresholds and trigger alerts.
56
+ */
57
+ checkSpending(
58
+ sessionKeyHash: string,
59
+ dailySpentUSD: number,
60
+ dailyLimitUSD: number
61
+ ) {
62
+ const ratio = dailySpentUSD / dailyLimitUSD;
63
+
64
+ for (const threshold of this.config.spendingThresholds) {
65
+ const alertId = `${sessionKeyHash}_${threshold}`;
66
+
67
+ if (ratio >= threshold && !this.triggeredAlerts.has(alertId)) {
68
+ this.triggeredAlerts.add(alertId);
69
+
70
+ const alert: SpendingAlert = {
71
+ type: threshold >= 0.9 ? 'CRITICAL' : 'WARNING',
72
+ message: `Spending reached ${threshold * 100}% of daily limit.`,
73
+ sessionKeyHash,
74
+ dailySpentUSD,
75
+ dailyLimitUSD,
76
+ timestamp: Date.now()
77
+ };
78
+
79
+ this.notify(alert);
80
+ }
81
+ }
82
+
83
+ // Reset alerts if spending was reset
84
+ if (ratio < 0.1) {
85
+ for (const threshold of this.config.spendingThresholds) {
86
+ this.triggeredAlerts.delete(`${sessionKeyHash}_${threshold}`);
87
+ }
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Check if a transaction is high-value and requires approval.
93
+ */
94
+ isHighValueTransaction(amountUSD: number): boolean {
95
+ return amountUSD >= this.config.highValueThresholdUSD;
96
+ }
97
+
98
+ /**
99
+ * Request approval for a high-value transaction.
100
+ */
101
+ requestApproval(transactionId: string, amountUSD: number): HighValueApproval {
102
+ const approval: HighValueApproval = {
103
+ transactionId,
104
+ amountUSD,
105
+ requestedAt: Date.now(),
106
+ expiresAt: Date.now() + this.APPROVAL_WINDOW_MS,
107
+ approved: false,
108
+ };
109
+
110
+ this.pendingApprovals.set(transactionId, approval);
111
+
112
+ // Notify about pending approval
113
+ const alert: SpendingAlert = {
114
+ type: 'CRITICAL',
115
+ message: `High-value transaction ($${amountUSD}) requires approval within 5 minutes.`,
116
+ sessionKeyHash: transactionId,
117
+ dailySpentUSD: amountUSD,
118
+ dailyLimitUSD: this.config.highValueThresholdUSD,
119
+ timestamp: Date.now(),
120
+ };
121
+ this.notify(alert);
122
+
123
+ return approval;
124
+ }
125
+
126
+ /**
127
+ * Approve a pending high-value transaction.
128
+ */
129
+ approveTransaction(transactionId: string, approverKey: string): boolean {
130
+ const approval = this.pendingApprovals.get(transactionId);
131
+ if (!approval) return false;
132
+
133
+ if (Date.now() > approval.expiresAt) {
134
+ this.pendingApprovals.delete(transactionId);
135
+ return false; // Expired
136
+ }
137
+
138
+ approval.approved = true;
139
+ approval.approvedBy = approverKey;
140
+ return true;
141
+ }
142
+
143
+ /**
144
+ * Check if a transaction has been approved.
145
+ */
146
+ checkApproval(transactionId: string): { approved: boolean; expired: boolean } {
147
+ const approval = this.pendingApprovals.get(transactionId);
148
+ if (!approval) {
149
+ return { approved: false, expired: false };
150
+ }
151
+
152
+ if (Date.now() > approval.expiresAt) {
153
+ this.pendingApprovals.delete(transactionId);
154
+ return { approved: false, expired: true };
155
+ }
156
+
157
+ return { approved: approval.approved, expired: false };
158
+ }
159
+
160
+ /**
161
+ * Detect anomalies in transaction patterns.
162
+ */
163
+ detectAnomaly(record: PaymentRecord): boolean {
164
+ if (!this.config.anomalyDetectionEnabled) return false;
165
+
166
+ this.transactionHistory.push(record);
167
+
168
+ // Keep only last 100 transactions for analysis
169
+ if (this.transactionHistory.length > 100) {
170
+ this.transactionHistory = this.transactionHistory.slice(-100);
171
+ }
172
+
173
+ // Simple anomaly detection: unusual amount or frequency
174
+ const recentTxs = this.transactionHistory.filter(
175
+ tx => tx.timestamp > Date.now() - 60 * 60 * 1000 // Last hour
176
+ );
177
+
178
+ // Check for unusual frequency (more than 10 tx/hour)
179
+ if (recentTxs.length > 10) {
180
+ this.notify({
181
+ type: 'WARNING',
182
+ message: `Unusual transaction frequency detected: ${recentTxs.length} transactions in the last hour.`,
183
+ sessionKeyHash: record.sessionKeyHash ?? 'unknown',
184
+ dailySpentUSD: record.amountUSD ?? 0,
185
+ dailyLimitUSD: 0,
186
+ timestamp: Date.now(),
187
+ });
188
+ return true;
189
+ }
190
+
191
+ // Check for unusual amount (3x average)
192
+ if (recentTxs.length > 3) {
193
+ const avgAmount = recentTxs.reduce((sum, tx) => sum + (tx.amountUSD ?? 0), 0) / recentTxs.length;
194
+ const recordAmount = record.amountUSD ?? 0;
195
+ if (recordAmount > avgAmount * 3) {
196
+ this.notify({
197
+ type: 'WARNING',
198
+ message: `Unusual transaction amount: $${recordAmount} is 3x above average ($${avgAmount.toFixed(2)}).`,
199
+ sessionKeyHash: record.sessionKeyHash ?? 'unknown',
200
+ dailySpentUSD: recordAmount,
201
+ dailyLimitUSD: 0,
202
+ timestamp: Date.now(),
203
+ });
204
+ return true;
205
+ }
206
+ }
207
+
208
+ return false;
209
+ }
210
+
211
+ /**
212
+ * Send webhook notification for alerts.
213
+ */
214
+ private async sendWebhook(alert: SpendingAlert): Promise<boolean> {
215
+ if (!this.config.webhookUrl) return false;
216
+
217
+ try {
218
+ const response = await fetch(this.config.webhookUrl, {
219
+ method: 'POST',
220
+ headers: { 'Content-Type': 'application/json' },
221
+ body: JSON.stringify({
222
+ event: 'spending_alert',
223
+ alert,
224
+ timestamp: new Date().toISOString(),
225
+ }),
226
+ });
227
+ return response.ok;
228
+ } catch (error) {
229
+ console.error('[AlertManager] Webhook delivery failed:', error);
230
+ return false;
231
+ }
232
+ }
233
+
234
+ private notify(alert: SpendingAlert) {
235
+ this.callbacks.forEach(cb => cb(alert));
236
+ console.warn(`[SpendingAlert] ${alert.type}: ${alert.message} (${alert.sessionKeyHash})`);
237
+
238
+ // Send webhook asynchronously
239
+ if (this.config.webhookUrl) {
240
+ this.sendWebhook(alert).catch(() => { });
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Clean up expired pending approvals.
246
+ */
247
+ cleanupExpiredApprovals(): number {
248
+ const now = Date.now();
249
+ let cleaned = 0;
250
+ for (const [id, approval] of this.pendingApprovals.entries()) {
251
+ if (approval.expiresAt < now) {
252
+ this.pendingApprovals.delete(id);
253
+ cleaned++;
254
+ }
255
+ }
256
+ return cleaned;
257
+ }
258
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * @module AuditLogger
4
+ * @description
5
+ * Immutable transaction logging for compliance and auditing.
6
+ *
7
+ * Every payment attempt (successful or failed) is recorded here. In a production environment,
8
+ * this should ideally write to a tamper-evident log or database. Currently, it persists
9
+ * to local storage and memory for the demo.
10
+ *
11
+ * Records:
12
+ * - Timestamp
13
+ * - Amount (USD and Native)
14
+ * - Chain ID
15
+ * - Recipient
16
+ * - Session ID
17
+ */
18
+ import { PaymentReceipt, HistoryOptions } from '../types/agent';
19
+
20
+ export interface PaymentRecord extends PaymentReceipt {
21
+ id: string;
22
+ sessionKeyHash?: string;
23
+ }
24
+
25
+ export class AuditLogger {
26
+ private static readonly STORAGE_KEY = 'veridex_audit_log';
27
+ private inMemoryLogs: PaymentRecord[] = [];
28
+
29
+ async log(entry: PaymentReceipt, sessionKeyHash?: string): Promise<void> {
30
+ const record: PaymentRecord = {
31
+ ...entry,
32
+ id: crypto.randomUUID ? crypto.randomUUID() : `log_${Date.now()}_${Math.random()}`,
33
+ sessionKeyHash
34
+ };
35
+
36
+ this.inMemoryLogs.push(record);
37
+ this.persistLogs();
38
+
39
+ // Original console log
40
+ console.log('AUDIT:', JSON.stringify(record, (key, value) =>
41
+ typeof value === 'bigint' ? value.toString() : value
42
+ ));
43
+ }
44
+
45
+ async getLogs(options: HistoryOptions = {}): Promise<PaymentRecord[]> {
46
+ this.loadLogs();
47
+ let logs = [...this.inMemoryLogs];
48
+
49
+ // Filter by chain
50
+ if (options.chain !== undefined) {
51
+ logs = logs.filter(l => l.chain === options.chain);
52
+ }
53
+
54
+ // Filter by time
55
+ if (options.startTime) {
56
+ logs = logs.filter(l => l.timestamp >= options.startTime!);
57
+ }
58
+ if (options.endTime) {
59
+ logs = logs.filter(l => l.timestamp <= options.endTime!);
60
+ }
61
+
62
+ // Sort desc
63
+ logs.sort((a, b) => b.timestamp - a.timestamp);
64
+
65
+ // Pagination
66
+ const offset = options.offset || 0;
67
+ const limit = options.limit || 50;
68
+
69
+ return logs.slice(offset, offset + limit);
70
+ }
71
+
72
+ private persistLogs() {
73
+ if (typeof localStorage !== 'undefined') {
74
+ localStorage.setItem(AuditLogger.STORAGE_KEY, JSON.stringify(this.inMemoryLogs));
75
+ }
76
+ }
77
+
78
+ private loadLogs() {
79
+ if (typeof localStorage !== 'undefined') {
80
+ const data = localStorage.getItem(AuditLogger.STORAGE_KEY);
81
+ if (data) {
82
+ this.inMemoryLogs = JSON.parse(data);
83
+ }
84
+ }
85
+ }
86
+ }