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,7 @@
node_modules
dist
*.log
.env
.git
.DS_Store

View File

@@ -0,0 +1,28 @@
FROM node:18-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
COPY tsconfig.json ./
# Install pnpm
RUN npm install -g pnpm
# Install dependencies
RUN pnpm install --frozen-lockfile
# Copy source files
COPY src/ ./src/
COPY ../../packages/openapi/v1/openapi.yaml ./packages/openapi/v1/openapi.yaml
COPY static/ ./static/
# Build
RUN pnpm run build
# Expose port
EXPOSE 8080
# Start server
CMD ["pnpm", "start"]

View File

@@ -0,0 +1,33 @@
.PHONY: install build start dev generate-standalone docker-build docker-run help
help:
@echo "Swagger UI Server - Available commands:"
@echo " make install - Install dependencies"
@echo " make build - Build TypeScript"
@echo " make start - Start server"
@echo " make dev - Start in development mode"
@echo " make generate-standalone - Generate standalone HTML"
@echo " make docker-build - Build Docker image"
@echo " make docker-run - Run Docker container"
install:
pnpm install
build:
pnpm run build
start: build
pnpm start
dev:
pnpm run dev
generate-standalone:
pnpm run generate:standalone
docker-build:
docker build -t emoney-swagger-ui .
docker-run:
docker run -p 8080:8080 emoney-swagger-ui

View File

@@ -0,0 +1,126 @@
# Swagger UI Quick Start Guide
## Local Development
### Option 1: Node.js (Recommended)
```bash
cd api/tools/swagger-ui
pnpm install
pnpm run dev
```
Visit: http://localhost:8080/api-docs
### Option 2: Docker
```bash
cd api/tools/swagger-ui
docker-compose up
```
Visit: http://localhost:8080/api-docs
## Features
### Interactive Documentation
- Browse all API endpoints
- View request/response schemas
- See example payloads
- Explore data models
### Try It Out
- Test API calls directly from the browser
- Set authentication tokens
- View real responses
- Debug API interactions
### Authentication Testing
- OAuth2 client credentials flow
- mTLS configuration
- API key testing
- Token persistence
### Export Options
- Download OpenAPI spec as JSON
- Download OpenAPI spec as YAML
- Share documentation links
## API Endpoints
The Swagger UI server provides:
- `GET /api-docs` - Interactive documentation
- `GET /openapi.json` - OpenAPI spec (JSON)
- `GET /openapi.yaml` - OpenAPI spec (YAML)
- `GET /health` - Health check
## Configuration
### Environment Variables
```bash
SWAGGER_PORT=8080 # Server port (default: 8080)
```
### Customization
Edit `src/index.ts` to customize:
- Swagger UI theme
- Default expansion level
- Supported HTTP methods
- OAuth2 redirect URL
## Integration with Main API
To integrate Swagger UI into the main REST API server:
```typescript
// In api/services/rest-api/src/index.ts
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
import { join } from 'path';
const openapiSpec = YAML.load(join(__dirname, '../../packages/openapi/v1/openapi.yaml'));
app.use('/docs', swaggerUi.serve, swaggerUi.setup(openapiSpec));
```
## Production Deployment
### Standalone Server
Deploy as separate service:
- Lightweight Express server
- Serves only documentation
- Can be behind CDN
- No API dependencies
### Embedded in API
Include in main API server:
- Single deployment
- Shared authentication
- Live spec updates
- Integrated experience
## Troubleshooting
### OpenAPI Spec Not Loading
1. Check file path: `../../packages/openapi/v1/openapi.yaml`
2. Verify YAML syntax is valid
3. Check file permissions
### OAuth2 Not Working
1. Verify redirect URL matches configuration
2. Check CORS settings
3. Ensure OAuth2 server is accessible
### Styles Not Loading
1. Check network tab for 404s
2. Verify CDN is accessible
3. Check custom CSS syntax

View File

@@ -0,0 +1,55 @@
# Swagger UI Server
Interactive API documentation server for the eMoney Token Factory API.
## Quick Start
```bash
# Install dependencies
pnpm install
# Start server
pnpm start
# Or in development mode
pnpm run dev
```
The Swagger UI will be available at:
- **Documentation**: http://localhost:8080/api-docs
- **OpenAPI JSON**: http://localhost:8080/openapi.json
- **OpenAPI YAML**: http://localhost:8080/openapi.yaml
## Features
- ✅ Interactive API documentation
- ✅ Try-it-out functionality
- ✅ Request/response examples
- ✅ Authentication testing (OAuth2, mTLS, API Key)
- ✅ Schema exploration
- ✅ Export OpenAPI spec (JSON/YAML)
## Configuration
Set environment variables:
```bash
export SWAGGER_PORT=8080 # Default: 8080
```
## Usage
1. Navigate to http://localhost:8080/api-docs
2. Click "Authorize" to set up authentication
3. Explore endpoints by expanding sections
4. Use "Try it out" to test API calls
5. View request/response schemas
## Integration
This server can be:
- Deployed standalone for documentation
- Integrated into main API server
- Used in CI/CD for API validation
- Embedded in developer portals

View File

@@ -0,0 +1,278 @@
# Swagger Documentation - Complete Guide
## Overview
Full Swagger/OpenAPI documentation for the eMoney Token Factory API is available through an interactive Swagger UI server.
## Quick Start
### Option 1: Node.js Server (Recommended)
```bash
cd api/tools/swagger-ui
pnpm install
pnpm run dev
```
**Access**: http://localhost:8080/api-docs
### Option 2: Docker
```bash
cd api/tools/swagger-ui
docker-compose up
```
**Access**: http://localhost:8080/api-docs
### Option 3: Standalone HTML
```bash
cd api/tools/swagger-ui
pnpm install
pnpm run build
pnpm run generate:standalone
```
**Output**: `static/standalone.html` (open directly in browser)
## Documentation Endpoints
When the server is running:
- **Interactive Docs**: http://localhost:8080/api-docs
- **OpenAPI JSON**: http://localhost:8080/openapi.json
- **OpenAPI YAML**: http://localhost:8080/openapi.yaml
- **Standalone HTML**: http://localhost:8080/standalone
- **Health Check**: http://localhost:8080/health
## Features
### 1. Complete API Coverage
All API endpoints documented:
- ✅ Token operations (deploy, mint, burn, clawback, force-transfer)
- ✅ Lien management (place, reduce, release, query)
- ✅ Compliance operations (set, freeze, query)
- ✅ Account-Wallet mappings
- ✅ Trigger management (ISO-20022 processing)
- ✅ Packet operations (generate, dispatch, acknowledge)
- ✅ Bridge operations (lock, unlock)
### 2. Interactive Testing
- **Try It Out**: Test any endpoint directly from the browser
- **Request Builder**: Fill in parameters and see request format
- **Response Viewer**: See actual API responses
- **Error Handling**: View error responses with reason codes
### 3. Authentication Support
- **OAuth2**: Test client credentials flow
- **mTLS**: Configure mutual TLS for adapters
- **API Key**: Set API keys for internal services
- **Token Persistence**: Tokens saved across page reloads
### 4. Schema Documentation
- **Data Models**: All request/response schemas
- **Enums**: All enum values (ReasonCodes, TriggerStates, Rails, etc.)
- **Examples**: Example payloads for each endpoint
- **Validation Rules**: Field requirements and constraints
### 5. Export Options
- **Download JSON**: Get OpenAPI spec as JSON
- **Download YAML**: Get OpenAPI spec as YAML
- **Share Links**: Share specific endpoint documentation
- **Embed**: Embed Swagger UI in other applications
## API Modules Documented
### Tokens Module
- Deploy new eMoney tokens
- Configure token policies
- Mint and burn operations
- Clawback and force transfer
- Query token metadata
### Liens Module
- Place liens on accounts
- Reduce lien amounts
- Release liens
- Query lien information
- Check encumbrance summaries
### Compliance Module
- Set compliance profiles
- Freeze/unfreeze accounts
- Manage risk tiers
- Set jurisdiction information
- Query compliance status
### Mappings Module
- Link accounts to wallets
- Unlink mappings
- Query account wallets
- Query wallet accounts
### Triggers Module
- Submit ISO-20022 messages
- Query trigger status
- Manage trigger lifecycle
- View trigger history
### ISO-20022 Module
- Submit inbound messages (from rails)
- Submit outbound messages (to rails)
- Message normalization
- Instruction ID tracking
### Packets Module
- Generate packets (PDF/AS4/Email)
- Dispatch packets
- Track acknowledgements
- Download packet files
### Bridge Module
- Lock tokens for cross-chain
- Unlock tokens with proofs
- Query lock status
- View supported corridors
## Usage Examples
### Testing Token Deployment
1. Navigate to `/tokens` endpoint
2. Click "Try it out"
3. Fill in token configuration:
```json
{
"name": "USD Wrapped",
"symbol": "USDW",
"decimals": 18,
"issuer": "0x1234...",
"defaultLienMode": "ENCUMBERED"
}
```
4. Click "Execute"
5. View response with token address
### Testing Lien Placement
1. Navigate to `/liens` endpoint
2. Click "Try it out"
3. Fill in lien details:
```json
{
"debtor": "0xabcd...",
"amount": "1000000000000000000",
"priority": 1,
"reasonCode": "DEBT_ENFORCEMENT"
}
```
4. Click "Execute"
5. View response with lien ID
### Setting Authentication
1. Click "Authorize" button at top
2. Enter OAuth2 token in "Value" field
3. Click "Authorize"
4. Token will be used for all requests
5. Click "Logout" to clear
## Integration
### Embed in Main API Server
Add to `api/services/rest-api/src/index.ts`:
```typescript
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
import { join } from 'path';
const openapiSpec = YAML.load(join(__dirname, '../../packages/openapi/v1/openapi.yaml'));
app.use('/docs', swaggerUi.serve, swaggerUi.setup(openapiSpec));
```
### Production Deployment
1. **Standalone Service**: Deploy as separate service
2. **CDN Distribution**: Serve via CDN for performance
3. **Embedded**: Include in main API server
4. **Static HTML**: Generate and serve static file
## Customization
### Change Port
```bash
export SWAGGER_PORT=9000
pnpm start
```
### Custom Theme
Edit `src/index.ts`:
```typescript
const swaggerOptions = {
customCss: `
.swagger-ui .info .title {
color: #your-brand-color;
font-family: 'Your Font';
}
`,
};
```
### Default Server
Set default API server:
```typescript
swaggerOptions: {
url: 'https://api.emoney.example.com/v1',
}
```
## Troubleshooting
### Server Won't Start
- Check if port 8080 is available
- Verify OpenAPI spec path is correct
- Check YAML syntax is valid
### Spec Not Loading
- Verify `openapi.yaml` exists
- Check file permissions
- Validate YAML syntax
### Try It Out Fails
- Check CORS settings on API server
- Verify authentication is set
- Check network tab for errors
- Ensure API server is running
## Best Practices
1. **Keep Spec Updated**: Update OpenAPI spec as API changes
2. **Use Examples**: Provide realistic examples in spec
3. **Document Errors**: Include error response examples
4. **Test Regularly**: Use Try It Out to validate endpoints
5. **Share Links**: Share specific endpoint URLs with team
## Additional Resources
- [OpenAPI Specification](https://swagger.io/specification/)
- [Swagger UI Documentation](https://swagger.io/tools/swagger-ui/)
- [API Integration Cookbook](../docs/api/integration-cookbook.md)
- [Error Catalog](../docs/api/error-catalog.md)

View File

@@ -0,0 +1,13 @@
version: '3.8'
services:
swagger-ui:
build: .
ports:
- "8080:8080"
environment:
- SWAGGER_PORT=8080
volumes:
- ../packages/openapi/v1/openapi.yaml:/app/packages/openapi/v1/openapi.yaml:ro
restart: unless-stopped

View File

@@ -0,0 +1,28 @@
{
"name": "@emoney/swagger-ui",
"version": "1.0.0",
"description": "Swagger UI server for eMoney API documentation",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
"generate:standalone": "ts-node src/generate-standalone.ts",
"docker:build": "docker build -t emoney-swagger-ui .",
"docker:run": "docker run -p 8080:8080 emoney-swagger-ui"
},
"dependencies": {
"express": "^4.18.2",
"swagger-ui-express": "^5.0.0",
"swagger-jsdoc": "^6.2.8",
"yamljs": "^0.3.0"
},
"devDependencies": {
"@types/express": "^4.17.21",
"@types/swagger-ui-express": "^4.1.4",
"@types/node": "^20.10.0",
"typescript": "^5.3.0",
"ts-node-dev": "^2.0.0",
"ts-node": "^10.9.2"
}
}

View File

@@ -0,0 +1,87 @@
/**
* Generate standalone HTML documentation
* Creates a self-contained HTML file with embedded OpenAPI spec
*/
import { readFileSync, writeFileSync } from 'fs';
import { join } from 'path';
import YAML from 'yamljs';
const openapiPath = join(__dirname, '../../packages/openapi/v1/openapi.yaml');
const openapiSpec = YAML.load(openapiPath);
const outputPath = join(__dirname, '../swagger-ui/static/standalone.html');
const htmlTemplate = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>eMoney Token Factory API Documentation</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui.css" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
background: #fafafa;
}
.swagger-ui .topbar {
display: none;
}
.swagger-ui .info {
margin: 50px 0;
}
.swagger-ui .info .title {
font-size: 36px;
color: #3b4151;
}
.swagger-ui .info .description {
font-size: 16px;
line-height: 1.6;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
const spec = ${JSON.stringify(openapiSpec, null, 2)};
const ui = SwaggerUIBundle({
spec: spec,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
persistAuthorization: true,
displayRequestDuration: true,
filter: true,
tryItOutEnabled: true,
supportedSubmitMethods: ['get', 'post', 'put', 'patch', 'delete'],
docExpansion: 'list',
defaultModelsExpandDepth: 2,
defaultModelExpandDepth: 2,
});
};
</script>
</body>
</html>`;
writeFileSync(outputPath, htmlTemplate);
console.log(`Standalone HTML documentation generated: ${outputPath}`);

View File

@@ -0,0 +1,85 @@
/**
* Swagger UI Server
* Serves interactive API documentation from OpenAPI specification
*/
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import YAML from 'yamljs';
import { readFileSync } from 'fs';
import { join } from 'path';
import path from 'path';
const app = express();
const PORT = process.env.SWAGGER_PORT || 8080;
// Load OpenAPI specification
const openapiPath = join(__dirname, '../../packages/openapi/v1/openapi.yaml');
const openapiSpec = YAML.load(openapiPath);
// Serve static files (OAuth2 redirect, standalone HTML)
app.use('/static', express.static(join(__dirname, '../../swagger-ui/static')));
// Swagger UI options
const swaggerOptions = {
customCss: `
.swagger-ui .topbar { display: none; }
.swagger-ui .info { margin: 50px 0; }
.swagger-ui .info .title { font-size: 36px; }
.swagger-ui .info .description { font-size: 16px; line-height: 1.6; }
.swagger-ui .scheme-container { margin: 20px 0; }
`,
customSiteTitle: 'eMoney Token Factory API Documentation',
customfavIcon: '/favicon.ico',
swaggerOptions: {
persistAuthorization: true,
displayRequestDuration: true,
filter: true,
tryItOutEnabled: true,
supportedSubmitMethods: ['get', 'post', 'put', 'patch', 'delete'],
docExpansion: 'list',
defaultModelsExpandDepth: 2,
defaultModelExpandDepth: 2,
oauth2RedirectUrl: '/static/oauth2-redirect.html',
},
};
// Serve Swagger UI
app.use('/api-docs', swaggerUi.serve);
app.get('/api-docs', swaggerUi.setup(openapiSpec, swaggerOptions));
// Serve OpenAPI spec as JSON
app.get('/openapi.json', (req, res) => {
res.json(openapiSpec);
});
// Serve OpenAPI spec as YAML
app.get('/openapi.yaml', (req, res) => {
res.setHeader('Content-Type', 'text/yaml');
res.send(readFileSync(openapiPath, 'utf-8'));
});
// Serve standalone HTML
app.get('/standalone', (req, res) => {
res.sendFile(join(__dirname, '../../swagger-ui/static/standalone.html'));
});
// Redirect root to docs
app.get('/', (req, res) => {
res.redirect('/api-docs');
});
// Health check
app.get('/health', (req, res) => {
res.json({ status: 'ok', service: 'swagger-ui' });
});
app.listen(PORT, () => {
console.log(`Swagger UI server running on http://localhost:${PORT}`);
console.log(`API Documentation: http://localhost:${PORT}/api-docs`);
console.log(`OpenAPI JSON: http://localhost:${PORT}/openapi.json`);
console.log(`OpenAPI YAML: http://localhost:${PORT}/openapi.yaml`);
});
export default app;

View File

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>eMoney Token Factory API Documentation</title>
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui.css" />
<style>
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
background: #fafafa;
}
.swagger-ui .topbar {
display: none;
}
.swagger-ui .info {
margin: 50px 0;
}
.swagger-ui .info .title {
font-size: 36px;
color: #3b4151;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.10.3/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function() {
const ui = SwaggerUIBundle({
url: "/openapi.yaml",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
persistAuthorization: true,
displayRequestDuration: true,
filter: true,
tryItOutEnabled: true,
supportedSubmitMethods: ['get', 'post', 'put', 'patch', 'delete'],
docExpansion: 'list',
defaultModelsExpandDepth: 2,
defaultModelExpandDepth: 2,
oauth2RedirectUrl: window.location.origin + '/oauth2-redirect.html'
});
};
</script>
</body>
</html>

View File

@@ -0,0 +1,76 @@
<!doctype html>
<html>
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() +'}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
err: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
err: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', run);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}