The GasGuard Audit Logging System provides comprehensive traceability and accountability for all critical actions in the platform. It captures and stores immutable logs of API requests, key management events, and gas transactions, enabling full visibility and compliance readiness.
- Event Tracking: Captures API requests, API key lifecycle events, and gas transactions
- Immutable Storage: Append-only logs with integrity verification via cryptographic hashing
- Query & Filtering: Advanced filtering by event type, user, date range, and more
- Export Capabilities: Export logs as CSV or JSON for compliance reporting
- Retention Policies: Configurable log retention with automatic cleanup
- Access Control: Admin-only access to audit logs (production implementations)
- Multi-chain Support: Track events across multiple blockchain networks
- Performance Optimized: Strategic indexing for efficient querying
Logged for every API endpoint access.
Fields:
apiKey: The API key used for the requestendpoint: The API endpoint accessed (e.g.,/scanner/scan)httpMethod: HTTP method (GET, POST, PUT, DELETE, etc.)responseStatus: HTTP response codeipAddress: Client IP addressresponseDuration: Request processing time in millisecondsoutcome: Success/Failure/WarningerrorMessage: Error message if failed
Example:
{
"eventType": "APIRequest",
"timestamp": "2024-02-23T10:30:00Z",
"apiKey": "sk_prod_abc123def456",
"endpoint": "/scanner/scan",
"httpMethod": "POST",
"responseStatus": 200,
"ipAddress": "192.168.1.100",
"responseDuration": 250,
"outcome": "success"
}Logged when a new API key is created for a merchant.
Fields in details:
keyId: Unique identifier of the new keykeyName: Friendly name of the keyrole: Permission level (user, admin, read-only)expiresAt: Expiration date if applicable
Example:
{
"eventType": "KeyCreated",
"timestamp": "2024-02-23T09:15:00Z",
"user": "merchant_456",
"outcome": "success",
"details": {
"keyId": "key_1708592100",
"keyName": "Production API Key",
"role": "user",
"expiresAt": "2025-02-23"
}
}Logged when an API key is rotated (creating a new key and deprecating the old).
Fields in details:
oldKeyId: ID of the previous keynewKeyId: ID of the new keyreason: Reason for rotation (scheduled, security, manual)
Example:
{
"eventType": "KeyRotated",
"timestamp": "2024-02-23T08:00:00Z",
"user": "merchant_456",
"outcome": "success",
"details": {
"oldKeyId": "key_1708592100",
"newKeyId": "key_1708678500",
"reason": "scheduled rotation"
}
}Logged when an API key is revoked/disabled.
Fields in details:
revokedKeyId: ID of the revoked keyreason: Reason for revocation (compromised, obsolete, user-initiated)
Example:
{
"eventType": "KeyRevoked",
"timestamp": "2024-02-22T15:45:00Z",
"user": "merchant_456",
"outcome": "success",
"details": {
"revokedKeyId": "key_1708592100",
"reason": "suspected compromise"
}
}Logged for every gas-related transaction submitted or processed.
Fields in details:
transactionHash: Blockchain transaction hashgasUsed: Amount of gas consumedgasPrice: Gas price in the respective denominationsenderAddress: Address that initiated the transactionmethod: Contract method called (if applicable)value: Transaction value (if applicable)
Example:
{
"eventType": "GasTransaction",
"timestamp": "2024-02-23T11:20:00Z",
"user": "merchant_123",
"chainId": 1,
"outcome": "success",
"details": {
"transactionHash": "0x1234567890abcdef",
"gasUsed": 21000,
"gasPrice": "45 gwei",
"senderAddress": "0xabcdefabcdefabcdef",
"method": "transfer",
"value": "1.5"
}
}Logged when gas is submitted for processing (e.g., via subsidy program).
Fields in details:
submissionId: Unique submission identifieramount: Amount of gas submittedsubsidyProgram: Which subsidy program (if applicable)status: Submission status
Logged when system configuration is updated by an administrator.
Fields in details:
configType: Type of configuration being updated (e.g., "rate-limits", "alert-thresholds", "rpc-providers")changes: Object containing the configuration changes madetarget: Target of the configuration change (e.g., chain ID, "global", specific component)
Example:
{
"eventType": "ConfigUpdate",
"timestamp": "2024-02-23T14:30:00Z",
"user": "admin_user_123",
"outcome": "success",
"details": {
"configType": "alert-thresholds",
"changes": {
"gasSpikeThreshold": 150,
"volatilityThreshold": 25
},
"target": "chain-1"
}
}Logged when user roles are modified by an administrator.
Fields in details:
targetUser: User whose role is being changedaction: Type of role change ("grant", "revoke", "update")role: The role being granted/revoked/updatedpreviousRole: Previous role (for updates)
Example:
{
"eventType": "RoleChange",
"timestamp": "2024-02-23T15:45:00Z",
"user": "admin_user_123",
"outcome": "success",
"details": {
"targetUser": "user_456",
"action": "grant",
"role": "admin",
"previousRole": "operator"
}
}Logged for treasury-related operations performed by administrators.
Fields in details:
operation: Type of treasury operation (e.g., "withdraw", "deposit", "transfer")amount: Amount involved in the operationasset: Asset type (e.g., "ETH", "USDC", "gas-tokens")recipient: Recipient address or identifier- Additional operation-specific details
Example:
{
"eventType": "TreasuryOperation",
"timestamp": "2024-02-23T16:20:00Z",
"user": "admin_user_123",
"outcome": "success",
"details": {
"operation": "withdraw",
"amount": "1000",
"asset": "ETH",
"recipient": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e"
}
}Logged for general system administration actions.
Fields in details:
action: Administrative action performed (e.g., "force-refresh", "system-restart", "maintenance-mode")target: Target of the administrative action- Additional action-specific details
Example:
{
"eventType": "SystemAdmin",
"timestamp": "2024-02-23T17:00:00Z",
"user": "admin_user_123",
"outcome": "success",
"details": {
"action": "force-refresh",
"target": "gas-price-data",
"reason": "Manual data refresh requested"
}
}| Field | Type | Description | Indexed |
|---|---|---|---|
| id | UUID | Primary key, auto-generated | Yes |
| eventType | Enum | Type of event | Yes |
| timestamp | DateTime | When event occurred | Yes |
| user | String(255) | User/merchant ID | Yes |
| apiKey | String(255) | API key used | No |
| chainId | Integer | Blockchain chain ID | Yes |
| details | JSONB | Event-specific data | No |
| outcome | Enum | success/failure/warning | No |
| endpoint | String(255) | API endpoint (for requests) | No |
| httpMethod | String(10) | HTTP method | No |
| responseStatus | Integer | HTTP response code | No |
| ipAddress | String(255) | Client IP address | No |
| errorMessage | Text | Error details if failure | No |
| responseDuration | BigInt | Duration in milliseconds | No |
| integrity | String(64) | SHA256 hash for integrity | No |
| createdAt | DateTime | Record creation time | No |
| Field | Type | Description | Indexed |
|---|---|---|---|
| id | UUID | Primary key | Yes |
| merchantId | String(100) | Associated merchant | Yes |
| name | String(255) | Friendly name | No |
| keyHash | String(255) | SHA256 hash of key | Yes |
| status | Enum | active/rotated/revoked/expired | Yes |
| lastUsedAt | DateTime | Last usage time | No |
| requestCount | Integer | Total requests with key | No |
| expiresAt | DateTime | Expiration date | No |
| description | Text | Key description | No |
| role | String(50) | Permission role | No |
| metadata | JSONB | Additional metadata | No |
| rotatedFromId | UUID | Previous key ID | No |
| createdAt | DateTime | Creation time | Yes |
| updatedAt | DateTime | Last update time | No |
Retrieve audit logs with filtering and pagination.
Query Parameters:
eventType(string): Filter by event type (APIRequest, KeyCreated, KeyRotated, KeyRevoked, GasTransaction, GasSubmission, ConfigUpdate, RoleChange, TreasuryOperation, SystemAdmin)user(string): Filter by user/merchant IDapiKey(string): Filter by API keychainId(integer): Filter by blockchain chain IDoutcome(string): Filter by outcome (success, failure, warning)from(ISO datetime): Start date for range filterto(ISO datetime): End date for range filterlimit(integer): Results per page, default 50offset(integer): Pagination offset, default 0sortBy(string): Sort field, default "timestamp"sortOrder(string): ASC or DESC, default DESC
Example Request:
GET /audit/logs?eventType=APIRequest&user=merchant_123&from=2024-02-01&to=2024-02-28&limit=50&offset=0Example Response:
{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "APIRequest",
"timestamp": "2024-02-23T10:30:00Z",
"user": "merchant_123",
"apiKey": "sk_prod_abc123",
"outcome": "success",
"endpoint": "/scanner/scan",
"httpMethod": "POST",
"responseStatus": 200,
"ipAddress": "192.168.1.100",
"responseDuration": 250,
"createdAt": "2024-02-23T10:30:00Z"
}
],
"total": 1543,
"limit": 50,
"offset": 0
}Retrieve a specific audit log by ID.
Example Request:
GET /audit/logs/550e8400-e29b-41d4-a716-446655440000Example Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"eventType": "APIRequest",
"timestamp": "2024-02-23T10:30:00Z",
"user": "merchant_123",
"apiKey": "sk_prod_abc123",
"details": {},
"outcome": "success",
"endpoint": "/scanner/scan",
"httpMethod": "POST",
"responseStatus": 200,
"ipAddress": "192.168.1.100",
"responseDuration": 250,
"createdAt": "2024-02-23T10:30:00Z"
}Retrieve logs filtered by event type.
Example Request:
GET /audit/logs/type/KeyCreated?limit=100Example Response:
[
{
"id": "...",
"eventType": "KeyCreated",
"timestamp": "2024-02-23T09:15:00Z",
"user": "merchant_456",
"outcome": "success",
"details": {
"keyId": "key_1708592100",
"keyName": "Production API Key",
"role": "user"
},
"createdAt": "2024-02-23T09:15:00Z"
}
]Retrieve logs for a specific user/merchant.
Example Request:
GET /audit/logs/user/merchant_123?limit=100Export audit logs in CSV or JSON format.
Request Body:
{
"format": "csv",
"eventType": "APIRequest",
"user": "merchant_123",
"from": "2024-02-01T00:00:00Z",
"to": "2024-02-28T23:59:59Z"
}Response: File download with appropriate Content-Type header
Formats:
- CSV:
Content-Type: text/csv - JSON:
Content-Type: application/json
Retrieve high-level audit statistics.
Example Response:
{
"message": "Audit statistics endpoint",
"totalEvents": 15432,
"eventsByType": {
"APIRequest": 12000,
"KeyCreated": 150,
"GasTransaction": 3000,
"KeyRotated": 200,
"KeyRevoked": 50,
"GasSubmission": 32,
"ConfigUpdate": 45,
"RoleChange": 12,
"TreasuryOperation": 8,
"SystemAdmin": 23
}
}All audit endpoints require authentication and authorization:
- Local Development: Endpoints are accessible without guards (configure in production)
- Production: Add
@UseGuards(AdminGuard)to restrict access to admin users only - Implementation: Use
AdminGuardor similar auth middleware
Example implementation for production:
@Controller('audit')
@UseGuards(AdminGuard)
export class AuditController {
// Protected endpoints
}import { AuditLogService } from './audit/services';
export class YourService {
constructor(private auditLogService: AuditLogService) {}
async someAction() {
// Emit API request (automatically done by interceptor)
this.auditLogService.emitApiRequest(
'api_key_abc',
'/endpoint',
'POST',
200,
'192.168.1.1',
150,
);
// Emit API key creation event
this.auditLogService.emitApiKeyEvent(
EventType.API_KEY_CREATED,
'merchant_123',
{ keyId: 'key_1', name: 'Production Key', role: 'user' }
);
// Emit gas transaction event
this.auditLogService.emitGasTransaction(
'merchant_123',
1, // chainId
'0x1234567890abcdef', // txHash
21000, // gasUsed
'45 gwei', // gasPrice
'0xabcdefabcdefabcdef', // senderAddress
{ method: 'transfer', value: '1.5' } // additional details
);
}
}Each log entry includes an integrity field containing a SHA256 hash of the event data to prevent unauthorized modifications.
integrity = SHA256(JSON.stringify(auditLogDto))- Logs are never updated or deleted by normal operations
- Only retention policies can remove old logs
- Schema uses immutable storage patterns
- Timestamp fields are set at creation time
- Restrict audit log access to admin users only
- Log all access to audit logs themselves
- Use HTTPS/TLS for all API communication
- Implement rate limiting on audit endpoints
- Store API key hashes, never plaintext
Configure retention via environment variables or code:
// Cleanup logs older than 90 days
await auditLogService.retentionCleanup(90);- API Requests: 30-90 days
- Key Lifecycle Events: 1-2 years
- Gas Transactions: 6-12 months (for compliance)
- Failed Events: 1-2 years (for troubleshooting)
Set up scheduled jobs:
@Cron('0 0 * * *') // Daily at midnight
async cleanupOldLogs() {
const retentionDays = parseInt(process.env.AUDIT_LOG_RETENTION_DAYS || '90');
await this.auditLogService.retentionCleanup(retentionDays);
}The schema includes composite and single-column indexes:
-- Fast queries by event type and user
idx_audit_composite ON (eventType, user, timestamp)
-- Fast range queries
idx_audit_timestamp ON (timestamp)
-- Identity queries
idx_audit_event_type ON (eventType)
idx_audit_user ON (user)
idx_audit_chain_id ON (chainId)// Fast - uses composite index
auditLogService.queryLogs({
eventType: EventType.API_REQUEST,
user: 'merchant_123',
from: '2024-02-01',
to: '2024-02-28'
});
// Fast - uses timestamp index for range
auditLogService.queryLogs({
from: '2024-02-01',
to: '2024-02-28'
});
// Medium - filters by single column
auditLogService.getLogsByUser('merchant_123');1. User Activity Report
const logs = await auditLogService.queryLogs({
user: 'merchant_123',
from: '2024-01-01',
to: '2024-01-31',
limit: 10000
});
// Export as CSV
const csv = await auditLogService.exportLogs('csv', { user: 'merchant_123' });2. API Key Lifecycle Report
const keyEvents = await auditLogService.queryLogs({
eventType: EventType.API_KEY_CREATED,
from: '2024-01-01',
to: '2024-12-31',
limit: 10000
});3. Gas Transaction Report
const gasLogs = await auditLogService.queryLogs({
eventType: EventType.GAS_TRANSACTION,
chainId: 1,
from: '2024-02-01',
to: '2024-02-28',
limit: 10000
});4. Failed Requests Report
const failures = await auditLogService.queryLogs({
eventType: EventType.API_REQUEST,
outcome: OutcomeStatus.FAILURE,
from: '2024-02-01',
to: '2024-02-28',
limit: 10000
});Run audit system tests:
# Unit tests
npm test -- audit-log.service.spec.ts
npm test -- audit-event-emitter.spec.ts
# Integration/E2E tests
npm run test:e2e -- audit.controller.e2e.spec.ts
# Coverage report
npm run test:cov -- src/auditRun migrations to create audit tables:
npm run migration:run- Ensure PostgreSQL is running
- Run database migrations
- Restart API service
- Verify with
GET /audit/logs(should return empty data array)
- Check if
AuditModuleis imported inAppModule - Verify
AuditInterceptoris registered inmain.ts - Check database connection in logs
- Ensure PostgreSQL is running and accessible
- Monitor database query times
- Verify indexes are created:
SELECT * FROM pg_indexes WHERE tablename = 'audit_logs';
- Consider archiving old logs to separate table
- Implement pagination with appropriate limits
- Verify CSV parsing library is installed
- Check file permissions
- Monitor disk space
- Reduce export size if failing
- Elasticsearch integration for large-scale queries
- Real-time log streaming via WebSockets
- Advanced analytics dashboard
- Automated compliance report generation
- Log encryption at rest
- Distributed tracing integration
- Machine learning for anomaly detection
- Audit log digitally signed exports