Initial project setup: Add contracts, API definitions, tests, and documentation

- Add Foundry project configuration (foundry.toml, foundry.lock)
- Add Solidity contracts (TokenFactory138, BridgeVault138, ComplianceRegistry, etc.)
- Add API definitions (OpenAPI, GraphQL, gRPC, AsyncAPI)
- Add comprehensive test suite (unit, integration, fuzz, invariants)
- Add API services (REST, GraphQL, orchestrator, packet service)
- Add documentation (ISO20022 mapping, runbooks, adapter guides)
- Add development tools (RBC tool, Swagger UI, mock server)
- Update OpenZeppelin submodules to v5.0.0
This commit is contained in:
defiQUG
2025-12-12 10:59:41 -08:00
parent 26b5aaf932
commit 651ff4f7eb
281 changed files with 24813 additions and 2 deletions

View File

@@ -0,0 +1,29 @@
/**
* Webhook Service
* Converts event bus topics into HTTPS callbacks with retry logic
*/
import express from 'express';
import { webhookRouter } from './routes/webhooks';
import { eventBusClient } from '@emoney/events';
import { webhookDeliveryService } from './services/delivery';
const app = express();
const PORT = process.env.PORT || 3001;
app.use(express.json());
// Webhook management API
app.use('/v1/webhooks', webhookRouter);
// Subscribe to event bus and deliver webhooks
eventBusClient.on('published', async ({ topic, event }) => {
await webhookDeliveryService.deliverToSubscribers(topic, event);
});
app.listen(PORT, () => {
console.log(`Webhook service listening on port ${PORT}`);
});
export default app;

View File

@@ -0,0 +1,70 @@
/**
* Webhook management routes
*/
import { Router, Request, Response } from 'express';
import { webhookService } from '../services/webhook-service';
export const webhookRouter = Router();
// Create webhook
webhookRouter.post('/', async (req: Request, res: Response) => {
try {
const webhook = await webhookService.createWebhook(req.body);
res.status(201).json(webhook);
} catch (error: any) {
res.status(400).json({ error: error.message });
}
});
// Update webhook
webhookRouter.patch('/:id', async (req: Request, res: Response) => {
try {
const webhook = await webhookService.updateWebhook(req.params.id, req.body);
res.json(webhook);
} catch (error: any) {
res.status(404).json({ error: error.message });
}
});
// Test webhook
webhookRouter.post('/:id/test', async (req: Request, res: Response) => {
try {
await webhookService.testWebhook(req.params.id);
res.json({ success: true });
} catch (error: any) {
res.status(404).json({ error: error.message });
}
});
// Replay webhooks
webhookRouter.post('/:id/replay', async (req: Request, res: Response) => {
try {
const { since } = req.query;
const count = await webhookService.replayWebhooks(req.params.id, since as string);
res.json({ replayed: count });
} catch (error: any) {
res.status(404).json({ error: error.message });
}
});
// Get webhook
webhookRouter.get('/:id', async (req: Request, res: Response) => {
try {
const webhook = await webhookService.getWebhook(req.params.id);
res.json(webhook);
} catch (error: any) {
res.status(404).json({ error: error.message });
}
});
// List webhooks
webhookRouter.get('/', async (req: Request, res: Response) => {
try {
const webhooks = await webhookService.listWebhooks();
res.json({ items: webhooks });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});

View File

@@ -0,0 +1,77 @@
/**
* Webhook delivery service with retry logic and DLQ
*/
import axios from 'axios';
import crypto from 'crypto';
export interface DeliveryAttempt {
webhookId: string;
url: string;
event: any;
attempt: number;
status: 'pending' | 'success' | 'failed';
error?: string;
timestamp: string;
}
export const webhookDeliveryService = {
async deliverToSubscribers(topic: string, event: any): Promise<void> {
// TODO: Get all webhooks subscribed to this topic
// TODO: For each webhook, deliver with retry logic
},
async deliver(webhookId: string, url: string, event: any, secret?: string): Promise<void> {
const payload = JSON.stringify(event);
const signature = secret ? this.signPayload(payload, secret) : undefined;
const headers: any = {
'Content-Type': 'application/json',
'User-Agent': 'eMoney-Webhook/1.0',
};
if (signature) {
headers['X-Webhook-Signature'] = signature;
}
try {
await axios.post(url, payload, {
headers,
timeout: 10000,
});
} catch (error: any) {
// TODO: Retry with exponential backoff
// TODO: Move to DLQ after max retries
throw error;
}
},
signPayload(payload: string, secret: string): string {
return crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
},
async retryWithBackoff(
webhookId: string,
url: string,
event: any,
maxRetries: number = 3
): Promise<void> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await this.deliver(webhookId, url, event);
return;
} catch (error) {
if (attempt === maxRetries) {
// TODO: Move to dead letter queue
throw error;
}
// Exponential backoff: 1s, 2s, 4s
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1000));
}
}
},
};

View File

@@ -0,0 +1,45 @@
/**
* Webhook service - manages webhook registrations
*/
export interface Webhook {
id: string;
url: string;
events: string[];
secret?: string;
enabled: boolean;
createdAt: string;
}
export const webhookService = {
async createWebhook(data: Partial<Webhook>): Promise<Webhook> {
// TODO: Store webhook in database
throw new Error('Not implemented');
},
async updateWebhook(id: string, data: Partial<Webhook>): Promise<Webhook> {
// TODO: Update webhook in database
throw new Error('Not implemented');
},
async getWebhook(id: string): Promise<Webhook> {
// TODO: Retrieve webhook from database
throw new Error('Not implemented');
},
async listWebhooks(): Promise<Webhook[]> {
// TODO: List all webhooks
throw new Error('Not implemented');
},
async testWebhook(id: string): Promise<void> {
// TODO: Send test event to webhook
throw new Error('Not implemented');
},
async replayWebhooks(id: string, since?: string): Promise<number> {
// TODO: Replay events since timestamp
throw new Error('Not implemented');
},
};