From 118ad413a3fa671dd9f7536b68e56ea33ce39ba9 Mon Sep 17 00:00:00 2001 From: memplethee-lab Date: Mon, 29 Jun 2026 19:22:39 +0100 Subject: [PATCH] Revert "Implement Transaction Tracking & History" --- package-lock.json | 54 +--- package.json | 3 +- src/app.controller.ts | 3 + src/app.service.ts | 3 + .../oracle/dto/create-payload.dto.ts | 3 + .../oracle/dto/payload-response.dto.ts | 3 + src/blockchain/oracle/dto/sign-payload.dto.ts | 3 + .../oracle/dto/submit-payload.dto.ts | 3 + .../oracle/dto/verify-signature.dto.ts | 3 + .../oracle/entities/signed-payload.entity.ts | 3 + .../entities/submission-nonce.entity.ts | 3 + src/blockchain/oracle/oracle.controller.ts | 3 + src/blockchain/oracle/oracle.module.ts | 3 + .../services/nonce-management.service.ts | 3 + .../oracle/services/oracle.service.ts | 3 + .../services/payload-signing.service.ts | 3 + .../services/submission-batch.service.spec.ts | 3 + .../services/submission-batch.service.ts | 3 + .../oracle/services/submitter.service.ts | 3 + .../oracle/submission-verifier.controller.ts | 3 + .../oracle/submission-verifier.e2e-spec.ts | 3 + .../oracle/submission-verifier.service.ts | 3 + src/common/database/database-index.service.ts | 3 + src/common/decorators/public.decorator.ts | 3 + src/common/decorators/roles.decorator.ts | 3 + src/common/decorators/skip-kyc.decorator.ts | 3 + src/common/filters/global-exception.filter.ts | 3 + src/common/guard/kyc.guard.ts | 3 + src/common/guard/nonce.guard.spec.ts | 3 + src/common/guard/nonce.guard.ts | 3 + src/common/guard/role-separation.spec.ts | 3 + src/common/guard/roles.decorator.ts | 3 + src/common/guard/roles.enum.ts | 3 + src/common/guard/roles.guard.spec.ts | 3 + src/common/guard/roles.guard.ts | 3 + src/common/guard/throttler.guard.ts | 3 + src/common/index.ts | 3 + src/common/middleware/logging.config.ts | 3 + .../middleware/logging.middleware.spec.ts | 3 + src/common/middleware/logging.middleware.ts | 3 + src/common/middleware/sentry.middleware.ts | 3 + .../pagination/cursor-pagination.dto.ts | 3 + .../cursor-pagination.service.spec.ts | 3 + .../pagination/cursor-pagination.service.ts | 3 + src/common/pagination/pagination.module.ts | 3 + src/common/pipes/sanitize.pipe.ts | 3 + .../sensitive-throttler.guard.spec.ts | 3 + .../throttler/sensitive-throttler.guard.ts | 3 + src/config/cors.config.ts | 3 + src/config/env.validation.ts | 3 + src/config/helmet.config.ts | 3 + src/config/logger.ts | 3 + src/config/metrics.ts | 3 + src/config/nest-pino-logger.ts | 3 + src/config/quota.config.ts | 3 +- src/config/sentry.ts | 3 + src/config/swagger.config.ts | 3 + src/config/tracing.ts | 3 +- src/core/auth/auth.module.ts | 3 + src/core/auth/auth.service.spec.ts | 3 + src/core/auth/challenge.service.ts | 3 + .../allowed-strategies.decorator.ts | 3 + .../auth/decorators/auth-type.decorator.ts | 3 + .../auth/decorators/current-user.decorator.ts | 3 + src/core/auth/decorators/index.ts | 3 + src/core/auth/delegation.service.ts | 3 + src/core/auth/dto/auth.dto.ts | 3 + src/core/auth/dto/kyc.dto.ts | 3 + src/core/auth/dto/link-email.dto.ts | 3 + src/core/auth/dto/link-wallet.dto.ts | 3 + src/core/auth/dto/recover-wallet.dto.ts | 3 + src/core/auth/dto/request-recovery.dto.ts | 3 + src/core/auth/dto/unlink-wallet.dto.ts | 3 + src/core/auth/dto/verify-email.dto.ts | 3 + src/core/auth/email-linking.service.ts | 3 + src/core/auth/email.service.ts | 3 + src/core/auth/enhanced-auth.controller.ts | 3 + src/core/auth/enhanced-auth.service.spec.ts | 3 + src/core/auth/entities/auth.entity.ts | 3 + .../entities/email-verification.entity.ts | 3 + src/core/auth/entities/wallet.entity.ts | 3 + .../guards/admin-two-factor.guard.spec.ts | 3 + .../auth/guards/admin-two-factor.guard.ts | 3 + src/core/auth/guards/jwt-auth.guard.ts | 3 + src/core/auth/jwt.guard.ts | 3 + src/core/auth/kyc.guard.ts | 3 + src/core/auth/recovery.service.ts | 3 + src/core/auth/session-recovery.service.ts | 3 + src/core/auth/strategies/index.ts | 3 + src/core/auth/strategies/strategy.registry.ts | 3 + src/core/auth/strategy-auth.service.ts | 3 + src/core/auth/token-blacklist.service.ts | 3 + src/core/auth/wallet-auth.service.spec.ts | 3 + src/core/profile/dto/create-profile.dto.ts | 3 + src/core/profile/dto/update-profile.dto.ts | 3 + src/core/profile/entities/profile.entity.ts | 3 + src/core/profile/profile.controller.ts | 3 + src/core/profile/profile.module.ts | 3 + src/core/profile/profile.service.ts | 3 + src/core/user/dto/create-user.dto.ts | 3 + src/core/user/dto/update-user.dto.ts | 3 + src/core/user/user-role-separation.spec.ts | 3 + src/core/user/user.controller.ts | 3 + src/core/user/user.module.ts | 3 + src/core/user/user.service.ts | 3 + src/dashboard/dashboard.controller.ts | 3 + src/dashboard/dashboard.module.ts | 3 + src/dashboard/dashboard.service.ts | 3 + src/dashboard/dto/dashboard.dto.ts | 3 + .../adapters/dashboard-ws-auth.adapter.ts | 3 + src/dashboard/websocket/dashboard.gateway.ts | 3 + .../websocket/filters/ws-exception.filter.ts | 3 + src/dashboard/websocket/index.ts | 3 + .../interfaces/websocket.interfaces.ts | 3 + .../connection-manager.service.spec.ts | 3 + .../services/connection-manager.service.ts | 3 + .../services/connection-pool.service.ts | 3 + .../services/dashboard-client.service.ts | 3 + .../services/dashboard-metrics.service.ts | 3 + .../services/event-buffer.service.spec.ts | 3 + .../services/event-buffer.service.ts | 3 + .../services/reconnection.service.spec.ts | 3 + .../services/reconnection.service.ts | 3 + .../services/websocket-health.service.ts | 3 + .../websocket/websocket.stress.spec.ts | 3 + src/defi/defi.controller.ts | 3 + src/defi/defi.module.ts | 3 + src/defi/dto/defi.dto.ts | 3 + src/defi/dto/yield-strategy.dto.ts | 3 + src/defi/entities/defi-position.entity.ts | 3 + .../entities/defi-risk-assessment.entity.ts | 3 + src/defi/entities/defi-transaction.entity.ts | 3 + src/defi/entities/defi-yield-record.entity.ts | 3 + .../entities/defi-yield-strategy.entity.ts | 3 + src/defi/protocols/aave.adapter.ts | 3 + src/defi/protocols/compound.adapter.ts | 3 + .../protocols/protocol-adapter.interface.ts | 3 + src/defi/protocols/protocol-registry.ts | 3 + .../services/position-tracking.service.ts | 3 + src/defi/services/risk-assessment.service.ts | 3 + .../transaction-optimization.service.ts | 3 + .../services/yield-optimization.service.ts | 3 + src/defi/trade-lock.service.ts | 3 + src/defi/trade.controller.ts | 3 + .../algorithms/agent-scoring.spec.ts | 3 + src/discovery/algorithms/agent-scoring.ts | 3 + src/growth/alerts/alerts.controller.ts | 3 + src/growth/alerts/alerts.module.ts | 3 + src/growth/alerts/alerts.service.spec.ts | 3 + src/growth/alerts/alerts.service.ts | 3 + src/growth/alerts/dto/alert-preference.dto.ts | 3 + src/growth/alerts/dto/alert.dto.ts | 3 + .../entities/alert-preference.entity.ts | 3 + .../entities/alert-trigger-log.entity.ts | 3 + src/growth/alerts/entities/alert.entity.ts | 3 + .../listeners/portfolio-alert.listener.ts | 3 + .../alerts/listeners/risk-alert.listener.ts | 3 + .../services/alert-dispatcher.service.spec.ts | 3 + .../services/alert-dispatcher.service.ts | 3 + .../services/alert-evaluation.service.spec.ts | 3 + .../services/alert-evaluation.service.ts | 3 + src/health/dto/health-response.dto.ts | 3 + src/health/health.constants.ts | 3 + src/health/health.controller.spec.ts | 3 + src/health/health.controller.ts | 3 + src/health/health.module.ts | 3 + src/health/health.service.spec.ts | 3 + src/health/health.service.ts | 3 + .../ai-compute/provider-failover.spec.ts | 3 + .../ai-compute/provider-failover.ts | 3 + src/infrastructure/audit/audit-log.service.ts | 3 + src/infrastructure/audit/audit.module.ts | 3 + .../audit/dto/create-provenance-record.dto.ts | 3 + .../audit/dto/provenance-response.dto.ts | 3 + .../audit/dto/query-provenance.dto.ts | 3 + .../audit/entities/agent-event.entity.ts | 3 + .../audit/entities/compute-result.entity.ts | 3 + .../entities/oracle-submission.entity.ts | 3 + .../entities/provenance-record.entity.ts | 3 + .../audit/guards/provenance-access.guard.ts | 3 + .../audit/provenance.controller.ts | 3 + .../audit/provenance.service.ts | 3 + .../portfolio/algorithms/black-litterman.ts | 3 + .../algorithms/constraint-optimizer.ts | 3 + .../algorithms/modern-portfolio-theory.ts | 3 + .../performance-calculations.spec.ts | 3 + .../algorithms/performance-calculations.ts | 3 + .../algorithms/portfolio-validation.spec.ts | 3 + .../algorithms/portfolio-validation.ts | 3 + .../controllers/transaction.controller.ts | 62 ----- src/investment/portfolio/dto/api-error.dto.ts | 3 + src/investment/portfolio/dto/backtest.dto.ts | 3 + .../portfolio/dto/optimization.dto.ts | 3 + .../portfolio/dto/performance.dto.ts | 3 + .../portfolio/dto/portfolio-asset.dto.ts | 3 + .../portfolio/dto/portfolio-management.dto.ts | 3 + src/investment/portfolio/dto/portfolio.dto.ts | 3 + .../portfolio/dto/risk-profile.dto.ts | 3 + .../portfolio/dto/transaction.dto.ts | 67 ----- .../entities/backtest-result.entity.ts | 3 + .../entities/optimization-history.entity.ts | 3 + .../entities/performance-metric.entity.ts | 3 + .../entities/portfolio-asset.entity.ts | 3 + .../portfolio/entities/portfolio.entity.ts | 3 + .../entities/rebalancing-event.entity.ts | 3 + .../portfolio/entities/risk-profile.entity.ts | 3 + .../portfolio/entities/transaction.entity.ts | 26 +- .../portfolio/guards/portfolio-owner.guard.ts | 3 + .../portfolio/ml-models/predictor.ts | 3 + .../portfolio-management.controller.ts | 3 + src/investment/portfolio/portfolio.module.ts | 7 +- .../portfolio/services/backtesting.service.ts | 3 + .../services/ml-prediction.service.ts | 3 + .../performance-analytics.service.spec.ts | 3 + .../services/performance-analytics.service.ts | 3 + .../portfolio-constraint.service.spec.ts | 3 + .../services/portfolio-constraint.service.ts | 3 + .../portfolio/services/portfolio.service.ts | 3 + .../services/trading-transaction.service.ts | 187 +------------ .../circuit-breaker.service.spec.ts | 3 + .../circuit-breaker.service.ts | 3 + .../risk-management/dto/risk.dto.ts | 3 + .../risk-management.controller.ts | 3 + .../risk-management/risk-management.health.ts | 3 + .../risk-management/risk-management.module.ts | 3 + .../risk-management.service.ts | 3 + src/main.ts | 3 + .../database-timing.interceptor.ts | 3 + .../monitoring-dashboard.spec.ts | 3 + .../observability.controller.spec.ts | 3 + src/observability/observability.controller.ts | 3 + src/observability/observability.module.ts | 3 + .../performance-baseline.service.ts | 3 + src/observability/profiling.controller.ts | 3 + src/observability/profiling.service.ts | 3 + .../request-timing.middleware.spec.ts | 3 + .../request-timing.middleware.ts | 3 + .../controllers/portfolio.controller.ts | 3 + src/portfolio/portfolio.module.ts | 3 + src/portfolio/services/rebalancing.service.ts | 3 + src/profiling/profiling.controller.ts | 3 + src/profiling/profiling.middleware.ts | 3 + src/profiling/profiling.module.ts | 3 + src/profiling/profiling.service.ts | 3 + src/types/jest-globals.d.ts | 3 + src/types/supertest.d.ts | 3 + test/audit/provenance.e2e-spec.ts | 255 +++++++++--------- test/auth/wallet-advanced.e2e-spec.ts | 202 +++++++------- test/email-linking.spec.ts | 198 ++++++-------- test/enhanced-auth.service.spec.ts | 3 +- test/oracle-e2e.spec.ts | 200 +++++++------- test/oracle/payload-signing.service.spec.ts | 108 ++++---- test/portfolio/mpt.spec.ts | 179 ++++++------ .../portfolio-management.e2e-spec.ts | 1 + test/portfolio/portfolio.service.spec.ts | 97 +++---- test/recovery.spec.ts | 89 +++--- test/traditional-auth.e2e-spec.ts | 174 ++++++------ test/wallet-auth.spec.ts | 69 +++-- test/wallet-management.e2e-spec.ts | 174 ++++++------ tsconfig.json | 6 +- 260 files changed, 1584 insertions(+), 1294 deletions(-) delete mode 100644 src/investment/portfolio/controllers/transaction.controller.ts delete mode 100644 src/investment/portfolio/dto/transaction.dto.ts diff --git a/package-lock.json b/package-lock.json index feb38dc..89f3ab4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,6 @@ "express": "^5.2.1", "express-mongo-sanitize": "^2.2.0", "express-rate-limit": "^8.2.1", - "fast-csv": "^5.0.7", "helmet": "^8.1.0", "hpp": "^0.2.3", "ioredis": "^5.9.3", @@ -95,7 +94,7 @@ "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.17.0", "@typescript-eslint/parser": "^6.17.0", - "eslint": "^8.57.1", + "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-prettier": "^5.1.2", @@ -1028,26 +1027,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@fast-csv/format": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-5.0.7.tgz", - "integrity": "sha512-VdypoRxv7PF+LsyPouTMKdB0d76hync+gLpgdNqfqVK44MsgW4oiCJSdrki2FisWT7v2QGUYDHjp4L7w5oO6gw==", - "license": "MIT", - "dependencies": { - "lodash.escaperegexp": "^4.1.2" - } - }, - "node_modules/@fast-csv/parse": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-5.0.7.tgz", - "integrity": "sha512-MeuDeQj0DVmIGWky8STaKtvj232Gpq8kjrOGplHJ99Os7OO5CetVfXvUGqX/3GHYFOUsz6FK8isWtDY2XTFNWw==", - "license": "MIT", - "dependencies": { - "lodash.escaperegexp": "^4.1.2", - "lodash.groupby": "^4.6.0", - "lodash.uniq": "^4.5.0" - } - }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", @@ -10811,19 +10790,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-csv": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-5.0.7.tgz", - "integrity": "sha512-KirK9wYIUXF/xTYmg/jv9ehUWbQ4Faf6XutuJKlEz72eoqKMMLdCnz+rGDeBSjpV2wwkHQnLSuJ5i+FRRnzZwA==", - "license": "MIT", - "dependencies": { - "@fast-csv/format": "5.0.7", - "@fast-csv/parse": "5.0.7" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -13865,18 +13831,6 @@ "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "license": "MIT" }, - "node_modules/lodash.escaperegexp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", - "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", - "license": "MIT" - }, - "node_modules/lodash.groupby": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", - "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==", - "license": "MIT" - }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", @@ -13933,12 +13887,6 @@ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "license": "MIT" - }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", diff --git a/package.json b/package.json index 4029a48..a4d4743 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,6 @@ "express": "^5.2.1", "express-mongo-sanitize": "^2.2.0", "express-rate-limit": "^8.2.1", - "fast-csv": "^5.0.7", "helmet": "^8.1.0", "hpp": "^0.2.3", "ioredis": "^5.9.3", @@ -123,7 +122,7 @@ "@types/uuid": "^9.0.7", "@typescript-eslint/eslint-plugin": "^6.17.0", "@typescript-eslint/parser": "^6.17.0", - "eslint": "^8.57.1", + "eslint": "^8.56.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-prettier": "^5.1.2", diff --git a/src/app.controller.ts b/src/app.controller.ts index 0d422e7..01532df 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -120,3 +120,6 @@ export class AppController { }; } } + + + diff --git a/src/app.service.ts b/src/app.service.ts index 4926cb3..942e330 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -29,3 +29,6 @@ export class AppService { }; } } + + + diff --git a/src/blockchain/oracle/dto/create-payload.dto.ts b/src/blockchain/oracle/dto/create-payload.dto.ts index f14a77f..2123720 100644 --- a/src/blockchain/oracle/dto/create-payload.dto.ts +++ b/src/blockchain/oracle/dto/create-payload.dto.ts @@ -36,3 +36,6 @@ export class CreatePayloadDto { @IsOptional() metadata?: Record; } + + + diff --git a/src/blockchain/oracle/dto/payload-response.dto.ts b/src/blockchain/oracle/dto/payload-response.dto.ts index b383a2d..8c8186e 100644 --- a/src/blockchain/oracle/dto/payload-response.dto.ts +++ b/src/blockchain/oracle/dto/payload-response.dto.ts @@ -24,3 +24,6 @@ export class PayloadResponseDto { submittedAt: Date | null; confirmedAt: Date | null; } + + + diff --git a/src/blockchain/oracle/dto/sign-payload.dto.ts b/src/blockchain/oracle/dto/sign-payload.dto.ts index 5f66bc9..e7a8dad 100644 --- a/src/blockchain/oracle/dto/sign-payload.dto.ts +++ b/src/blockchain/oracle/dto/sign-payload.dto.ts @@ -15,3 +15,6 @@ export class SignPayloadDto { }) privateKey: string; } + + + diff --git a/src/blockchain/oracle/dto/submit-payload.dto.ts b/src/blockchain/oracle/dto/submit-payload.dto.ts index 76e1eff..d0ff475 100644 --- a/src/blockchain/oracle/dto/submit-payload.dto.ts +++ b/src/blockchain/oracle/dto/submit-payload.dto.ts @@ -14,3 +14,6 @@ export class SubmitPayloadDto { @IsNotEmpty() payloadId: string; } + + + diff --git a/src/blockchain/oracle/dto/verify-signature.dto.ts b/src/blockchain/oracle/dto/verify-signature.dto.ts index c3f9d54..d3cb15d 100644 --- a/src/blockchain/oracle/dto/verify-signature.dto.ts +++ b/src/blockchain/oracle/dto/verify-signature.dto.ts @@ -22,3 +22,6 @@ export class VerifySignatureDto { }) expectedSigner: string; } + + + diff --git a/src/blockchain/oracle/entities/signed-payload.entity.ts b/src/blockchain/oracle/entities/signed-payload.entity.ts index 28f6a39..d42f3ee 100644 --- a/src/blockchain/oracle/entities/signed-payload.entity.ts +++ b/src/blockchain/oracle/entities/signed-payload.entity.ts @@ -141,3 +141,6 @@ export class SignedPayload { @Column({ type: "timestamp", nullable: true }) confirmedAt: Date | null; } + + + diff --git a/src/blockchain/oracle/entities/submission-nonce.entity.ts b/src/blockchain/oracle/entities/submission-nonce.entity.ts index b4b84ac..17880a7 100644 --- a/src/blockchain/oracle/entities/submission-nonce.entity.ts +++ b/src/blockchain/oracle/entities/submission-nonce.entity.ts @@ -41,3 +41,6 @@ export class SubmissionNonce { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/blockchain/oracle/oracle.controller.ts b/src/blockchain/oracle/oracle.controller.ts index d5cd3c5..aa1af2a 100644 --- a/src/blockchain/oracle/oracle.controller.ts +++ b/src/blockchain/oracle/oracle.controller.ts @@ -252,3 +252,6 @@ export class OracleController { }; } } + + + diff --git a/src/blockchain/oracle/oracle.module.ts b/src/blockchain/oracle/oracle.module.ts index 2151f72..81ebc06 100644 --- a/src/blockchain/oracle/oracle.module.ts +++ b/src/blockchain/oracle/oracle.module.ts @@ -46,3 +46,6 @@ import { AuditModule } from "src/infrastructure/audit/audit.module"; ], }) export class OracleModule {} + + + diff --git a/src/blockchain/oracle/services/nonce-management.service.ts b/src/blockchain/oracle/services/nonce-management.service.ts index 5781ffc..e4f2c2d 100644 --- a/src/blockchain/oracle/services/nonce-management.service.ts +++ b/src/blockchain/oracle/services/nonce-management.service.ts @@ -267,3 +267,6 @@ export class NonceManagementService { return deletedCount; } } + + + diff --git a/src/blockchain/oracle/services/oracle.service.ts b/src/blockchain/oracle/services/oracle.service.ts index 87760f2..6af1c21 100644 --- a/src/blockchain/oracle/services/oracle.service.ts +++ b/src/blockchain/oracle/services/oracle.service.ts @@ -393,3 +393,6 @@ export class OracleService { }; } } + + + diff --git a/src/blockchain/oracle/services/payload-signing.service.ts b/src/blockchain/oracle/services/payload-signing.service.ts index 426ed1e..aba5f0e 100644 --- a/src/blockchain/oracle/services/payload-signing.service.ts +++ b/src/blockchain/oracle/services/payload-signing.service.ts @@ -251,3 +251,6 @@ export class PayloadSigningService { return payloadHash; } } + + + diff --git a/src/blockchain/oracle/services/submission-batch.service.spec.ts b/src/blockchain/oracle/services/submission-batch.service.spec.ts index 284dba4..44e3b0b 100644 --- a/src/blockchain/oracle/services/submission-batch.service.spec.ts +++ b/src/blockchain/oracle/services/submission-batch.service.spec.ts @@ -446,3 +446,6 @@ describe("SubmissionBatchService - Exponential Backoff", () => { expect(result.attemptNumber).toBe(1); }); }); + + + diff --git a/src/blockchain/oracle/services/submission-batch.service.ts b/src/blockchain/oracle/services/submission-batch.service.ts index da6db45..a54a3f0 100644 --- a/src/blockchain/oracle/services/submission-batch.service.ts +++ b/src/blockchain/oracle/services/submission-batch.service.ts @@ -747,3 +747,6 @@ export class SubmissionBatchService { return new Promise((resolve) => setTimeout(resolve, ms)); } } + + + diff --git a/src/blockchain/oracle/services/submitter.service.ts b/src/blockchain/oracle/services/submitter.service.ts index c424ca0..8e370e0 100644 --- a/src/blockchain/oracle/services/submitter.service.ts +++ b/src/blockchain/oracle/services/submitter.service.ts @@ -697,3 +697,6 @@ export class SubmitterService { }; } } + + + diff --git a/src/blockchain/oracle/submission-verifier.controller.ts b/src/blockchain/oracle/submission-verifier.controller.ts index 36eaabe..fcc1719 100644 --- a/src/blockchain/oracle/submission-verifier.controller.ts +++ b/src/blockchain/oracle/submission-verifier.controller.ts @@ -21,3 +21,6 @@ export class SubmissionVerifierController { return this.audit.getLogs(); } } + + + diff --git a/src/blockchain/oracle/submission-verifier.e2e-spec.ts b/src/blockchain/oracle/submission-verifier.e2e-spec.ts index ddf0ad1..a1ba9d2 100644 --- a/src/blockchain/oracle/submission-verifier.e2e-spec.ts +++ b/src/blockchain/oracle/submission-verifier.e2e-spec.ts @@ -19,3 +19,6 @@ describe("Submission Verifier", () => { expect(Array.isArray(res.body)).toBe(true); }); }); + + + diff --git a/src/blockchain/oracle/submission-verifier.service.ts b/src/blockchain/oracle/submission-verifier.service.ts index 87ef32d..bd087a3 100644 --- a/src/blockchain/oracle/submission-verifier.service.ts +++ b/src/blockchain/oracle/submission-verifier.service.ts @@ -150,3 +150,6 @@ export class SubmissionVerifierService { }; } } + + + diff --git a/src/common/database/database-index.service.ts b/src/common/database/database-index.service.ts index ada38ef..3585ccd 100644 --- a/src/common/database/database-index.service.ts +++ b/src/common/database/database-index.service.ts @@ -281,3 +281,6 @@ export class DatabaseIndexService { } } } + + + diff --git a/src/common/decorators/public.decorator.ts b/src/common/decorators/public.decorator.ts index 6b72f1f..0ac145e 100644 --- a/src/common/decorators/public.decorator.ts +++ b/src/common/decorators/public.decorator.ts @@ -12,3 +12,6 @@ export const IS_PUBLIC_KEY = "isPublic"; * healthCheck() { ... } */ export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); + + + diff --git a/src/common/decorators/roles.decorator.ts b/src/common/decorators/roles.decorator.ts index 4c228fb..d363b48 100644 --- a/src/common/decorators/roles.decorator.ts +++ b/src/common/decorators/roles.decorator.ts @@ -1,3 +1,6 @@ // Re-export from canonical location in guard/ to maintain backward compatibility export * from "../guard/roles.decorator"; export * from "../guard/roles.enum"; + + + diff --git a/src/common/decorators/skip-kyc.decorator.ts b/src/common/decorators/skip-kyc.decorator.ts index a62e18c..19327c9 100644 --- a/src/common/decorators/skip-kyc.decorator.ts +++ b/src/common/decorators/skip-kyc.decorator.ts @@ -7,3 +7,6 @@ export const SKIP_KYC_KEY = "skipKyc"; * Use only for onboarding flows that are required to become KYC verified. */ export const SkipKyc = () => SetMetadata(SKIP_KYC_KEY, true); + + + diff --git a/src/common/filters/global-exception.filter.ts b/src/common/filters/global-exception.filter.ts index f18b853..6c4dd9f 100644 --- a/src/common/filters/global-exception.filter.ts +++ b/src/common/filters/global-exception.filter.ts @@ -105,3 +105,6 @@ export class GlobalExceptionFilter implements ExceptionFilter { }); } } + + + diff --git a/src/common/guard/kyc.guard.ts b/src/common/guard/kyc.guard.ts index f14b3cb..b591299 100644 --- a/src/common/guard/kyc.guard.ts +++ b/src/common/guard/kyc.guard.ts @@ -37,3 +37,6 @@ export class KycGuard implements CanActivate { return user?.kycVerified === true; } } + + + diff --git a/src/common/guard/nonce.guard.spec.ts b/src/common/guard/nonce.guard.spec.ts index f19bf64..5b19e7c 100644 --- a/src/common/guard/nonce.guard.spec.ts +++ b/src/common/guard/nonce.guard.spec.ts @@ -92,3 +92,6 @@ describe("NonceGuard", () => { ).rejects.toThrow(ConflictException); }); }); + + + diff --git a/src/common/guard/nonce.guard.ts b/src/common/guard/nonce.guard.ts index 51b1c44..bee6f14 100644 --- a/src/common/guard/nonce.guard.ts +++ b/src/common/guard/nonce.guard.ts @@ -56,3 +56,6 @@ export class NonceGuard implements CanActivate { return true; } } + + + diff --git a/src/common/guard/role-separation.spec.ts b/src/common/guard/role-separation.spec.ts index a6ed82f..613cb90 100644 --- a/src/common/guard/role-separation.spec.ts +++ b/src/common/guard/role-separation.spec.ts @@ -90,3 +90,6 @@ describe("Role Separation — Governance cannot access KYC endpoints and vice ve }); }); }); + + + diff --git a/src/common/guard/roles.decorator.ts b/src/common/guard/roles.decorator.ts index 9b20ae6..8bee32a 100644 --- a/src/common/guard/roles.decorator.ts +++ b/src/common/guard/roles.decorator.ts @@ -25,3 +25,6 @@ export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles); * remove() { ... } */ export const RequireRole = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles); + + + diff --git a/src/common/guard/roles.enum.ts b/src/common/guard/roles.enum.ts index 98ade7f..744be09 100644 --- a/src/common/guard/roles.enum.ts +++ b/src/common/guard/roles.enum.ts @@ -55,3 +55,6 @@ export function hasRole(candidate: Role, required: Role): boolean { return candidateIdx >= requiredIdx; } + + + diff --git a/src/common/guard/roles.guard.spec.ts b/src/common/guard/roles.guard.spec.ts index 6d715cd..22e1cfe 100644 --- a/src/common/guard/roles.guard.spec.ts +++ b/src/common/guard/roles.guard.spec.ts @@ -161,3 +161,6 @@ describe("RolesGuard", () => { }); }); }); + + + diff --git a/src/common/guard/roles.guard.ts b/src/common/guard/roles.guard.ts index 3b188d8..c8dd728 100644 --- a/src/common/guard/roles.guard.ts +++ b/src/common/guard/roles.guard.ts @@ -75,3 +75,6 @@ export class RolesGuard implements CanActivate { return true; } } + + + diff --git a/src/common/guard/throttler.guard.ts b/src/common/guard/throttler.guard.ts index ef342e4..4ea2cd1 100644 --- a/src/common/guard/throttler.guard.ts +++ b/src/common/guard/throttler.guard.ts @@ -32,3 +32,6 @@ export class ThrottlerUserIpGuard extends ThrottlerGuard { return req.ip ?? "unknown"; } } + + + diff --git a/src/common/index.ts b/src/common/index.ts index 295353c..778a585 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -26,3 +26,6 @@ export { SENSITIVE_BODY_FIELDS, REQUEST_ID_HEADER, } from "./middleware/logging.config"; + + + diff --git a/src/common/middleware/logging.config.ts b/src/common/middleware/logging.config.ts index 9c4dc88..ae9a731 100644 --- a/src/common/middleware/logging.config.ts +++ b/src/common/middleware/logging.config.ts @@ -72,3 +72,6 @@ export const DEFAULT_LOGGING_CONFIG: Required = { }; export const REQUEST_ID_HEADER = "x-request-id"; + + + diff --git a/src/common/middleware/logging.middleware.spec.ts b/src/common/middleware/logging.middleware.spec.ts index 759184c..a10e182 100644 --- a/src/common/middleware/logging.middleware.spec.ts +++ b/src/common/middleware/logging.middleware.spec.ts @@ -464,3 +464,6 @@ describe("LoggingMiddleware – performance", () => { expect(avgMs).toBeLessThan(2); }); }); + + + diff --git a/src/common/middleware/logging.middleware.ts b/src/common/middleware/logging.middleware.ts index 3d2c178..551700f 100644 --- a/src/common/middleware/logging.middleware.ts +++ b/src/common/middleware/logging.middleware.ts @@ -152,3 +152,6 @@ export class LoggingMiddleware implements NestMiddleware { return contentLength > this.cfg.maxBodySize; } } + + + diff --git a/src/common/middleware/sentry.middleware.ts b/src/common/middleware/sentry.middleware.ts index 2c953b0..ccc00ad 100644 --- a/src/common/middleware/sentry.middleware.ts +++ b/src/common/middleware/sentry.middleware.ts @@ -25,3 +25,6 @@ export const sentryBreadcrumbMiddleware = ( next(); }; + + + diff --git a/src/common/pagination/cursor-pagination.dto.ts b/src/common/pagination/cursor-pagination.dto.ts index 19d20fa..7fc8d3a 100644 --- a/src/common/pagination/cursor-pagination.dto.ts +++ b/src/common/pagination/cursor-pagination.dto.ts @@ -34,3 +34,6 @@ export interface CursorOptions { orderBy: string; orderDirection: "ASC" | "DESC"; } + + + diff --git a/src/common/pagination/cursor-pagination.service.spec.ts b/src/common/pagination/cursor-pagination.service.spec.ts index 7d662af..90df2fc 100644 --- a/src/common/pagination/cursor-pagination.service.spec.ts +++ b/src/common/pagination/cursor-pagination.service.spec.ts @@ -212,3 +212,6 @@ describe("CursorPaginationService", () => { }); }); }); + + + diff --git a/src/common/pagination/cursor-pagination.service.ts b/src/common/pagination/cursor-pagination.service.ts index 38b6f9f..ae406c6 100644 --- a/src/common/pagination/cursor-pagination.service.ts +++ b/src/common/pagination/cursor-pagination.service.ts @@ -153,3 +153,6 @@ export class CursorPaginationService { } } } + + + diff --git a/src/common/pagination/pagination.module.ts b/src/common/pagination/pagination.module.ts index b54b0d8..e0ca3ae 100644 --- a/src/common/pagination/pagination.module.ts +++ b/src/common/pagination/pagination.module.ts @@ -6,3 +6,6 @@ import { CursorPaginationService } from "./cursor-pagination.service"; exports: [CursorPaginationService], }) export class PaginationModule {} + + + diff --git a/src/common/pipes/sanitize.pipe.ts b/src/common/pipes/sanitize.pipe.ts index b384cb7..9f87bf8 100644 --- a/src/common/pipes/sanitize.pipe.ts +++ b/src/common/pipes/sanitize.pipe.ts @@ -45,3 +45,6 @@ export class SanitizePipe implements PipeTransform { ); } } + + + diff --git a/src/common/throttler/sensitive-throttler.guard.spec.ts b/src/common/throttler/sensitive-throttler.guard.spec.ts index 47ba543..db1f672 100644 --- a/src/common/throttler/sensitive-throttler.guard.spec.ts +++ b/src/common/throttler/sensitive-throttler.guard.spec.ts @@ -80,3 +80,6 @@ describe("SensitiveThrottlerGuard", () => { }); }); }); + + + diff --git a/src/common/throttler/sensitive-throttler.guard.ts b/src/common/throttler/sensitive-throttler.guard.ts index 7dafc9b..4eade07 100644 --- a/src/common/throttler/sensitive-throttler.guard.ts +++ b/src/common/throttler/sensitive-throttler.guard.ts @@ -56,3 +56,6 @@ export class SensitiveThrottlerGuard extends ThrottlerGuard { return false; } } + + + diff --git a/src/config/cors.config.ts b/src/config/cors.config.ts index 2e0c010..11c0e28 100644 --- a/src/config/cors.config.ts +++ b/src/config/cors.config.ts @@ -22,3 +22,6 @@ export function createCorsConfig(configService: ConfigService): CorsOptions { maxAge: 3600, }; } + + + diff --git a/src/config/env.validation.ts b/src/config/env.validation.ts index 4016903..3e3557c 100644 --- a/src/config/env.validation.ts +++ b/src/config/env.validation.ts @@ -250,3 +250,6 @@ export class EnvironmentVariables { @Transform(({ value }) => value === "true") REFERRAL_ENABLE_VPN_DETECTION?: boolean = false; } + + + diff --git a/src/config/helmet.config.ts b/src/config/helmet.config.ts index fcef4b4..32ece08 100644 --- a/src/config/helmet.config.ts +++ b/src/config/helmet.config.ts @@ -21,3 +21,6 @@ export function createHelmetConfig(): HelmetOptions { }, }; } + + + diff --git a/src/config/logger.ts b/src/config/logger.ts index ec8e679..eb5539a 100644 --- a/src/config/logger.ts +++ b/src/config/logger.ts @@ -31,3 +31,6 @@ export const logger = pino({ export const createLogger = (context: Record) => { return logger.child(context); }; + + + diff --git a/src/config/metrics.ts b/src/config/metrics.ts index 21097c7..096bb11 100644 --- a/src/config/metrics.ts +++ b/src/config/metrics.ts @@ -96,3 +96,6 @@ export const queueLength = new client.Gauge({ labelNames: ["queue_name", "state"], registers: [register], }); + + + diff --git a/src/config/nest-pino-logger.ts b/src/config/nest-pino-logger.ts index f91e61c..63af924 100644 --- a/src/config/nest-pino-logger.ts +++ b/src/config/nest-pino-logger.ts @@ -46,3 +46,6 @@ export class PinoLogger implements LoggerService { logger[level](logMessage); } } + + + diff --git a/src/config/quota.config.ts b/src/config/quota.config.ts index 969f60c..7af6d70 100644 --- a/src/config/quota.config.ts +++ b/src/config/quota.config.ts @@ -136,4 +136,5 @@ export const QUOTA_LEVELS: Record = { }, }; -export const DEFAULT_QUOTA = QUOTA_LEVELS.free; \ No newline at end of file +export const DEFAULT_QUOTA = QUOTA_LEVELS.free; + diff --git a/src/config/sentry.ts b/src/config/sentry.ts index f09c29a..135f2a4 100644 --- a/src/config/sentry.ts +++ b/src/config/sentry.ts @@ -72,3 +72,6 @@ export const addBreadcrumb = (breadcrumb: Sentry.Breadcrumb) => { Sentry.addBreadcrumb(breadcrumb); } }; + + + diff --git a/src/config/swagger.config.ts b/src/config/swagger.config.ts index f2a9d13..37177b7 100644 --- a/src/config/swagger.config.ts +++ b/src/config/swagger.config.ts @@ -77,3 +77,6 @@ export function setupSwagger(app: INestApplication): void { }, }); } + + + diff --git a/src/config/tracing.ts b/src/config/tracing.ts index ce9104d..4318326 100644 --- a/src/config/tracing.ts +++ b/src/config/tracing.ts @@ -128,6 +128,7 @@ export const createSpan = async ( } }); }; + /** * Extract trace context from an incoming carrier (HTTP headers, WS handshake * headers, message metadata, etc.) and return an active context so that child @@ -147,4 +148,4 @@ export const injectContext = ( ) => { propagation.inject(ctx, carrier); return carrier; -}; \ No newline at end of file +}; diff --git a/src/core/auth/auth.module.ts b/src/core/auth/auth.module.ts index be0937d..d6715cd 100644 --- a/src/core/auth/auth.module.ts +++ b/src/core/auth/auth.module.ts @@ -148,3 +148,6 @@ export class AuthModule implements OnModuleInit { this.strategyRegistry.register(this.apiKeyStrategy); } } + + + diff --git a/src/core/auth/auth.service.spec.ts b/src/core/auth/auth.service.spec.ts index 3f482db..448b5fb 100644 --- a/src/core/auth/auth.service.spec.ts +++ b/src/core/auth/auth.service.spec.ts @@ -262,3 +262,6 @@ describe("AuthService", () => { }); }); }); + + + diff --git a/src/core/auth/challenge.service.ts b/src/core/auth/challenge.service.ts index 79819e7..74a81ab 100644 --- a/src/core/auth/challenge.service.ts +++ b/src/core/auth/challenge.service.ts @@ -61,3 +61,6 @@ export class ChallengeService { return match ? match[1] : null; } } + + + diff --git a/src/core/auth/decorators/allowed-strategies.decorator.ts b/src/core/auth/decorators/allowed-strategies.decorator.ts index 7b1e669..e589a8c 100644 --- a/src/core/auth/decorators/allowed-strategies.decorator.ts +++ b/src/core/auth/decorators/allowed-strategies.decorator.ts @@ -15,3 +15,6 @@ export const ALLOWED_STRATEGIES_KEY = "allowedStrategies"; */ export const AllowedStrategies = (...strategies: AuthType[]) => SetMetadata(ALLOWED_STRATEGIES_KEY, strategies); + + + diff --git a/src/core/auth/decorators/auth-type.decorator.ts b/src/core/auth/decorators/auth-type.decorator.ts index 3e88b8a..a3bfcf1 100644 --- a/src/core/auth/decorators/auth-type.decorator.ts +++ b/src/core/auth/decorators/auth-type.decorator.ts @@ -16,3 +16,6 @@ export const AuthType = createParamDecorator( return request.authType as AuthTypeEnum; }, ); + + + diff --git a/src/core/auth/decorators/current-user.decorator.ts b/src/core/auth/decorators/current-user.decorator.ts index b4b7bcc..ddddcbe 100644 --- a/src/core/auth/decorators/current-user.decorator.ts +++ b/src/core/auth/decorators/current-user.decorator.ts @@ -25,3 +25,6 @@ export const CurrentUser = createParamDecorator( return data ? user[data] : user; }, ); + + + diff --git a/src/core/auth/decorators/index.ts b/src/core/auth/decorators/index.ts index 429967a..1a0e553 100644 --- a/src/core/auth/decorators/index.ts +++ b/src/core/auth/decorators/index.ts @@ -1,3 +1,6 @@ export * from "./allowed-strategies.decorator"; export * from "./current-user.decorator"; export * from "./auth-type.decorator"; + + + diff --git a/src/core/auth/delegation.service.ts b/src/core/auth/delegation.service.ts index e982108..8ffb268 100644 --- a/src/core/auth/delegation.service.ts +++ b/src/core/auth/delegation.service.ts @@ -520,3 +520,6 @@ export class DelegationService { ); } } + + + diff --git a/src/core/auth/dto/auth.dto.ts b/src/core/auth/dto/auth.dto.ts index 990fcc3..09e6525 100644 --- a/src/core/auth/dto/auth.dto.ts +++ b/src/core/auth/dto/auth.dto.ts @@ -125,3 +125,6 @@ export class AuthStatusDto { }) user?: AuthUserDto; } + + + diff --git a/src/core/auth/dto/kyc.dto.ts b/src/core/auth/dto/kyc.dto.ts index 08ef93c..2adae00 100644 --- a/src/core/auth/dto/kyc.dto.ts +++ b/src/core/auth/dto/kyc.dto.ts @@ -21,3 +21,6 @@ export class RefreshTokenDto { @IsNotEmpty() refreshToken: string; } + + + diff --git a/src/core/auth/dto/link-email.dto.ts b/src/core/auth/dto/link-email.dto.ts index 8df0d0d..170d350 100644 --- a/src/core/auth/dto/link-email.dto.ts +++ b/src/core/auth/dto/link-email.dto.ts @@ -11,3 +11,6 @@ export class LinkEmailDto { @IsNotEmpty() email: string; } + + + diff --git a/src/core/auth/dto/link-wallet.dto.ts b/src/core/auth/dto/link-wallet.dto.ts index 2d26496..45105df 100644 --- a/src/core/auth/dto/link-wallet.dto.ts +++ b/src/core/auth/dto/link-wallet.dto.ts @@ -44,3 +44,6 @@ export class LinkWalletDto { @IsOptional() permissions?: string[]; } + + + diff --git a/src/core/auth/dto/recover-wallet.dto.ts b/src/core/auth/dto/recover-wallet.dto.ts index 98f79cb..e3a1a17 100644 --- a/src/core/auth/dto/recover-wallet.dto.ts +++ b/src/core/auth/dto/recover-wallet.dto.ts @@ -8,3 +8,6 @@ export class RecoverWalletDto { @Length(64, 64) recoveryToken: string; } + + + diff --git a/src/core/auth/dto/request-recovery.dto.ts b/src/core/auth/dto/request-recovery.dto.ts index 52348a4..29689d7 100644 --- a/src/core/auth/dto/request-recovery.dto.ts +++ b/src/core/auth/dto/request-recovery.dto.ts @@ -4,3 +4,6 @@ export class RequestRecoveryDto { @IsEmail() email: string; } + + + diff --git a/src/core/auth/dto/unlink-wallet.dto.ts b/src/core/auth/dto/unlink-wallet.dto.ts index e62eabe..a10dc5a 100644 --- a/src/core/auth/dto/unlink-wallet.dto.ts +++ b/src/core/auth/dto/unlink-wallet.dto.ts @@ -9,3 +9,6 @@ export class UnlinkWalletDto { @IsUUID() walletId: string; } + + + diff --git a/src/core/auth/dto/verify-email.dto.ts b/src/core/auth/dto/verify-email.dto.ts index 94b85d9..2a91f6f 100644 --- a/src/core/auth/dto/verify-email.dto.ts +++ b/src/core/auth/dto/verify-email.dto.ts @@ -12,3 +12,6 @@ export class VerifyEmailDto { @IsNotEmpty() token: string; } + + + diff --git a/src/core/auth/email-linking.service.ts b/src/core/auth/email-linking.service.ts index 1bcd8af..52ae59b 100644 --- a/src/core/auth/email-linking.service.ts +++ b/src/core/auth/email-linking.service.ts @@ -216,3 +216,6 @@ export class EmailLinkingService { }); } } + + + diff --git a/src/core/auth/email.service.ts b/src/core/auth/email.service.ts index d9be22a..028ca3f 100644 --- a/src/core/auth/email.service.ts +++ b/src/core/auth/email.service.ts @@ -316,3 +316,6 @@ export class EmailService { }; } } + + + diff --git a/src/core/auth/enhanced-auth.controller.ts b/src/core/auth/enhanced-auth.controller.ts index 0bf098d..096c6a5 100644 --- a/src/core/auth/enhanced-auth.controller.ts +++ b/src/core/auth/enhanced-auth.controller.ts @@ -246,3 +246,6 @@ export class EnhancedAuthController { return this.enhancedAuthService.getTwoFactorStatus(req.user.sub); } } + + + diff --git a/src/core/auth/enhanced-auth.service.spec.ts b/src/core/auth/enhanced-auth.service.spec.ts index 414d530..a05d51b 100644 --- a/src/core/auth/enhanced-auth.service.spec.ts +++ b/src/core/auth/enhanced-auth.service.spec.ts @@ -349,3 +349,6 @@ describe("EnhancedAuthService — 2FA", () => { }); }); }); + + + diff --git a/src/core/auth/entities/auth.entity.ts b/src/core/auth/entities/auth.entity.ts index 83d914b..75d0683 100644 --- a/src/core/auth/entities/auth.entity.ts +++ b/src/core/auth/entities/auth.entity.ts @@ -119,3 +119,6 @@ export class TwoFactorAuth { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/core/auth/entities/email-verification.entity.ts b/src/core/auth/entities/email-verification.entity.ts index 94cf411..c5fbce0 100644 --- a/src/core/auth/entities/email-verification.entity.ts +++ b/src/core/auth/entities/email-verification.entity.ts @@ -28,3 +28,6 @@ export class EmailVerification { @CreateDateColumn() createdAt: Date; } + + + diff --git a/src/core/auth/entities/wallet.entity.ts b/src/core/auth/entities/wallet.entity.ts index 10f8237..d26b414 100644 --- a/src/core/auth/entities/wallet.entity.ts +++ b/src/core/auth/entities/wallet.entity.ts @@ -165,3 +165,6 @@ export class Wallet { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/core/auth/guards/admin-two-factor.guard.spec.ts b/src/core/auth/guards/admin-two-factor.guard.spec.ts index 3773c47..8b3dc63 100644 --- a/src/core/auth/guards/admin-two-factor.guard.spec.ts +++ b/src/core/auth/guards/admin-two-factor.guard.spec.ts @@ -74,3 +74,6 @@ describe("AdminTwoFactorGuard", () => { expect(isTwoFactorEnabled).toHaveBeenCalledWith("admin-2"); }); }); + + + diff --git a/src/core/auth/guards/admin-two-factor.guard.ts b/src/core/auth/guards/admin-two-factor.guard.ts index 045f22a..70364a6 100644 --- a/src/core/auth/guards/admin-two-factor.guard.ts +++ b/src/core/auth/guards/admin-two-factor.guard.ts @@ -105,3 +105,6 @@ export class AdminTwoFactorGuard implements CanActivate { return null; } } + + + diff --git a/src/core/auth/guards/jwt-auth.guard.ts b/src/core/auth/guards/jwt-auth.guard.ts index 7367108..38af00a 100644 --- a/src/core/auth/guards/jwt-auth.guard.ts +++ b/src/core/auth/guards/jwt-auth.guard.ts @@ -1 +1,4 @@ export { JwtAuthGuard } from "../jwt.guard"; + + + diff --git a/src/core/auth/jwt.guard.ts b/src/core/auth/jwt.guard.ts index 2e81dba..84b854a 100644 --- a/src/core/auth/jwt.guard.ts +++ b/src/core/auth/jwt.guard.ts @@ -3,3 +3,6 @@ import { AuthGuard } from "@nestjs/passport"; @Injectable() export class JwtAuthGuard extends AuthGuard("jwt") {} + + + diff --git a/src/core/auth/kyc.guard.ts b/src/core/auth/kyc.guard.ts index 06c2967..3f13f75 100644 --- a/src/core/auth/kyc.guard.ts +++ b/src/core/auth/kyc.guard.ts @@ -24,3 +24,6 @@ export class KycGuard implements CanActivate { return user?.kycVerified === true; } } + + + diff --git a/src/core/auth/recovery.service.ts b/src/core/auth/recovery.service.ts index 94aebcf..15c36d5 100644 --- a/src/core/auth/recovery.service.ts +++ b/src/core/auth/recovery.service.ts @@ -72,3 +72,6 @@ export class RecoveryService { }; } } + + + diff --git a/src/core/auth/session-recovery.service.ts b/src/core/auth/session-recovery.service.ts index 4d92667..e05e14a 100644 --- a/src/core/auth/session-recovery.service.ts +++ b/src/core/auth/session-recovery.service.ts @@ -500,3 +500,6 @@ export class SessionRecoveryService { // In production, store this in audit log } } + + + diff --git a/src/core/auth/strategies/index.ts b/src/core/auth/strategies/index.ts index cabe639..715750e 100644 --- a/src/core/auth/strategies/index.ts +++ b/src/core/auth/strategies/index.ts @@ -9,3 +9,6 @@ export * from "./wallet/wallet.strategy"; export * from "./traditional/traditional.strategy"; export * from "./oauth/oauth.strategy"; export * from "./api-key/api-key.strategy"; + + + diff --git a/src/core/auth/strategies/strategy.registry.ts b/src/core/auth/strategies/strategy.registry.ts index daf9880..e7d9178 100644 --- a/src/core/auth/strategies/strategy.registry.ts +++ b/src/core/auth/strategies/strategy.registry.ts @@ -118,3 +118,6 @@ export class StrategyRegistry implements OnModuleInit { this.logger.log("All strategies cleared from registry"); } } + + + diff --git a/src/core/auth/strategy-auth.service.ts b/src/core/auth/strategy-auth.service.ts index e859423..8adcf0c 100644 --- a/src/core/auth/strategy-auth.service.ts +++ b/src/core/auth/strategy-auth.service.ts @@ -144,3 +144,6 @@ export class StrategyAuthService { return this.strategyRegistry.get(strategyName); } } + + + diff --git a/src/core/auth/token-blacklist.service.ts b/src/core/auth/token-blacklist.service.ts index 94500a4..f006d20 100644 --- a/src/core/auth/token-blacklist.service.ts +++ b/src/core/auth/token-blacklist.service.ts @@ -37,3 +37,6 @@ export class TokenBlacklistService { } } } + + + diff --git a/src/core/auth/wallet-auth.service.spec.ts b/src/core/auth/wallet-auth.service.spec.ts index 4b6c2fe..d7ab0e7 100644 --- a/src/core/auth/wallet-auth.service.spec.ts +++ b/src/core/auth/wallet-auth.service.spec.ts @@ -409,3 +409,6 @@ describe("WalletAuthService", () => { }); }); }); + + + diff --git a/src/core/profile/dto/create-profile.dto.ts b/src/core/profile/dto/create-profile.dto.ts index 2913518..6a90a2f 100644 --- a/src/core/profile/dto/create-profile.dto.ts +++ b/src/core/profile/dto/create-profile.dto.ts @@ -1 +1,4 @@ export class CreateProfileDto {} + + + diff --git a/src/core/profile/dto/update-profile.dto.ts b/src/core/profile/dto/update-profile.dto.ts index 2fe87cc..d03eed8 100644 --- a/src/core/profile/dto/update-profile.dto.ts +++ b/src/core/profile/dto/update-profile.dto.ts @@ -2,3 +2,6 @@ import { PartialType } from "@nestjs/mapped-types"; import { CreateProfileDto } from "./create-profile.dto"; export class UpdateProfileDto extends PartialType(CreateProfileDto) {} + + + diff --git a/src/core/profile/entities/profile.entity.ts b/src/core/profile/entities/profile.entity.ts index b4a8829..10442af 100644 --- a/src/core/profile/entities/profile.entity.ts +++ b/src/core/profile/entities/profile.entity.ts @@ -1 +1,4 @@ export class Profile {} + + + diff --git a/src/core/profile/profile.controller.ts b/src/core/profile/profile.controller.ts index b993c28..321f284 100644 --- a/src/core/profile/profile.controller.ts +++ b/src/core/profile/profile.controller.ts @@ -40,3 +40,6 @@ export class ProfileController { return this.profileService.remove(+id); } } + + + diff --git a/src/core/profile/profile.module.ts b/src/core/profile/profile.module.ts index 4f4c9af..30b89d1 100644 --- a/src/core/profile/profile.module.ts +++ b/src/core/profile/profile.module.ts @@ -7,3 +7,6 @@ import { ProfileController } from "./profile.controller"; providers: [ProfileService], }) export class ProfileModule {} + + + diff --git a/src/core/profile/profile.service.ts b/src/core/profile/profile.service.ts index 405afa7..1ef3e70 100644 --- a/src/core/profile/profile.service.ts +++ b/src/core/profile/profile.service.ts @@ -24,3 +24,6 @@ export class ProfileService { return `This action removes a #${id} profile`; } } + + + diff --git a/src/core/user/dto/create-user.dto.ts b/src/core/user/dto/create-user.dto.ts index 0311be1..a1cb0e8 100644 --- a/src/core/user/dto/create-user.dto.ts +++ b/src/core/user/dto/create-user.dto.ts @@ -1 +1,4 @@ export class CreateUserDto {} + + + diff --git a/src/core/user/dto/update-user.dto.ts b/src/core/user/dto/update-user.dto.ts index ad061f2..4459632 100644 --- a/src/core/user/dto/update-user.dto.ts +++ b/src/core/user/dto/update-user.dto.ts @@ -2,3 +2,6 @@ import { PartialType } from "@nestjs/mapped-types"; import { CreateUserDto } from "./create-user.dto"; export class UpdateUserDto extends PartialType(CreateUserDto) {} + + + diff --git a/src/core/user/user-role-separation.spec.ts b/src/core/user/user-role-separation.spec.ts index a9b0ea5..4b005e4 100644 --- a/src/core/user/user-role-separation.spec.ts +++ b/src/core/user/user-role-separation.spec.ts @@ -110,3 +110,6 @@ describe("UserService — role separation (Governance vs KYC)", () => { }); }); }); + + + diff --git a/src/core/user/user.controller.ts b/src/core/user/user.controller.ts index 99c68b3..d7ef899 100644 --- a/src/core/user/user.controller.ts +++ b/src/core/user/user.controller.ts @@ -40,3 +40,6 @@ export class UserController { return this.userService.remove(id); } } + + + diff --git a/src/core/user/user.module.ts b/src/core/user/user.module.ts index 2d82058..1bc69e3 100644 --- a/src/core/user/user.module.ts +++ b/src/core/user/user.module.ts @@ -11,3 +11,6 @@ import { UserController } from "./user.controller"; exports: [UserService], }) export class UserModule {} + + + diff --git a/src/core/user/user.service.ts b/src/core/user/user.service.ts index d0b42f9..fba53e3 100644 --- a/src/core/user/user.service.ts +++ b/src/core/user/user.service.ts @@ -81,3 +81,6 @@ export class UserService { } } } + + + diff --git a/src/dashboard/dashboard.controller.ts b/src/dashboard/dashboard.controller.ts index 74ab108..8129865 100644 --- a/src/dashboard/dashboard.controller.ts +++ b/src/dashboard/dashboard.controller.ts @@ -60,3 +60,6 @@ export class DashboardController { return this.dashboardService.getHealth(id); } } + + + diff --git a/src/dashboard/dashboard.module.ts b/src/dashboard/dashboard.module.ts index f1f4dc4..69b12ea 100644 --- a/src/dashboard/dashboard.module.ts +++ b/src/dashboard/dashboard.module.ts @@ -59,3 +59,6 @@ import { WsExceptionFilter } from "./websocket/filters/ws-exception.filter"; ], }) export class DashboardModule {} + + + diff --git a/src/dashboard/dashboard.service.ts b/src/dashboard/dashboard.service.ts index f0bd5bd..27c511e 100644 --- a/src/dashboard/dashboard.service.ts +++ b/src/dashboard/dashboard.service.ts @@ -81,3 +81,6 @@ export class DashboardService { }; } } + + + diff --git a/src/dashboard/dto/dashboard.dto.ts b/src/dashboard/dto/dashboard.dto.ts index 6f813ff..ae4f73b 100644 --- a/src/dashboard/dto/dashboard.dto.ts +++ b/src/dashboard/dto/dashboard.dto.ts @@ -20,3 +20,6 @@ export class TimeRangeDto { @IsEnum(TimeRange) timeRange?: TimeRange; } + + + diff --git a/src/dashboard/websocket/adapters/dashboard-ws-auth.adapter.ts b/src/dashboard/websocket/adapters/dashboard-ws-auth.adapter.ts index de183a9..9d4f77c 100644 --- a/src/dashboard/websocket/adapters/dashboard-ws-auth.adapter.ts +++ b/src/dashboard/websocket/adapters/dashboard-ws-auth.adapter.ts @@ -113,3 +113,6 @@ export function setupAdapter( ) { server.adapter = adapter; } + + + diff --git a/src/dashboard/websocket/dashboard.gateway.ts b/src/dashboard/websocket/dashboard.gateway.ts index a1d99a5..9b2dd1a 100644 --- a/src/dashboard/websocket/dashboard.gateway.ts +++ b/src/dashboard/websocket/dashboard.gateway.ts @@ -356,3 +356,6 @@ export class DashboardGateway }, 60000); } } + + + diff --git a/src/dashboard/websocket/filters/ws-exception.filter.ts b/src/dashboard/websocket/filters/ws-exception.filter.ts index 7342f57..5036ce5 100644 --- a/src/dashboard/websocket/filters/ws-exception.filter.ts +++ b/src/dashboard/websocket/filters/ws-exception.filter.ts @@ -56,3 +56,6 @@ export class WsExceptionFilter implements ExceptionFilter { client.emit(DashboardEvent.ERROR, errorResponse); } } + + + diff --git a/src/dashboard/websocket/index.ts b/src/dashboard/websocket/index.ts index 169586a..facad1f 100644 --- a/src/dashboard/websocket/index.ts +++ b/src/dashboard/websocket/index.ts @@ -59,3 +59,6 @@ export { ConnectionState, EventHandler, } from "./services/dashboard-client.service"; + + + diff --git a/src/dashboard/websocket/interfaces/websocket.interfaces.ts b/src/dashboard/websocket/interfaces/websocket.interfaces.ts index 74c3b19..e30b773 100644 --- a/src/dashboard/websocket/interfaces/websocket.interfaces.ts +++ b/src/dashboard/websocket/interfaces/websocket.interfaces.ts @@ -156,3 +156,6 @@ export interface EventBufferConfig { maxAge: number; // Maximum age of buffered events in ms flushInterval: number; // Interval to check for expired buffers } + + + diff --git a/src/dashboard/websocket/services/connection-manager.service.spec.ts b/src/dashboard/websocket/services/connection-manager.service.spec.ts index 2da9c08..438779f 100644 --- a/src/dashboard/websocket/services/connection-manager.service.spec.ts +++ b/src/dashboard/websocket/services/connection-manager.service.spec.ts @@ -284,3 +284,6 @@ describe("ConnectionManagerService", () => { }); }); }); + + + diff --git a/src/dashboard/websocket/services/connection-manager.service.ts b/src/dashboard/websocket/services/connection-manager.service.ts index 53dc445..07c88ed 100644 --- a/src/dashboard/websocket/services/connection-manager.service.ts +++ b/src/dashboard/websocket/services/connection-manager.service.ts @@ -259,3 +259,6 @@ export class ConnectionManagerService { } } } + + + diff --git a/src/dashboard/websocket/services/connection-pool.service.ts b/src/dashboard/websocket/services/connection-pool.service.ts index 1d488f6..2262ff9 100644 --- a/src/dashboard/websocket/services/connection-pool.service.ts +++ b/src/dashboard/websocket/services/connection-pool.service.ts @@ -420,3 +420,6 @@ export class ConnectionPoolService implements OnModuleDestroy { this.logger.log("Connection pool service shut down"); } } + + + diff --git a/src/dashboard/websocket/services/dashboard-client.service.ts b/src/dashboard/websocket/services/dashboard-client.service.ts index 12b28ad..20a57dc 100644 --- a/src/dashboard/websocket/services/dashboard-client.service.ts +++ b/src/dashboard/websocket/services/dashboard-client.service.ts @@ -476,3 +476,6 @@ export function createDashboardClient( ): DashboardClientService { return new DashboardClientService(config); } + + + diff --git a/src/dashboard/websocket/services/dashboard-metrics.service.ts b/src/dashboard/websocket/services/dashboard-metrics.service.ts index 35806cb..a4aae25 100644 --- a/src/dashboard/websocket/services/dashboard-metrics.service.ts +++ b/src/dashboard/websocket/services/dashboard-metrics.service.ts @@ -292,3 +292,6 @@ export class DashboardMetricsService { return register.contentType; } } + + + diff --git a/src/dashboard/websocket/services/event-buffer.service.spec.ts b/src/dashboard/websocket/services/event-buffer.service.spec.ts index 1df4145..9e3c70f 100644 --- a/src/dashboard/websocket/services/event-buffer.service.spec.ts +++ b/src/dashboard/websocket/services/event-buffer.service.spec.ts @@ -227,3 +227,6 @@ describe("EventBufferService", () => { }); }); }); + + + diff --git a/src/dashboard/websocket/services/event-buffer.service.ts b/src/dashboard/websocket/services/event-buffer.service.ts index 9f87b07..08805af 100644 --- a/src/dashboard/websocket/services/event-buffer.service.ts +++ b/src/dashboard/websocket/services/event-buffer.service.ts @@ -179,3 +179,6 @@ export class EventBufferService { return this.disconnectionTracker.get(userId); } } + + + diff --git a/src/dashboard/websocket/services/reconnection.service.spec.ts b/src/dashboard/websocket/services/reconnection.service.spec.ts index 6746296..20ae22c 100644 --- a/src/dashboard/websocket/services/reconnection.service.spec.ts +++ b/src/dashboard/websocket/services/reconnection.service.spec.ts @@ -220,3 +220,6 @@ describe("Exponential Backoff", () => { expect(currentDelay).toBe(30000); }); }); + + + diff --git a/src/dashboard/websocket/services/reconnection.service.ts b/src/dashboard/websocket/services/reconnection.service.ts index 6a6008f..ef2fc78 100644 --- a/src/dashboard/websocket/services/reconnection.service.ts +++ b/src/dashboard/websocket/services/reconnection.service.ts @@ -536,3 +536,6 @@ export class WebSocketClientManager { }); } } + + + diff --git a/src/dashboard/websocket/services/websocket-health.service.ts b/src/dashboard/websocket/services/websocket-health.service.ts index 4938311..6b7d9fd 100644 --- a/src/dashboard/websocket/services/websocket-health.service.ts +++ b/src/dashboard/websocket/services/websocket-health.service.ts @@ -115,3 +115,6 @@ export class WebSocketHealthService { }; } } + + + diff --git a/src/dashboard/websocket/websocket.stress.spec.ts b/src/dashboard/websocket/websocket.stress.spec.ts index 4c20ed6..7512956 100644 --- a/src/dashboard/websocket/websocket.stress.spec.ts +++ b/src/dashboard/websocket/websocket.stress.spec.ts @@ -543,3 +543,6 @@ describe("WebSocket Client Manager Tests", () => { }); }); }); + + + diff --git a/src/defi/defi.controller.ts b/src/defi/defi.controller.ts index f15c377..f5e5bb8 100644 --- a/src/defi/defi.controller.ts +++ b/src/defi/defi.controller.ts @@ -491,3 +491,6 @@ export class DeFiController { return this.stakingService.getStakingOpportunities(tokenList); } } + + + diff --git a/src/defi/defi.module.ts b/src/defi/defi.module.ts index 1e1f0f8..36750d1 100644 --- a/src/defi/defi.module.ts +++ b/src/defi/defi.module.ts @@ -142,3 +142,6 @@ export class DeFiModule implements OnModuleInit { }); } } + + + diff --git a/src/defi/dto/defi.dto.ts b/src/defi/dto/defi.dto.ts index 3d5de63..549e514 100644 --- a/src/defi/dto/defi.dto.ts +++ b/src/defi/dto/defi.dto.ts @@ -270,3 +270,6 @@ export class DeFiAnalyticsDto { risk_distribution: Record; performance_chart: Array<{ date: Date; value: number; apy: number }>; } + + + diff --git a/src/defi/dto/yield-strategy.dto.ts b/src/defi/dto/yield-strategy.dto.ts index 8cdc9a0..d0cc808 100644 --- a/src/defi/dto/yield-strategy.dto.ts +++ b/src/defi/dto/yield-strategy.dto.ts @@ -181,3 +181,6 @@ export class StrategyPerformanceResponseDto { period_start: Date; period_end: Date; } + + + diff --git a/src/defi/entities/defi-position.entity.ts b/src/defi/entities/defi-position.entity.ts index e00c8aa..77aa90b 100644 --- a/src/defi/entities/defi-position.entity.ts +++ b/src/defi/entities/defi-position.entity.ts @@ -148,3 +148,6 @@ export class DeFiPosition { @Column("timestamp", { nullable: true }) last_updated_on_chain: Date; } + + + diff --git a/src/defi/entities/defi-risk-assessment.entity.ts b/src/defi/entities/defi-risk-assessment.entity.ts index 4eecd58..1d05a15 100644 --- a/src/defi/entities/defi-risk-assessment.entity.ts +++ b/src/defi/entities/defi-risk-assessment.entity.ts @@ -88,3 +88,6 @@ export class DeFiRiskAssessment { @Column("timestamp", { nullable: true }) effective_until: Date; } + + + diff --git a/src/defi/entities/defi-transaction.entity.ts b/src/defi/entities/defi-transaction.entity.ts index 238aad0..cc2a362 100644 --- a/src/defi/entities/defi-transaction.entity.ts +++ b/src/defi/entities/defi-transaction.entity.ts @@ -100,3 +100,6 @@ export class DeFiTransaction { @Column("timestamp", { nullable: true }) executed_at: Date; } + + + diff --git a/src/defi/entities/defi-yield-record.entity.ts b/src/defi/entities/defi-yield-record.entity.ts index 4687227..c351ec2 100644 --- a/src/defi/entities/defi-yield-record.entity.ts +++ b/src/defi/entities/defi-yield-record.entity.ts @@ -50,3 +50,6 @@ export class DeFiYieldRecord { @Column("boolean", { default: false }) claimed: boolean; } + + + diff --git a/src/defi/entities/defi-yield-strategy.entity.ts b/src/defi/entities/defi-yield-strategy.entity.ts index b81005e..f52af43 100644 --- a/src/defi/entities/defi-yield-strategy.entity.ts +++ b/src/defi/entities/defi-yield-strategy.entity.ts @@ -124,3 +124,6 @@ export class DeFiYieldStrategy { @UpdateDateColumn() updated_at: Date; } + + + diff --git a/src/defi/protocols/aave.adapter.ts b/src/defi/protocols/aave.adapter.ts index 9e29ef3..e502730 100644 --- a/src/defi/protocols/aave.adapter.ts +++ b/src/defi/protocols/aave.adapter.ts @@ -536,3 +536,6 @@ export class AaveAdapter implements ProtocolAdapter { return prices[token] || 0; } } + + + diff --git a/src/defi/protocols/compound.adapter.ts b/src/defi/protocols/compound.adapter.ts index 330fe02..e9ea17a 100644 --- a/src/defi/protocols/compound.adapter.ts +++ b/src/defi/protocols/compound.adapter.ts @@ -351,3 +351,6 @@ export class CompoundAdapter implements ProtocolAdapter { return prices[token] || 0; } } + + + diff --git a/src/defi/protocols/protocol-adapter.interface.ts b/src/defi/protocols/protocol-adapter.interface.ts index b69f16c..59b6d14 100644 --- a/src/defi/protocols/protocol-adapter.interface.ts +++ b/src/defi/protocols/protocol-adapter.interface.ts @@ -149,3 +149,6 @@ export interface SwapRoute { priceImpact: number; fee: number; } + + + diff --git a/src/defi/protocols/protocol-registry.ts b/src/defi/protocols/protocol-registry.ts index 308fd9a..7aaddba 100644 --- a/src/defi/protocols/protocol-registry.ts +++ b/src/defi/protocols/protocol-registry.ts @@ -56,3 +56,6 @@ export class ProtocolRegistry { return supportingAdapters; } } + + + diff --git a/src/defi/services/position-tracking.service.ts b/src/defi/services/position-tracking.service.ts index f5ef487..aa4800d 100644 --- a/src/defi/services/position-tracking.service.ts +++ b/src/defi/services/position-tracking.service.ts @@ -593,3 +593,6 @@ export interface RiskPosition { riskLevel: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"; hoursToLiquidation?: number; } + + + diff --git a/src/defi/services/risk-assessment.service.ts b/src/defi/services/risk-assessment.service.ts index 542ff1d..31b2bc4 100644 --- a/src/defi/services/risk-assessment.service.ts +++ b/src/defi/services/risk-assessment.service.ts @@ -430,3 +430,6 @@ export interface RiskMonitoringResult { healthRating: string; }; } + + + diff --git a/src/defi/services/transaction-optimization.service.ts b/src/defi/services/transaction-optimization.service.ts index 794a0d4..7a5fcdb 100644 --- a/src/defi/services/transaction-optimization.service.ts +++ b/src/defi/services/transaction-optimization.service.ts @@ -523,3 +523,6 @@ export interface NetworkConditions { networkCongestion: "low" | "moderate" | "high"; avgBlockTime: number; } + + + diff --git a/src/defi/services/yield-optimization.service.ts b/src/defi/services/yield-optimization.service.ts index afaad4e..cd1b9ff 100644 --- a/src/defi/services/yield-optimization.service.ts +++ b/src/defi/services/yield-optimization.service.ts @@ -491,3 +491,6 @@ export interface CompoundingResult { value: number; }>; } + + + diff --git a/src/defi/trade-lock.service.ts b/src/defi/trade-lock.service.ts index a0f6d4c..dac8a66 100644 --- a/src/defi/trade-lock.service.ts +++ b/src/defi/trade-lock.service.ts @@ -144,3 +144,6 @@ export class TradeLockService { } } } + + + diff --git a/src/defi/trade.controller.ts b/src/defi/trade.controller.ts index 2d6842f..419058b 100644 --- a/src/defi/trade.controller.ts +++ b/src/defi/trade.controller.ts @@ -33,3 +33,6 @@ export class TradeController { }); } } + + + diff --git a/src/discovery/algorithms/agent-scoring.spec.ts b/src/discovery/algorithms/agent-scoring.spec.ts index 0fd238e..21bbf0f 100644 --- a/src/discovery/algorithms/agent-scoring.spec.ts +++ b/src/discovery/algorithms/agent-scoring.spec.ts @@ -163,3 +163,6 @@ describe("AgentScoring", () => { }); }); }); + + + diff --git a/src/discovery/algorithms/agent-scoring.ts b/src/discovery/algorithms/agent-scoring.ts index 07a6091..303f57d 100644 --- a/src/discovery/algorithms/agent-scoring.ts +++ b/src/discovery/algorithms/agent-scoring.ts @@ -187,3 +187,6 @@ export class AgentScoring { }); } } + + + diff --git a/src/growth/alerts/alerts.controller.ts b/src/growth/alerts/alerts.controller.ts index 87f69f1..ca32e8d 100644 --- a/src/growth/alerts/alerts.controller.ts +++ b/src/growth/alerts/alerts.controller.ts @@ -136,3 +136,6 @@ export class AlertsController { return this.alertsService.getPreference(userId); } } + + + diff --git a/src/growth/alerts/alerts.module.ts b/src/growth/alerts/alerts.module.ts index 4f321dd..21b1935 100644 --- a/src/growth/alerts/alerts.module.ts +++ b/src/growth/alerts/alerts.module.ts @@ -27,3 +27,6 @@ import { PortfolioAlertListener } from "./listeners/portfolio-alert.listener"; exports: [AlertsService, AlertDispatcherService, AlertEvaluationService], }) export class AlertsModule {} + + + diff --git a/src/growth/alerts/alerts.service.spec.ts b/src/growth/alerts/alerts.service.spec.ts index a6f5daf..d9d8659 100644 --- a/src/growth/alerts/alerts.service.spec.ts +++ b/src/growth/alerts/alerts.service.spec.ts @@ -504,3 +504,6 @@ describe("AlertsService", () => { }); }); }); + + + diff --git a/src/growth/alerts/alerts.service.ts b/src/growth/alerts/alerts.service.ts index 49d2e8e..ea312b8 100644 --- a/src/growth/alerts/alerts.service.ts +++ b/src/growth/alerts/alerts.service.ts @@ -287,3 +287,6 @@ export class AlertsService { await this.preferenceRepo.remove(pref); } } + + + diff --git a/src/growth/alerts/dto/alert-preference.dto.ts b/src/growth/alerts/dto/alert-preference.dto.ts index 7339278..5d6e3fd 100644 --- a/src/growth/alerts/dto/alert-preference.dto.ts +++ b/src/growth/alerts/dto/alert-preference.dto.ts @@ -80,3 +80,6 @@ export class UnsubscribeAlertDto { @IsString() userId: string; } + + + diff --git a/src/growth/alerts/dto/alert.dto.ts b/src/growth/alerts/dto/alert.dto.ts index f47e0bb..007fdae 100644 --- a/src/growth/alerts/dto/alert.dto.ts +++ b/src/growth/alerts/dto/alert.dto.ts @@ -99,3 +99,6 @@ export class CreatePerformanceAlertDto { @Min(0) cooldownSeconds?: number; } + + + diff --git a/src/growth/alerts/entities/alert-preference.entity.ts b/src/growth/alerts/entities/alert-preference.entity.ts index 8dcb162..a3901d2 100644 --- a/src/growth/alerts/entities/alert-preference.entity.ts +++ b/src/growth/alerts/entities/alert-preference.entity.ts @@ -47,3 +47,6 @@ export class AlertPreference { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/growth/alerts/entities/alert-trigger-log.entity.ts b/src/growth/alerts/entities/alert-trigger-log.entity.ts index 21b02ec..cfdd14c 100644 --- a/src/growth/alerts/entities/alert-trigger-log.entity.ts +++ b/src/growth/alerts/entities/alert-trigger-log.entity.ts @@ -26,3 +26,6 @@ export class AlertTriggerLog { @CreateDateColumn() triggeredAt: Date; } + + + diff --git a/src/growth/alerts/entities/alert.entity.ts b/src/growth/alerts/entities/alert.entity.ts index 4436882..b546c13 100644 --- a/src/growth/alerts/entities/alert.entity.ts +++ b/src/growth/alerts/entities/alert.entity.ts @@ -57,3 +57,6 @@ export class Alert { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/growth/alerts/listeners/portfolio-alert.listener.ts b/src/growth/alerts/listeners/portfolio-alert.listener.ts index a206067..eeb356a 100644 --- a/src/growth/alerts/listeners/portfolio-alert.listener.ts +++ b/src/growth/alerts/listeners/portfolio-alert.listener.ts @@ -55,3 +55,6 @@ export class PortfolioAlertListener { }); } } + + + diff --git a/src/growth/alerts/listeners/risk-alert.listener.ts b/src/growth/alerts/listeners/risk-alert.listener.ts index 0357318..3092c45 100644 --- a/src/growth/alerts/listeners/risk-alert.listener.ts +++ b/src/growth/alerts/listeners/risk-alert.listener.ts @@ -14,3 +14,6 @@ export class RiskAlertListener { }); } } + + + diff --git a/src/growth/alerts/services/alert-dispatcher.service.spec.ts b/src/growth/alerts/services/alert-dispatcher.service.spec.ts index fcc1a46..f6e7580 100644 --- a/src/growth/alerts/services/alert-dispatcher.service.spec.ts +++ b/src/growth/alerts/services/alert-dispatcher.service.spec.ts @@ -305,3 +305,6 @@ describe("AlertDispatcherService", () => { }); }); }); + + + diff --git a/src/growth/alerts/services/alert-dispatcher.service.ts b/src/growth/alerts/services/alert-dispatcher.service.ts index bc12147..517061f 100644 --- a/src/growth/alerts/services/alert-dispatcher.service.ts +++ b/src/growth/alerts/services/alert-dispatcher.service.ts @@ -225,3 +225,6 @@ export class AlertDispatcherService { return new Promise((resolve) => setTimeout(resolve, ms)); } } + + + diff --git a/src/growth/alerts/services/alert-evaluation.service.spec.ts b/src/growth/alerts/services/alert-evaluation.service.spec.ts index 417f10a..3dcd8aa 100644 --- a/src/growth/alerts/services/alert-evaluation.service.spec.ts +++ b/src/growth/alerts/services/alert-evaluation.service.spec.ts @@ -183,3 +183,6 @@ describe("AlertEvaluationService", () => { }); }); }); + + + diff --git a/src/growth/alerts/services/alert-evaluation.service.ts b/src/growth/alerts/services/alert-evaluation.service.ts index c90f04a..bbdf8f7 100644 --- a/src/growth/alerts/services/alert-evaluation.service.ts +++ b/src/growth/alerts/services/alert-evaluation.service.ts @@ -92,3 +92,6 @@ export class AlertEvaluationService { } } } + + + diff --git a/src/health/dto/health-response.dto.ts b/src/health/dto/health-response.dto.ts index fe7fdb3..39eb630 100644 --- a/src/health/dto/health-response.dto.ts +++ b/src/health/dto/health-response.dto.ts @@ -40,3 +40,6 @@ export class HealthResponseDto { }) components: Record; } + + + diff --git a/src/health/health.constants.ts b/src/health/health.constants.ts index 7f697cb..f73d8ed 100644 --- a/src/health/health.constants.ts +++ b/src/health/health.constants.ts @@ -1 +1,4 @@ export const HEALTH_REDIS_CLIENT = "HEALTH_REDIS_CLIENT"; + + + diff --git a/src/health/health.controller.spec.ts b/src/health/health.controller.spec.ts index 4d4d74d..264e415 100644 --- a/src/health/health.controller.spec.ts +++ b/src/health/health.controller.spec.ts @@ -160,3 +160,6 @@ describe("HealthController", () => { }); }); }); + + + diff --git a/src/health/health.controller.ts b/src/health/health.controller.ts index b689987..af5da32 100644 --- a/src/health/health.controller.ts +++ b/src/health/health.controller.ts @@ -95,3 +95,6 @@ export class HealthController { return result; } } + + + diff --git a/src/health/health.module.ts b/src/health/health.module.ts index 5728dee..de47a09 100644 --- a/src/health/health.module.ts +++ b/src/health/health.module.ts @@ -26,3 +26,6 @@ import { HEALTH_REDIS_CLIENT } from "./health.constants"; ], }) export class HealthModule {} + + + diff --git a/src/health/health.service.spec.ts b/src/health/health.service.spec.ts index 7d5fd91..3a437ab 100644 --- a/src/health/health.service.spec.ts +++ b/src/health/health.service.spec.ts @@ -203,3 +203,6 @@ describe("HealthService", () => { }); }); }); + + + diff --git a/src/health/health.service.ts b/src/health/health.service.ts index 1b551b8..912c87a 100644 --- a/src/health/health.service.ts +++ b/src/health/health.service.ts @@ -135,3 +135,6 @@ export class HealthService { ); } } + + + diff --git a/src/infrastructure/ai-compute/provider-failover.spec.ts b/src/infrastructure/ai-compute/provider-failover.spec.ts index 92047ed..f1bd67c 100644 --- a/src/infrastructure/ai-compute/provider-failover.spec.ts +++ b/src/infrastructure/ai-compute/provider-failover.spec.ts @@ -85,3 +85,6 @@ describe("ProviderFailover", () => { expect(Object.keys(m)).toHaveLength(3); }); }); + + + diff --git a/src/infrastructure/ai-compute/provider-failover.ts b/src/infrastructure/ai-compute/provider-failover.ts index fb27384..06da40e 100644 --- a/src/infrastructure/ai-compute/provider-failover.ts +++ b/src/infrastructure/ai-compute/provider-failover.ts @@ -183,3 +183,6 @@ export class ProviderFailover { return out; } } + + + diff --git a/src/infrastructure/audit/audit-log.service.ts b/src/infrastructure/audit/audit-log.service.ts index b2ba189..b8d55ab 100644 --- a/src/infrastructure/audit/audit-log.service.ts +++ b/src/infrastructure/audit/audit-log.service.ts @@ -189,3 +189,6 @@ export class AuditLogService { .execute(); } } + + + diff --git a/src/infrastructure/audit/audit.module.ts b/src/infrastructure/audit/audit.module.ts index 47732d4..5960fe3 100644 --- a/src/infrastructure/audit/audit.module.ts +++ b/src/infrastructure/audit/audit.module.ts @@ -22,3 +22,6 @@ import { AuditLogService } from "./audit-log.service"; exports: [TypeOrmModule, ProvenanceService, AuditLogService], }) export class AuditModule {} + + + diff --git a/src/infrastructure/audit/dto/create-provenance-record.dto.ts b/src/infrastructure/audit/dto/create-provenance-record.dto.ts index d07dc66..2aeade4 100644 --- a/src/infrastructure/audit/dto/create-provenance-record.dto.ts +++ b/src/infrastructure/audit/dto/create-provenance-record.dto.ts @@ -130,3 +130,6 @@ export class CreateProvenanceRecordDto { @IsString() userAgent?: string; } + + + diff --git a/src/infrastructure/audit/dto/provenance-response.dto.ts b/src/infrastructure/audit/dto/provenance-response.dto.ts index 4e1a9a5..bd05d4a 100644 --- a/src/infrastructure/audit/dto/provenance-response.dto.ts +++ b/src/infrastructure/audit/dto/provenance-response.dto.ts @@ -205,3 +205,6 @@ export class ProvenanceTimelineResponseDto { }) toDate: string; } + + + diff --git a/src/infrastructure/audit/dto/query-provenance.dto.ts b/src/infrastructure/audit/dto/query-provenance.dto.ts index 1642193..2e16029 100644 --- a/src/infrastructure/audit/dto/query-provenance.dto.ts +++ b/src/infrastructure/audit/dto/query-provenance.dto.ts @@ -132,3 +132,6 @@ export class ExportProvenanceDto { @IsString() format?: "json" | "csv" = "json"; } + + + diff --git a/src/infrastructure/audit/entities/agent-event.entity.ts b/src/infrastructure/audit/entities/agent-event.entity.ts index aeefc44..0e13b5d 100644 --- a/src/infrastructure/audit/entities/agent-event.entity.ts +++ b/src/infrastructure/audit/entities/agent-event.entity.ts @@ -91,3 +91,6 @@ export class AgentEvent { @Index() createdAt: Date; } + + + diff --git a/src/infrastructure/audit/entities/compute-result.entity.ts b/src/infrastructure/audit/entities/compute-result.entity.ts index 1486a02..ecc9ef9 100644 --- a/src/infrastructure/audit/entities/compute-result.entity.ts +++ b/src/infrastructure/audit/entities/compute-result.entity.ts @@ -130,3 +130,6 @@ export class ComputeResult { @UpdateDateColumn() updatedAt: Date; } + + + diff --git a/src/infrastructure/audit/entities/oracle-submission.entity.ts b/src/infrastructure/audit/entities/oracle-submission.entity.ts index 933faa8..ee6854a 100644 --- a/src/infrastructure/audit/entities/oracle-submission.entity.ts +++ b/src/infrastructure/audit/entities/oracle-submission.entity.ts @@ -144,3 +144,6 @@ export class OracleSubmission { @Index() expiresAt: Date | null; } + + + diff --git a/src/infrastructure/audit/entities/provenance-record.entity.ts b/src/infrastructure/audit/entities/provenance-record.entity.ts index f7dff4d..caf15ac 100644 --- a/src/infrastructure/audit/entities/provenance-record.entity.ts +++ b/src/infrastructure/audit/entities/provenance-record.entity.ts @@ -159,3 +159,6 @@ export class ProvenanceRecord { @Column({ type: "text", nullable: true }) userAgent: string | null; } + + + diff --git a/src/infrastructure/audit/guards/provenance-access.guard.ts b/src/infrastructure/audit/guards/provenance-access.guard.ts index 4ca7696..ce274dd 100644 --- a/src/infrastructure/audit/guards/provenance-access.guard.ts +++ b/src/infrastructure/audit/guards/provenance-access.guard.ts @@ -48,3 +48,6 @@ export class ProvenanceAccessGuard implements CanActivate { return true; } } + + + diff --git a/src/infrastructure/audit/provenance.controller.ts b/src/infrastructure/audit/provenance.controller.ts index abd3c58..95523ea 100644 --- a/src/infrastructure/audit/provenance.controller.ts +++ b/src/infrastructure/audit/provenance.controller.ts @@ -267,3 +267,6 @@ export class ProvenanceController { res.send(csv); } } + + + diff --git a/src/infrastructure/audit/provenance.service.ts b/src/infrastructure/audit/provenance.service.ts index 405367c..865fc7e 100644 --- a/src/infrastructure/audit/provenance.service.ts +++ b/src/infrastructure/audit/provenance.service.ts @@ -450,3 +450,6 @@ export class ProvenanceService { }; } } + + + diff --git a/src/investment/portfolio/algorithms/black-litterman.ts b/src/investment/portfolio/algorithms/black-litterman.ts index 75ee7c0..5aac924 100644 --- a/src/investment/portfolio/algorithms/black-litterman.ts +++ b/src/investment/portfolio/algorithms/black-litterman.ts @@ -153,3 +153,6 @@ export class BlackLittermanModel { return matrix.map((row) => row.map((val) => (1 / val) * 0.1)); } } + + + diff --git a/src/investment/portfolio/algorithms/constraint-optimizer.ts b/src/investment/portfolio/algorithms/constraint-optimizer.ts index aca53fb..1cb6915 100644 --- a/src/investment/portfolio/algorithms/constraint-optimizer.ts +++ b/src/investment/portfolio/algorithms/constraint-optimizer.ts @@ -133,3 +133,6 @@ export class ConstraintOptimizer { return w; } } + + + diff --git a/src/investment/portfolio/algorithms/modern-portfolio-theory.ts b/src/investment/portfolio/algorithms/modern-portfolio-theory.ts index 168eddf..d26c73b 100644 --- a/src/investment/portfolio/algorithms/modern-portfolio-theory.ts +++ b/src/investment/portfolio/algorithms/modern-portfolio-theory.ts @@ -482,3 +482,6 @@ export class ModernPortfolioTheory { } } } + + + diff --git a/src/investment/portfolio/algorithms/performance-calculations.spec.ts b/src/investment/portfolio/algorithms/performance-calculations.spec.ts index 76416e6..d3677c8 100644 --- a/src/investment/portfolio/algorithms/performance-calculations.spec.ts +++ b/src/investment/portfolio/algorithms/performance-calculations.spec.ts @@ -298,3 +298,6 @@ describe("PerformanceCalculations", () => { }); }); }); + + + diff --git a/src/investment/portfolio/algorithms/performance-calculations.ts b/src/investment/portfolio/algorithms/performance-calculations.ts index eaef23a..6802d94 100644 --- a/src/investment/portfolio/algorithms/performance-calculations.ts +++ b/src/investment/portfolio/algorithms/performance-calculations.ts @@ -309,3 +309,6 @@ export class PerformanceCalculations { }; } } + + + diff --git a/src/investment/portfolio/algorithms/portfolio-validation.spec.ts b/src/investment/portfolio/algorithms/portfolio-validation.spec.ts index 0c43db6..7d1a2c1 100644 --- a/src/investment/portfolio/algorithms/portfolio-validation.spec.ts +++ b/src/investment/portfolio/algorithms/portfolio-validation.spec.ts @@ -230,3 +230,6 @@ describe("PortfolioValidation", () => { }); }); }); + + + diff --git a/src/investment/portfolio/algorithms/portfolio-validation.ts b/src/investment/portfolio/algorithms/portfolio-validation.ts index ebe1d73..8c47e69 100644 --- a/src/investment/portfolio/algorithms/portfolio-validation.ts +++ b/src/investment/portfolio/algorithms/portfolio-validation.ts @@ -267,3 +267,6 @@ export class PortfolioValidation { return { ...result, issues, valid }; } } + + + diff --git a/src/investment/portfolio/controllers/transaction.controller.ts b/src/investment/portfolio/controllers/transaction.controller.ts deleted file mode 100644 index b49d720..0000000 --- a/src/investment/portfolio/controllers/transaction.controller.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { - Controller, - Post, - Body, - Get, - Query, - Param, - Patch, - Res, -} from "@nestjs/common"; -import { TradingTransactionService } from "../services/trading-transaction.service"; -import { - CreateTransactionDto, - FilterTransactionDto, -} from "../dto/transaction.dto"; -import { Response } from "express"; - -@Controller("portfolios/:portfolioId/transactions") -export class TransactionController { - constructor(private readonly transactionService: TradingTransactionService) {} - - @Post() - createTransaction(@Body() createTransactionDto: CreateTransactionDto) { - return this.transactionService.createTransaction(createTransactionDto); - } - - @Get() - getTransactions( - @Param("portfolioId") portfolioId: string, - @Query() filterDto: FilterTransactionDto, - ) { - return this.transactionService.getTransactions(portfolioId, filterDto); - } - - @Patch(":id/archive") - archiveTransaction(@Param("id") id: string) { - return this.transactionService.archiveTransaction(id); - } - - @Get("export") - async exportTransactions( - @Param("portfolioId") portfolioId: string, - @Query() filterDto: FilterTransactionDto, - @Res() res: Response, - ) { - const stream = await this.transactionService.exportTransactionsToCsv( - portfolioId, - filterDto, - ); - res.setHeader("Content-Type", "text/csv"); - res.setHeader( - "Content-Disposition", - "attachment; filename=transactions.csv", - ); - stream.pipe(res); - } - - @Get("assets/:assetId/cost-basis") - calculateCostBasis(@Param("assetId") assetId: string) { - return this.transactionService.calculateCostBasis(assetId); - } -} diff --git a/src/investment/portfolio/dto/api-error.dto.ts b/src/investment/portfolio/dto/api-error.dto.ts index a7fc7cc..90c0487 100644 --- a/src/investment/portfolio/dto/api-error.dto.ts +++ b/src/investment/portfolio/dto/api-error.dto.ts @@ -23,3 +23,6 @@ export class ApiErrorDto { @ApiProperty({ example: "/api/v1/portfolio/:id" }) path: string; } + + + diff --git a/src/investment/portfolio/dto/backtest.dto.ts b/src/investment/portfolio/dto/backtest.dto.ts index acc494c..286dc22 100644 --- a/src/investment/portfolio/dto/backtest.dto.ts +++ b/src/investment/portfolio/dto/backtest.dto.ts @@ -65,3 +65,6 @@ export class BacktestResultResponseDto { createdAt: Date; completedAt?: Date; } + + + diff --git a/src/investment/portfolio/dto/optimization.dto.ts b/src/investment/portfolio/dto/optimization.dto.ts index d214084..5a7dd25 100644 --- a/src/investment/portfolio/dto/optimization.dto.ts +++ b/src/investment/portfolio/dto/optimization.dto.ts @@ -82,3 +82,6 @@ export class OptimizationHistoryResponseDto { completedAt?: Date; implementedAt?: Date; } + + + diff --git a/src/investment/portfolio/dto/performance.dto.ts b/src/investment/portfolio/dto/performance.dto.ts index d685b21..c4e3651 100644 --- a/src/investment/portfolio/dto/performance.dto.ts +++ b/src/investment/portfolio/dto/performance.dto.ts @@ -177,3 +177,6 @@ export class ComparisonResponseDto { timestamp: Date; calculationDate: Date; } + + + diff --git a/src/investment/portfolio/dto/portfolio-asset.dto.ts b/src/investment/portfolio/dto/portfolio-asset.dto.ts index fdb7655..0fb2892 100644 --- a/src/investment/portfolio/dto/portfolio-asset.dto.ts +++ b/src/investment/portfolio/dto/portfolio-asset.dto.ts @@ -127,3 +127,6 @@ export class PortfolioAssetResponseDto { unrealizedGain?: number; updatedAt: Date; } + + + diff --git a/src/investment/portfolio/dto/portfolio-management.dto.ts b/src/investment/portfolio/dto/portfolio-management.dto.ts index 7698e28..9ce629e 100644 --- a/src/investment/portfolio/dto/portfolio-management.dto.ts +++ b/src/investment/portfolio/dto/portfolio-management.dto.ts @@ -137,3 +137,6 @@ export class PortfolioListResponseDto { @ApiProperty({ type: [PortfolioResponseDto] }) portfolios: PortfolioResponseDto[]; } + + + diff --git a/src/investment/portfolio/dto/portfolio.dto.ts b/src/investment/portfolio/dto/portfolio.dto.ts index 0c17e33..e96ef09 100644 --- a/src/investment/portfolio/dto/portfolio.dto.ts +++ b/src/investment/portfolio/dto/portfolio.dto.ts @@ -128,3 +128,6 @@ export class PortfolioResponseDto { createdAt: Date; updatedAt: Date; } + + + diff --git a/src/investment/portfolio/dto/risk-profile.dto.ts b/src/investment/portfolio/dto/risk-profile.dto.ts index cf44c0f..e307c81 100644 --- a/src/investment/portfolio/dto/risk-profile.dto.ts +++ b/src/investment/portfolio/dto/risk-profile.dto.ts @@ -134,3 +134,6 @@ export class RiskProfileResponseDto { createdAt: Date; updatedAt: Date; } + + + diff --git a/src/investment/portfolio/dto/transaction.dto.ts b/src/investment/portfolio/dto/transaction.dto.ts deleted file mode 100644 index defd7c7..0000000 --- a/src/investment/portfolio/dto/transaction.dto.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - IsEnum, - IsOptional, - IsDateString, - IsNumber, - Min, -} from "class-validator"; -import { - TransactionType, - TransactionStatus, -} from "../entities/transaction.entity"; - -export class CreateTransactionDto { - @IsEnum(TransactionType) - type: TransactionType; - - @IsDateString() - date: string; - - @IsNumber() - @Min(0) - amount: number; - - @IsOptional() - @IsNumber() - @Min(0) - price?: number; - - @IsOptional() - @IsNumber() - @Min(0) - fees?: number; - - @IsOptional() - @IsNumber() - @Min(0) - gasFees?: number; - - portfolioId: string; - - @IsOptional() - portfolioAssetId?: string; - - @IsOptional() - notes?: string; - - @IsOptional() - metadata?: Record; -} - -export class FilterTransactionDto { - @IsOptional() - @IsEnum(TransactionType) - type?: TransactionType; - - @IsOptional() - @IsDateString() - startDate?: string; - - @IsOptional() - @IsDateString() - endDate?: string; - - @IsOptional() - @IsEnum(TransactionStatus) - status?: TransactionStatus; -} diff --git a/src/investment/portfolio/entities/backtest-result.entity.ts b/src/investment/portfolio/entities/backtest-result.entity.ts index 3d24761..00e6f5e 100644 --- a/src/investment/portfolio/entities/backtest-result.entity.ts +++ b/src/investment/portfolio/entities/backtest-result.entity.ts @@ -191,3 +191,6 @@ export class BacktestResult { @Column("uuid") userId: string; } + + + diff --git a/src/investment/portfolio/entities/optimization-history.entity.ts b/src/investment/portfolio/entities/optimization-history.entity.ts index 0d95ea8..2ca7555 100644 --- a/src/investment/portfolio/entities/optimization-history.entity.ts +++ b/src/investment/portfolio/entities/optimization-history.entity.ts @@ -142,3 +142,6 @@ export class OptimizationHistory { @Column("uuid") portfolioId: string; } + + + diff --git a/src/investment/portfolio/entities/performance-metric.entity.ts b/src/investment/portfolio/entities/performance-metric.entity.ts index 09b4496..407f25b 100644 --- a/src/investment/portfolio/entities/performance-metric.entity.ts +++ b/src/investment/portfolio/entities/performance-metric.entity.ts @@ -131,3 +131,6 @@ export class PerformanceMetric { @Column("uuid") portfolioId: string; } + + + diff --git a/src/investment/portfolio/entities/portfolio-asset.entity.ts b/src/investment/portfolio/entities/portfolio-asset.entity.ts index 1282a03..75bea9b 100644 --- a/src/investment/portfolio/entities/portfolio-asset.entity.ts +++ b/src/investment/portfolio/entities/portfolio-asset.entity.ts @@ -133,3 +133,6 @@ export class PortfolioAsset { @Column("uuid") portfolioId: string; } + + + diff --git a/src/investment/portfolio/entities/portfolio.entity.ts b/src/investment/portfolio/entities/portfolio.entity.ts index 397ef36..8515d8e 100644 --- a/src/investment/portfolio/entities/portfolio.entity.ts +++ b/src/investment/portfolio/entities/portfolio.entity.ts @@ -142,3 +142,6 @@ export class Portfolio { }) performanceMetrics: PerformanceMetric[]; } + + + diff --git a/src/investment/portfolio/entities/rebalancing-event.entity.ts b/src/investment/portfolio/entities/rebalancing-event.entity.ts index fb95a8a..bdd488f 100644 --- a/src/investment/portfolio/entities/rebalancing-event.entity.ts +++ b/src/investment/portfolio/entities/rebalancing-event.entity.ts @@ -125,3 +125,6 @@ export class RebalancingEvent { @Column("uuid") portfolioId: string; } + + + diff --git a/src/investment/portfolio/entities/risk-profile.entity.ts b/src/investment/portfolio/entities/risk-profile.entity.ts index 78e5ac0..4a6da11 100644 --- a/src/investment/portfolio/entities/risk-profile.entity.ts +++ b/src/investment/portfolio/entities/risk-profile.entity.ts @@ -138,3 +138,6 @@ export class RiskProfile { @Column("uuid") userId: string; } + + + diff --git a/src/investment/portfolio/entities/transaction.entity.ts b/src/investment/portfolio/entities/transaction.entity.ts index b44823b..255e8d7 100644 --- a/src/investment/portfolio/entities/transaction.entity.ts +++ b/src/investment/portfolio/entities/transaction.entity.ts @@ -22,16 +22,9 @@ export enum TransactionType { REBALANCE = "rebalance", DIVIDEND = "dividend", INTEREST = "interest", - STAKE = "stake", - UNSTAKE = "unstake", OTHER = "other", } -export enum TransactionStatus { - ACTIVE = "active", - ARCHIVED = "archived", -} - @Entity("transactions") @Index(["portfolioId", "createdAt"]) @Index(["portfolioId", "type"]) @@ -59,15 +52,6 @@ export class Transaction { @Column({ type: "decimal", precision: 18, scale: 2, nullable: true }) fees: number; - @Column({ - type: "decimal", - precision: 18, - scale: 8, - nullable: true, - comment: "Gas fees, specific to blockchain transactions", - }) - gasFees: number; - @Column({ type: "enum", enum: Chain, @@ -81,13 +65,6 @@ export class Transaction { @Column({ type: "jsonb", nullable: true }) metadata: Record; - @Column({ - type: "enum", - enum: TransactionStatus, - default: TransactionStatus.ACTIVE, - }) - status: TransactionStatus; - @CreateDateColumn() createdAt: Date; @@ -108,3 +85,6 @@ export class Transaction { @Column("uuid", { nullable: true }) portfolioAssetId: string | null; } + + + diff --git a/src/investment/portfolio/guards/portfolio-owner.guard.ts b/src/investment/portfolio/guards/portfolio-owner.guard.ts index a7f11b9..5c87efb 100644 --- a/src/investment/portfolio/guards/portfolio-owner.guard.ts +++ b/src/investment/portfolio/guards/portfolio-owner.guard.ts @@ -49,3 +49,6 @@ export class PortfolioOwnerGuard implements CanActivate { return true; } } + + + diff --git a/src/investment/portfolio/ml-models/predictor.ts b/src/investment/portfolio/ml-models/predictor.ts index e3c0eec..a3c86a5 100644 --- a/src/investment/portfolio/ml-models/predictor.ts +++ b/src/investment/portfolio/ml-models/predictor.ts @@ -437,3 +437,6 @@ export function calculateConfidence(metrics: TrainingMetrics): number { return (r2Confidence + mapeConfidence) / 2; } + + + diff --git a/src/investment/portfolio/portfolio-management.controller.ts b/src/investment/portfolio/portfolio-management.controller.ts index 08d08c2..028856e 100644 --- a/src/investment/portfolio/portfolio-management.controller.ts +++ b/src/investment/portfolio/portfolio-management.controller.ts @@ -157,3 +157,6 @@ export class PortfolioManagementController { return this.portfolioService.archivePortfolio(id, PortfolioStatus.ARCHIVED); } } + + + diff --git a/src/investment/portfolio/portfolio.module.ts b/src/investment/portfolio/portfolio.module.ts index 39959c5..3a50228 100644 --- a/src/investment/portfolio/portfolio.module.ts +++ b/src/investment/portfolio/portfolio.module.ts @@ -32,7 +32,6 @@ import { RebalancingProcessor } from "./processors/rebalancing.processor"; // Controllers import { PortfolioController } from "./portfolio.controller"; import { PortfolioManagementController } from "./portfolio-management.controller"; -import { TransactionController } from "./controllers/transaction.controller"; import { PortfolioOwnerGuard } from "./guards/portfolio-owner.guard"; @Module({ @@ -79,11 +78,7 @@ import { PortfolioOwnerGuard } from "./guards/portfolio-owner.guard"; PortfolioOwnerGuard, RebalancingProcessor, ], - controllers: [ - PortfolioController, - PortfolioManagementController, - TransactionController, - ], + controllers: [PortfolioController, PortfolioManagementController], exports: [ PortfolioService, diff --git a/src/investment/portfolio/services/backtesting.service.ts b/src/investment/portfolio/services/backtesting.service.ts index a5cb4de..eb280b1 100644 --- a/src/investment/portfolio/services/backtesting.service.ts +++ b/src/investment/portfolio/services/backtesting.service.ts @@ -352,3 +352,6 @@ export class BacktestingService { }; } } + + + diff --git a/src/investment/portfolio/services/ml-prediction.service.ts b/src/investment/portfolio/services/ml-prediction.service.ts index b8779de..150bbf1 100644 --- a/src/investment/portfolio/services/ml-prediction.service.ts +++ b/src/investment/portfolio/services/ml-prediction.service.ts @@ -180,3 +180,6 @@ export class MLPredictionService { }; } } + + + diff --git a/src/investment/portfolio/services/performance-analytics.service.spec.ts b/src/investment/portfolio/services/performance-analytics.service.spec.ts index 1166834..d328617 100644 --- a/src/investment/portfolio/services/performance-analytics.service.spec.ts +++ b/src/investment/portfolio/services/performance-analytics.service.spec.ts @@ -352,3 +352,6 @@ describe("PerformanceAnalyticsService", () => { }); }); }); + + + diff --git a/src/investment/portfolio/services/performance-analytics.service.ts b/src/investment/portfolio/services/performance-analytics.service.ts index b30b66a..7df15a3 100644 --- a/src/investment/portfolio/services/performance-analytics.service.ts +++ b/src/investment/portfolio/services/performance-analytics.service.ts @@ -611,3 +611,6 @@ export class PerformanceAnalyticsService { }; } } + + + diff --git a/src/investment/portfolio/services/portfolio-constraint.service.spec.ts b/src/investment/portfolio/services/portfolio-constraint.service.spec.ts index f53ac98..9b2c41f 100644 --- a/src/investment/portfolio/services/portfolio-constraint.service.spec.ts +++ b/src/investment/portfolio/services/portfolio-constraint.service.spec.ts @@ -246,3 +246,6 @@ describe("PortfolioConstraintService", () => { ).toBe(true); }); }); + + + diff --git a/src/investment/portfolio/services/portfolio-constraint.service.ts b/src/investment/portfolio/services/portfolio-constraint.service.ts index 5ae4859..de678cc 100644 --- a/src/investment/portfolio/services/portfolio-constraint.service.ts +++ b/src/investment/portfolio/services/portfolio-constraint.service.ts @@ -281,3 +281,6 @@ export class PortfolioConstraintService { return maxCategoryWeight > 0.5 ? (maxCategoryWeight - 0.5) * 30 : 0; } } + + + diff --git a/src/investment/portfolio/services/portfolio.service.ts b/src/investment/portfolio/services/portfolio.service.ts index 1c7188e..f08273b 100644 --- a/src/investment/portfolio/services/portfolio.service.ts +++ b/src/investment/portfolio/services/portfolio.service.ts @@ -650,3 +650,6 @@ export class PortfolioService { }); } } + + + diff --git a/src/investment/portfolio/services/trading-transaction.service.ts b/src/investment/portfolio/services/trading-transaction.service.ts index 40026f8..febc992 100644 --- a/src/investment/portfolio/services/trading-transaction.service.ts +++ b/src/investment/portfolio/services/trading-transaction.service.ts @@ -1,192 +1,23 @@ -import { Injectable, Logger, NotFoundException } from "@nestjs/common"; -import { InjectRepository } from "@nestjs/typeorm"; -import { - Repository, - Between, - MoreThanOrEqual, - LessThanOrEqual, - FindOptionsWhere, -} from "typeorm"; -import { - Transaction, - TransactionStatus, - TransactionType, -} from "../entities/transaction.entity"; -import { - CreateTransactionDto, - FilterTransactionDto, -} from "../dto/transaction.dto"; -import { PortfolioAsset } from "../entities/portfolio-asset.entity"; -import { Portfolio } from "../entities/portfolio.entity"; -import * as fastcsv from "fast-csv"; -import { Readable } from "stream"; +import { Injectable, Logger } from "@nestjs/common"; @Injectable() export class TradingTransactionService { private readonly logger = new Logger(TradingTransactionService.name); - constructor( - @InjectRepository(Transaction) - private readonly transactionRepository: Repository, - @InjectRepository(Portfolio) - private readonly portfolioRepository: Repository, - @InjectRepository(PortfolioAsset) - private readonly portfolioAssetRepository: Repository, - ) {} - - async createTransaction( - createTransactionDto: CreateTransactionDto, - ): Promise { - const { portfolioId, portfolioAssetId, ...transactionData } = - createTransactionDto; - - const portfolio = await this.portfolioRepository.findOne({ - where: { id: portfolioId }, - }); - if (!portfolio) { - throw new NotFoundException(`Portfolio with ID ${portfolioId} not found`); - } - - let portfolioAsset: PortfolioAsset | null = null; - if (portfolioAssetId) { - portfolioAsset = await this.portfolioAssetRepository.findOne({ - where: { id: portfolioAssetId }, - }); - if (!portfolioAsset) { - throw new NotFoundException( - `PortfolioAsset with ID ${portfolioAssetId} not found`, - ); - } - } - - const transaction = this.transactionRepository.create({ - ...transactionData, - portfolio, - portfolioAsset, - }); - - await this.validateTransaction(transaction); - - return this.transactionRepository.save(transaction); - } - - async getTransactions( - portfolioId: string, - filterDto: FilterTransactionDto, - ): Promise { - const { type, startDate, endDate, status } = filterDto; - - const where: FindOptionsWhere = { portfolioId }; - - if (type) { - where.type = type; - } - - if (startDate && endDate) { - where.date = Between(new Date(startDate), new Date(endDate)); - } else if (startDate) { - where.date = MoreThanOrEqual(new Date(startDate)); - } else if (endDate) { - where.date = LessThanOrEqual(new Date(endDate)); - } - - if (status) { - where.status = status; - } else { - where.status = TransactionStatus.ACTIVE; - } - - return this.transactionRepository.find({ - where, - order: { date: "DESC" }, - }); - } - - async archiveTransaction(id: string): Promise { - const transaction = await this.transactionRepository.findOne({ - where: { id }, - }); - if (!transaction) { - throw new NotFoundException(`Transaction with ID ${id} not found`); - } - - transaction.status = TransactionStatus.ARCHIVED; - return this.transactionRepository.save(transaction); - } - - async exportTransactionsToCsv( - portfolioId: string, - filterDto: FilterTransactionDto, - ): Promise { - const transactions = await this.getTransactions(portfolioId, filterDto); - return fastcsv.write(transactions, { headers: true }); - } - - async calculateCostBasis(portfolioAssetId: string): Promise<{ - averageCost: number; - totalCost: number; - totalQuantity: number; - }> { - const transactions = await this.transactionRepository.find({ - where: { - portfolioAssetId, - type: TransactionType.BUY, - status: TransactionStatus.ACTIVE, - }, - }); - - let totalCost = 0; - let totalQuantity = 0; - - for (const transaction of transactions) { - totalCost += transaction.amount * transaction.price; - totalQuantity += transaction.amount; - } - - const averageCost = totalQuantity > 0 ? totalCost / totalQuantity : 0; - - return { averageCost, totalCost, totalQuantity }; - } - async executeTrade( portfolioId: string, ticker: string, action: "buy" | "sell", quantity: number, price: number, - ): Promise { - const portfolioAsset = await this.portfolioAssetRepository.findOne({ - where: { portfolioId, ticker }, - }); - if (!portfolioAsset) { - throw new NotFoundException( - `Asset with ticker ${ticker} not found in portfolio ${portfolioId}`, - ); - } + ): Promise { + this.logger.log( + `Executing ${action} trade for ${quantity} of ${ticker} at $${price} for portfolio ${portfolioId}`, + ); + // TODO: Implement actual trade execution logic here + return Promise.resolve(); + } +} - const createTransactionDto: CreateTransactionDto = { - portfolioId, - portfolioAssetId: portfolioAsset.id, - type: action === "buy" ? TransactionType.BUY : TransactionType.SELL, - amount: quantity, - price: price, - date: new Date().toISOString(), - }; - return this.createTransaction(createTransactionDto); - } - private async validateTransaction(transaction: Transaction): Promise { - if ( - transaction.type === TransactionType.SELL || - transaction.type === TransactionType.UNSTAKE - ) { - const { totalQuantity } = await this.calculateCostBasis( - transaction.portfolioAssetId, - ); - if (transaction.amount > totalQuantity) { - throw new Error("Insufficient balance for this transaction"); - } - } - } -} diff --git a/src/investment/risk-management/circuit-breaker.service.spec.ts b/src/investment/risk-management/circuit-breaker.service.spec.ts index 3c714fc..fe5984d 100644 --- a/src/investment/risk-management/circuit-breaker.service.spec.ts +++ b/src/investment/risk-management/circuit-breaker.service.spec.ts @@ -174,3 +174,6 @@ describe("CircuitBreakerService", () => { }); }); }); + + + diff --git a/src/investment/risk-management/circuit-breaker.service.ts b/src/investment/risk-management/circuit-breaker.service.ts index 74305e3..7db5542 100644 --- a/src/investment/risk-management/circuit-breaker.service.ts +++ b/src/investment/risk-management/circuit-breaker.service.ts @@ -215,3 +215,6 @@ export class CircuitBreakerService { } } } + + + diff --git a/src/investment/risk-management/dto/risk.dto.ts b/src/investment/risk-management/dto/risk.dto.ts index 22cc3c9..901c7e3 100644 --- a/src/investment/risk-management/dto/risk.dto.ts +++ b/src/investment/risk-management/dto/risk.dto.ts @@ -85,3 +85,6 @@ export class PositionSizeDto { @Min(0) volatility: number; } + + + diff --git a/src/investment/risk-management/risk-management.controller.ts b/src/investment/risk-management/risk-management.controller.ts index 8bcf2b0..0f33871 100644 --- a/src/investment/risk-management/risk-management.controller.ts +++ b/src/investment/risk-management/risk-management.controller.ts @@ -112,3 +112,6 @@ export class RiskManagementController { return { triggered, asset, userId }; } } + + + diff --git a/src/investment/risk-management/risk-management.health.ts b/src/investment/risk-management/risk-management.health.ts index ba6ff3d..fb5dc93 100644 --- a/src/investment/risk-management/risk-management.health.ts +++ b/src/investment/risk-management/risk-management.health.ts @@ -40,3 +40,6 @@ export class RiskManagementHealthIndicator extends HealthIndicator { ); } } + + + diff --git a/src/investment/risk-management/risk-management.module.ts b/src/investment/risk-management/risk-management.module.ts index 0040ca1..c6a9524 100644 --- a/src/investment/risk-management/risk-management.module.ts +++ b/src/investment/risk-management/risk-management.module.ts @@ -20,3 +20,6 @@ import { RiskManagementHealthIndicator } from "./risk-management.health"; ], }) export class RiskManagementModule {} + + + diff --git a/src/investment/risk-management/risk-management.service.ts b/src/investment/risk-management/risk-management.service.ts index e4563d2..5b9b6c9 100644 --- a/src/investment/risk-management/risk-management.service.ts +++ b/src/investment/risk-management/risk-management.service.ts @@ -296,3 +296,6 @@ export class RiskManagementService { return alerts; } } + + + diff --git a/src/main.ts b/src/main.ts index afd202c..6f18c7b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -166,3 +166,6 @@ process.on("unhandledRejection", (reason: any) => { logger.error({ error, stack: error.stack }, "Unhandled Rejection"); process.exit(1); }); + + + diff --git a/src/observability/database-timing.interceptor.ts b/src/observability/database-timing.interceptor.ts index dc77920..e6003c3 100644 --- a/src/observability/database-timing.interceptor.ts +++ b/src/observability/database-timing.interceptor.ts @@ -38,3 +38,6 @@ export class DatabaseTimingInterceptor implements NestInterceptor { return next.handle(); } } + + + diff --git a/src/observability/monitoring-dashboard.spec.ts b/src/observability/monitoring-dashboard.spec.ts index 4bd853b..cfa6575 100644 --- a/src/observability/monitoring-dashboard.spec.ts +++ b/src/observability/monitoring-dashboard.spec.ts @@ -144,3 +144,6 @@ describe("Grafana application-overview dashboard (issue #25)", () => { expect(joined).toContain("histogram_quantile(0.99"); }); }); + + + diff --git a/src/observability/observability.controller.spec.ts b/src/observability/observability.controller.spec.ts index ea8393e..157be27 100644 --- a/src/observability/observability.controller.spec.ts +++ b/src/observability/observability.controller.spec.ts @@ -86,3 +86,6 @@ describe("ObservabilityController - Prometheus /metrics endpoint (issue #25)", ( ); }); }); + + + diff --git a/src/observability/observability.controller.ts b/src/observability/observability.controller.ts index 3ec1a3a..8151bcc 100644 --- a/src/observability/observability.controller.ts +++ b/src/observability/observability.controller.ts @@ -131,3 +131,6 @@ export class ObservabilityController { return register.metrics(); } } + + + diff --git a/src/observability/observability.module.ts b/src/observability/observability.module.ts index e4bec5d..c56687f 100644 --- a/src/observability/observability.module.ts +++ b/src/observability/observability.module.ts @@ -35,3 +35,6 @@ export class ObservabilityModule implements NestModule { consumer.apply(RequestTimingMiddleware).forRoutes("*"); } } + + + diff --git a/src/observability/performance-baseline.service.ts b/src/observability/performance-baseline.service.ts index 6d6c2b3..6861978 100644 --- a/src/observability/performance-baseline.service.ts +++ b/src/observability/performance-baseline.service.ts @@ -218,3 +218,6 @@ export class PerformanceBaselineService { this.logger.log("Performance baselines have been reset"); } } + + + diff --git a/src/observability/profiling.controller.ts b/src/observability/profiling.controller.ts index 8446ac3..cf64ec6 100644 --- a/src/observability/profiling.controller.ts +++ b/src/observability/profiling.controller.ts @@ -129,3 +129,6 @@ export class ProfilingController { return this.profilingService.checkMemoryHealth(); } } + + + diff --git a/src/observability/profiling.service.ts b/src/observability/profiling.service.ts index 0213e98..3cdd919 100644 --- a/src/observability/profiling.service.ts +++ b/src/observability/profiling.service.ts @@ -267,3 +267,6 @@ export class ProfilingService { }; } } + + + diff --git a/src/observability/request-timing.middleware.spec.ts b/src/observability/request-timing.middleware.spec.ts index 772c583..aa6aacc 100644 --- a/src/observability/request-timing.middleware.spec.ts +++ b/src/observability/request-timing.middleware.spec.ts @@ -194,3 +194,6 @@ describe("RequestTimingMiddleware Prometheus integration (issue #25)", () => { expect(remaining).toBe(0); }); }); + + + diff --git a/src/observability/request-timing.middleware.ts b/src/observability/request-timing.middleware.ts index 5f13734..a064c49 100644 --- a/src/observability/request-timing.middleware.ts +++ b/src/observability/request-timing.middleware.ts @@ -273,3 +273,6 @@ export class RequestTimingMiddleware implements NestMiddleware { return Array.from(this.activeRequests.values()); } } + + + diff --git a/src/portfolio/controllers/portfolio.controller.ts b/src/portfolio/controllers/portfolio.controller.ts index 79ec5ea..197a756 100644 --- a/src/portfolio/controllers/portfolio.controller.ts +++ b/src/portfolio/controllers/portfolio.controller.ts @@ -36,3 +36,6 @@ export class PortfolioController { ); } } + + + diff --git a/src/portfolio/portfolio.module.ts b/src/portfolio/portfolio.module.ts index be0d161..c7c51dc 100644 --- a/src/portfolio/portfolio.module.ts +++ b/src/portfolio/portfolio.module.ts @@ -7,3 +7,6 @@ import { PortfolioController } from "./controllers/portfolio.controller"; providers: [RebalancingService], }) export class PortfolioModule {} + + + diff --git a/src/portfolio/services/rebalancing.service.ts b/src/portfolio/services/rebalancing.service.ts index a69dc6d..f6de75f 100644 --- a/src/portfolio/services/rebalancing.service.ts +++ b/src/portfolio/services/rebalancing.service.ts @@ -50,3 +50,6 @@ export class RebalancingService { return { success: true }; } } + + + diff --git a/src/profiling/profiling.controller.ts b/src/profiling/profiling.controller.ts index c9e8a8e..dadf223 100644 --- a/src/profiling/profiling.controller.ts +++ b/src/profiling/profiling.controller.ts @@ -278,3 +278,6 @@ export class ProfilingController { res.send(html); } } + + + diff --git a/src/profiling/profiling.middleware.ts b/src/profiling/profiling.middleware.ts index 9af7e2f..421e9ce 100644 --- a/src/profiling/profiling.middleware.ts +++ b/src/profiling/profiling.middleware.ts @@ -37,3 +37,6 @@ export class ProfilingMiddleware implements NestMiddleware { }); } } + + + diff --git a/src/profiling/profiling.module.ts b/src/profiling/profiling.module.ts index ffb3ba7..7c4b486 100644 --- a/src/profiling/profiling.module.ts +++ b/src/profiling/profiling.module.ts @@ -8,3 +8,6 @@ import { ProfilingController } from "./profiling.controller"; exports: [ProfilingService], }) export class ProfilingModule {} + + + diff --git a/src/profiling/profiling.service.ts b/src/profiling/profiling.service.ts index 1a77502..b85d714 100644 --- a/src/profiling/profiling.service.ts +++ b/src/profiling/profiling.service.ts @@ -346,3 +346,6 @@ export class ProfilingService { return false; } } + + + diff --git a/src/types/jest-globals.d.ts b/src/types/jest-globals.d.ts index a520c45..df935a0 100644 --- a/src/types/jest-globals.d.ts +++ b/src/types/jest-globals.d.ts @@ -6,3 +6,6 @@ declare const it: any; declare const beforeAll: any; declare const afterAll: any; declare const expect: any; + + + diff --git a/src/types/supertest.d.ts b/src/types/supertest.d.ts index 8ce7c32..88a2607 100644 --- a/src/types/supertest.d.ts +++ b/src/types/supertest.d.ts @@ -2,3 +2,6 @@ declare module "supertest" { const anyExport: any; export default anyExport; } + + + diff --git a/test/audit/provenance.e2e-spec.ts b/test/audit/provenance.e2e-spec.ts index f957703..8d50560 100644 --- a/test/audit/provenance.e2e-spec.ts +++ b/test/audit/provenance.e2e-spec.ts @@ -1,19 +1,19 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication } from "@nestjs/common"; -import * as request from "supertest"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { ConfigModule } from "@nestjs/config"; -import { JwtService } from "@nestjs/jwt"; -import { AuditModule } from "../../src/infrastructure/audit/audit.module"; -import { ProvenanceService } from "../../src/infrastructure/audit/provenance.service"; +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ConfigModule } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import { AuditModule } from '../../src/infrastructure/audit/audit.module'; +import { ProvenanceService } from '../../src/infrastructure/audit/provenance.service'; import { ProvenanceRecord, ProvenanceStatus, ProvenanceAction, -} from "../../src/infrastructure/audit/entities/provenance-record.entity"; -import { User, UserRole } from "../../src/core/user/entities/user.entity"; +} from '../../src/infrastructure/audit/entities/provenance-record.entity'; +import { User, UserRole } from '../../src/core/user/entities/user.entity'; -describe("ProvenanceController (e2e)", () => { +describe('ProvenanceController (e2e)', () => { let app: INestApplication; let provenanceService: ProvenanceService; let jwtService: JwtService; @@ -27,11 +27,11 @@ describe("ProvenanceController (e2e)", () => { imports: [ ConfigModule.forRoot({ isGlobal: true, - envFilePath: ".env.test", + envFilePath: '.env.test', }), TypeOrmModule.forRoot({ - type: "sqlite", - database: ":memory:", + type: 'sqlite', + database: ':memory:', entities: [ProvenanceRecord, User], synchronize: true, }), @@ -45,18 +45,18 @@ describe("ProvenanceController (e2e)", () => { jwtService = moduleFixture.get(JwtService); // Create test tokens - testUserId = "550e8400-e29b-41d4-a716-446655440001"; - testAdminId = "550e8400-e29b-41d4-a716-446655440002"; + testUserId = '550e8400-e29b-41d4-a716-446655440001'; + testAdminId = '550e8400-e29b-41d4-a716-446655440002'; userToken = jwtService.sign({ sub: testUserId, - email: "user@test.com", + email: 'user@test.com', role: UserRole.USER, }); adminToken = jwtService.sign({ sub: testAdminId, - email: "admin@test.com", + email: 'admin@test.com', role: UserRole.ADMIN, }); @@ -67,19 +67,19 @@ describe("ProvenanceController (e2e)", () => { await app.close(); }); - describe("POST /provenance (via service)", () => { - it("should create a provenance record with valid data", async () => { + describe('POST /provenance (via service)', () => { + it('should create a provenance record with valid data', async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-123", + agentId: 'agent-123', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "test query" }, + input: { query: 'test query' }, status: ProvenanceStatus.SUCCESS, }); expect(record).toBeDefined(); expect(record.id).toBeDefined(); - expect(record.agentId).toBe("agent-123"); + expect(record.agentId).toBe('agent-123'); expect(record.userId).toBe(testUserId); expect(record.action).toBe(ProvenanceAction.REQUEST_RECEIVED); expect(record.status).toBe(ProvenanceStatus.SUCCESS); @@ -87,49 +87,49 @@ describe("ProvenanceController (e2e)", () => { expect(record.recordHash).toBeDefined(); }); - it("should create a provenance record with error status", async () => { + it('should create a provenance record with error status', async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-456", + agentId: 'agent-456', userId: testUserId, action: ProvenanceAction.PROVIDER_CALL, - input: { query: "test query" }, + input: { query: 'test query' }, status: ProvenanceStatus.FAILED, - error: "Rate limit exceeded", - provider: "openai", + error: 'Rate limit exceeded', + provider: 'openai', }); expect(record).toBeDefined(); expect(record.status).toBe(ProvenanceStatus.FAILED); - expect(record.error).toBe("Rate limit exceeded"); - expect(record.provider).toBe("openai"); + expect(record.error).toBe('Rate limit exceeded'); + expect(record.provider).toBe('openai'); }); }); - describe("GET /provenance", () => { + describe('GET /provenance', () => { beforeAll(async () => { // Create test records await provenanceService.createProvenanceRecord({ - agentId: "agent-test", + agentId: 'agent-test', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "test 1" }, + input: { query: 'test 1' }, status: ProvenanceStatus.SUCCESS, }); await provenanceService.createProvenanceRecord({ - agentId: "agent-test", + agentId: 'agent-test', userId: testUserId, action: ProvenanceAction.PROVIDER_CALL, - input: { query: "test 2" }, + input: { query: 'test 2' }, status: ProvenanceStatus.SUCCESS, - provider: "openai", + provider: 'openai', }); }); - it("should return provenance records with authentication", () => { + it('should return provenance records with authentication', () => { return request(app.getHttpServer()) - .get("/provenance") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance') + .set('Authorization', `Bearer ${userToken}`) .expect(200) .expect((res) => { expect(res.body.data).toBeDefined(); @@ -140,37 +140,35 @@ describe("ProvenanceController (e2e)", () => { }); }); - it("should return 401 without authentication", () => { - return request(app.getHttpServer()).get("/provenance").expect(401); + it('should return 401 without authentication', () => { + return request(app.getHttpServer()) + .get('/provenance') + .expect(401); }); - it("should filter by agentId", async () => { + it('should filter by agentId', async () => { const response = await request(app.getHttpServer()) - .get("/provenance?agentId=agent-test") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance?agentId=agent-test') + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.data.length).toBeGreaterThan(0); - expect( - response.body.data.every((r: any) => r.agentId === "agent-test"), - ).toBe(true); + expect(response.body.data.every((r: any) => r.agentId === 'agent-test')).toBe(true); }); - it("should filter by status", async () => { + it('should filter by status', async () => { const response = await request(app.getHttpServer()) - .get("/provenance?status=success") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance?status=success') + .set('Authorization', `Bearer ${userToken}`) .expect(200); - expect(response.body.data.every((r: any) => r.status === "success")).toBe( - true, - ); + expect(response.body.data.every((r: any) => r.status === 'success')).toBe(true); }); - it("should paginate results", async () => { + it('should paginate results', async () => { const response = await request(app.getHttpServer()) - .get("/provenance?page=1&limit=1") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance?page=1&limit=1') + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.data.length).toBeLessThanOrEqual(1); @@ -178,96 +176,96 @@ describe("ProvenanceController (e2e)", () => { }); }); - describe("GET /provenance/:id", () => { + describe('GET /provenance/:id', () => { let testRecordId: string; beforeAll(async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-specific", + agentId: 'agent-specific', userId: testUserId, action: ProvenanceAction.SUBMISSION, - input: { query: "specific test" }, - output: { result: "success" }, + input: { query: 'specific test' }, + output: { result: 'success' }, status: ProvenanceStatus.SUCCESS, - onChainTxHash: "0x1234567890abcdef", + onChainTxHash: '0x1234567890abcdef', }); testRecordId = record.id; }); - it("should return a specific provenance record", async () => { + it('should return a specific provenance record', async () => { const response = await request(app.getHttpServer()) .get(`/provenance/${testRecordId}`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.id).toBe(testRecordId); - expect(response.body.agentId).toBe("agent-specific"); - expect(response.body.onChainTxHash).toBe("0x1234567890abcdef"); + expect(response.body.agentId).toBe('agent-specific'); + expect(response.body.onChainTxHash).toBe('0x1234567890abcdef'); }); - it("should return 404 for non-existent record", () => { + it('should return 404 for non-existent record', () => { return request(app.getHttpServer()) - .get("/provenance/550e8400-e29b-41d4-a716-446655440999") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance/550e8400-e29b-41d4-a716-446655440999') + .set('Authorization', `Bearer ${userToken}`) .expect(404); }); }); - describe("GET /provenance/:id/export", () => { + describe('GET /provenance/:id/export', () => { let testRecordId: string; beforeAll(async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-export", + agentId: 'agent-export', userId: testUserId, action: ProvenanceAction.RESULT_NORMALIZATION, - input: { raw: "data" }, - output: { normalized: "data" }, + input: { raw: 'data' }, + output: { normalized: 'data' }, status: ProvenanceStatus.SUCCESS, }); testRecordId = record.id; }); - it("should export record as JSON", async () => { + it('should export record as JSON', async () => { const response = await request(app.getHttpServer()) .get(`/provenance/${testRecordId}/export?format=json`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); - expect(response.headers["content-type"]).toContain("application/json"); + expect(response.headers['content-type']).toContain('application/json'); const data = JSON.parse(response.text); expect(data.id).toBe(testRecordId); }); - it("should export record as CSV", async () => { + it('should export record as CSV', async () => { const response = await request(app.getHttpServer()) .get(`/provenance/${testRecordId}/export?format=csv`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); - expect(response.headers["content-type"]).toContain("text/csv"); - expect(response.text).toContain("id,agentId,userId"); + expect(response.headers['content-type']).toContain('text/csv'); + expect(response.text).toContain('id,agentId,userId'); }); }); - describe("POST /provenance/:id/verify", () => { + describe('POST /provenance/:id/verify', () => { let testRecordId: string; beforeAll(async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-verify", + agentId: 'agent-verify', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { test: "data" }, + input: { test: 'data' }, status: ProvenanceStatus.SUCCESS, }); testRecordId = record.id; }); - it("should verify a valid signature", async () => { + it('should verify a valid signature', async () => { const response = await request(app.getHttpServer()) .post(`/provenance/${testRecordId}/verify`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.isValid).toBeDefined(); @@ -276,37 +274,35 @@ describe("ProvenanceController (e2e)", () => { }); }); - describe("GET /provenance/agents/:agentId", () => { + describe('GET /provenance/agents/:agentId', () => { beforeAll(async () => { await provenanceService.createProvenanceRecord({ - agentId: "agent-specific-2", + agentId: 'agent-specific-2', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "agent test" }, + input: { query: 'agent test' }, status: ProvenanceStatus.SUCCESS, }); }); - it("should return provenance for a specific agent", async () => { + it('should return provenance for a specific agent', async () => { const response = await request(app.getHttpServer()) - .get("/provenance/agents/agent-specific-2") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance/agents/agent-specific-2') + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.data).toBeDefined(); expect(Array.isArray(response.body.data)).toBe(true); - expect( - response.body.data.every((r: any) => r.agentId === "agent-specific-2"), - ).toBe(true); + expect(response.body.data.every((r: any) => r.agentId === 'agent-specific-2')).toBe(true); }); }); - describe("GET /provenance/agents/:agentId/timeline", () => { + describe('GET /provenance/agents/:agentId/timeline', () => { beforeAll(async () => { // Create multiple records for timeline for (let i = 0; i < 3; i++) { await provenanceService.createProvenanceRecord({ - agentId: "agent-timeline", + agentId: 'agent-timeline', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, input: { iteration: i }, @@ -315,28 +311,28 @@ describe("ProvenanceController (e2e)", () => { } }); - it("should return chronological timeline for agent", async () => { + it('should return chronological timeline for agent', async () => { const response = await request(app.getHttpServer()) - .get("/provenance/agents/agent-timeline/timeline") - .set("Authorization", `Bearer ${userToken}`) + .get('/provenance/agents/agent-timeline/timeline') + .set('Authorization', `Bearer ${userToken}`) .expect(200); - expect(response.body.agentId).toBe("agent-timeline"); + expect(response.body.agentId).toBe('agent-timeline'); expect(response.body.timeline).toBeDefined(); expect(Array.isArray(response.body.timeline)).toBe(true); expect(response.body.total).toBeGreaterThanOrEqual(3); }); }); - describe("Authorization", () => { + describe('Authorization', () => { let otherUserId: string; let otherUserToken: string; beforeAll(() => { - otherUserId = "550e8400-e29b-41d4-a716-446655440003"; + otherUserId = '550e8400-e29b-41d4-a716-446655440003'; otherUserToken = jwtService.sign({ sub: otherUserId, - email: "other@test.com", + email: 'other@test.com', role: UserRole.USER, }); }); @@ -344,88 +340,85 @@ describe("ProvenanceController (e2e)", () => { beforeAll(async () => { // Create record for other user await provenanceService.createProvenanceRecord({ - agentId: "agent-other", + agentId: 'agent-other', userId: otherUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "other user" }, + input: { query: 'other user' }, status: ProvenanceStatus.SUCCESS, }); }); - it("should allow admin to access any user provenance", async () => { + it('should allow admin to access any user provenance', async () => { const response = await request(app.getHttpServer()) .get(`/provenance/users/${otherUserId}`) - .set("Authorization", `Bearer ${adminToken}`) + .set('Authorization', `Bearer ${adminToken}`) .expect(200); expect(response.body.data).toBeDefined(); }); - it("should allow user to access their own provenance", async () => { + it('should allow user to access their own provenance', async () => { const response = await request(app.getHttpServer()) .get(`/provenance/users/${testUserId}`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.data).toBeDefined(); }); - it("should forbid user from accessing other user provenance", () => { + it('should forbid user from accessing other user provenance', () => { return request(app.getHttpServer()) .get(`/provenance/users/${otherUserId}`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(403); }); }); - describe("ProvenanceService", () => { - it("should update a provenance record", async () => { + describe('ProvenanceService', () => { + it('should update a provenance record', async () => { const record = await provenanceService.createProvenanceRecord({ - agentId: "agent-update", + agentId: 'agent-update', userId: testUserId, action: ProvenanceAction.PROVIDER_CALL, - input: { query: "update test" }, + input: { query: 'update test' }, status: ProvenanceStatus.PENDING, }); - const updated = await provenanceService.updateProvenanceRecord( - record.id, - { - status: ProvenanceStatus.SUCCESS, - output: { result: "completed" }, - processingDurationMs: 1500, - }, - ); + const updated = await provenanceService.updateProvenanceRecord(record.id, { + status: ProvenanceStatus.SUCCESS, + output: { result: 'completed' }, + processingDurationMs: 1500, + }); expect(updated.status).toBe(ProvenanceStatus.SUCCESS); - expect(updated.output).toEqual({ result: "completed" }); + expect(updated.output).toEqual({ result: 'completed' }); expect(updated.processingDurationMs).toBe(1500); }); - it("should export multiple records to CSV", async () => { + it('should export multiple records to CSV', async () => { // Create test records await provenanceService.createProvenanceRecord({ - agentId: "agent-csv", + agentId: 'agent-csv', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "csv 1" }, + input: { query: 'csv 1' }, status: ProvenanceStatus.SUCCESS, }); await provenanceService.createProvenanceRecord({ - agentId: "agent-csv", + agentId: 'agent-csv', userId: testUserId, action: ProvenanceAction.REQUEST_RECEIVED, - input: { query: "csv 2" }, + input: { query: 'csv 2' }, status: ProvenanceStatus.SUCCESS, }); const csv = await provenanceService.exportProvenanceToCsv({ - agentId: "agent-csv", + agentId: 'agent-csv', }); - expect(csv).toContain("id,agentId,userId"); - expect(csv).toContain("agent-csv"); + expect(csv).toContain('id,agentId,userId'); + expect(csv).toContain('agent-csv'); }); }); }); diff --git a/test/auth/wallet-advanced.e2e-spec.ts b/test/auth/wallet-advanced.e2e-spec.ts index 1afb75a..62ff127 100644 --- a/test/auth/wallet-advanced.e2e-spec.ts +++ b/test/auth/wallet-advanced.e2e-spec.ts @@ -1,20 +1,16 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication } from "@nestjs/common"; -import * as request from "supertest"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { ConfigModule } from "@nestjs/config"; -import { JwtService } from "@nestjs/jwt"; -import { Wallet } from "ethers"; -import { AuthModule } from "../../src/core/auth/auth.module"; -import { User, UserRole } from "../../src/core/user/entities/user.entity"; -import { - Wallet as WalletEntity, - WalletStatus, - WalletType, -} from "../../src/core/auth/entities/wallet.entity"; -import { EmailVerification } from "../../src/core/auth/entities/email-verification.entity"; - -describe("Advanced Wallet Authentication (e2e)", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ConfigModule } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; +import { Wallet } from 'ethers'; +import { AuthModule } from '../../src/core/auth/auth.module'; +import { User, UserRole } from '../../src/core/user/entities/user.entity'; +import { Wallet as WalletEntity, WalletStatus, WalletType } from '../../src/core/auth/entities/wallet.entity'; +import { EmailVerification } from '../../src/core/auth/entities/email-verification.entity'; + +describe('Advanced Wallet Authentication (e2e)', () => { let app: INestApplication; let jwtService: JwtService; let userToken: string; @@ -27,11 +23,11 @@ describe("Advanced Wallet Authentication (e2e)", () => { imports: [ ConfigModule.forRoot({ isGlobal: true, - envFilePath: ".env.test", + envFilePath: '.env.test', }), TypeOrmModule.forRoot({ - type: "sqlite", - database: ":memory:", + type: 'sqlite', + database: ':memory:', entities: [User, WalletEntity, EmailVerification], synchronize: true, }), @@ -47,7 +43,7 @@ describe("Advanced Wallet Authentication (e2e)", () => { primaryWallet = Wallet.createRandom(); secondaryWallet = Wallet.createRandom(); - testUserId = "550e8400-e29b-41d4-a716-446655440001"; + testUserId = '550e8400-e29b-41d4-a716-446655440001'; userToken = jwtService.sign({ sub: testUserId, @@ -62,11 +58,11 @@ describe("Advanced Wallet Authentication (e2e)", () => { await app.close(); }); - describe("Multi-Wallet Support", () => { - it("should link a primary wallet", async () => { + describe('Multi-Wallet Support', () => { + it('should link a primary wallet', async () => { // First get a challenge const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: primaryWallet.address }) .expect(200); @@ -74,27 +70,25 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await primaryWallet.signMessage(message); const response = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: primaryWallet.address, message, signature, - walletName: "Primary Wallet", + walletName: 'Primary Wallet', }) .expect(201); expect(response.body.walletId).toBeDefined(); - expect(response.body.walletAddress).toBe( - primaryWallet.address.toLowerCase(), - ); + expect(response.body.walletAddress).toBe(primaryWallet.address.toLowerCase()); expect(response.body.type).toBe(WalletType.PRIMARY); }); - it("should link a secondary wallet", async () => { + it('should link a secondary wallet', async () => { // Get challenge for secondary wallet const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: secondaryWallet.address }) .expect(200); @@ -102,13 +96,13 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await secondaryWallet.signMessage(message); const response = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: secondaryWallet.address, message, signature, - walletName: "Secondary Wallet", + walletName: 'Secondary Wallet', }) .expect(201); @@ -116,9 +110,9 @@ describe("Advanced Wallet Authentication (e2e)", () => { expect(response.body.type).toBe(WalletType.SECONDARY); }); - it("should prevent linking duplicate wallet", async () => { + it('should prevent linking duplicate wallet', async () => { const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: primaryWallet.address }) .expect(200); @@ -126,8 +120,8 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await primaryWallet.signMessage(message); await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: primaryWallet.address, message, @@ -136,21 +130,21 @@ describe("Advanced Wallet Authentication (e2e)", () => { .expect(409); }); - it("should get all user wallets", async () => { + it('should get all user wallets', async () => { const response = await request(app.getHttpServer()) - .get("/auth/wallets") - .set("Authorization", `Bearer ${userToken}`) + .get('/auth/wallets') + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(Array.isArray(response.body)).toBe(true); expect(response.body.length).toBeGreaterThanOrEqual(2); }); - it("should set a wallet as primary", async () => { + it('should set a wallet as primary', async () => { // First get wallets to find secondary wallet ID const walletsRes = await request(app.getHttpServer()) - .get("/auth/wallets") - .set("Authorization", `Bearer ${userToken}`) + .get('/auth/wallets') + .set('Authorization', `Bearer ${userToken}`) .expect(200); const secondaryWalletData = walletsRes.body.find( @@ -160,19 +154,19 @@ describe("Advanced Wallet Authentication (e2e)", () => { if (secondaryWalletData) { const response = await request(app.getHttpServer()) .post(`/auth/wallets/${secondaryWalletData.id}/set-primary`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(201); - expect(response.body.message).toContain("Primary wallet updated"); + expect(response.body.message).toContain('Primary wallet updated'); } }); - it("should unlink a wallet", async () => { + it('should unlink a wallet', async () => { // Create a third wallet to unlink const thirdWallet = Wallet.createRandom(); const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: thirdWallet.address }) .expect(200); @@ -180,13 +174,13 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await thirdWallet.signMessage(message); const linkRes = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: thirdWallet.address, message, signature, - walletName: "Wallet to Unlink", + walletName: 'Wallet to Unlink', }) .expect(201); @@ -194,16 +188,16 @@ describe("Advanced Wallet Authentication (e2e)", () => { // Now unlink it const response = await request(app.getHttpServer()) - .post("/auth/unlink-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/unlink-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletId }) .expect(201); - expect(response.body.message).toContain("successfully unlinked"); + expect(response.body.message).toContain('successfully unlinked'); }); }); - describe("Session Recovery", () => { + describe('Session Recovery', () => { let recoveryWallet: Wallet; let recoveryWalletId: string; @@ -212,7 +206,7 @@ describe("Advanced Wallet Authentication (e2e)", () => { // Link recovery wallet const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: recoveryWallet.address }) .expect(200); @@ -220,23 +214,23 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await recoveryWallet.signMessage(message); const linkRes = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: recoveryWallet.address, message, signature, - walletName: "Recovery Test Wallet", + walletName: 'Recovery Test Wallet', }) .expect(201); recoveryWalletId = linkRes.body.walletId; }); - it("should generate backup codes", async () => { + it('should generate backup codes', async () => { const response = await request(app.getHttpServer()) - .post("/auth/recovery/backup-code/generate") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/recovery/backup-code/generate') + .set('Authorization', `Bearer ${userToken}`) .send({ walletId: recoveryWalletId }) .expect(201); @@ -244,28 +238,28 @@ describe("Advanced Wallet Authentication (e2e)", () => { expect(response.body.codes.length).toBe(10); }); - it("should get recovery status", async () => { + it('should get recovery status', async () => { const response = await request(app.getHttpServer()) .get(`/auth/recovery/status/${recoveryWalletId}`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.recoveryEnabled).toBeDefined(); expect(response.body.methods).toBeDefined(); }); - it("should initiate email recovery", async () => { + it('should initiate email recovery', async () => { const response = await request(app.getHttpServer()) - .post("/auth/recovery/email/initiate") - .send({ email: "test@example.com" }) + .post('/auth/recovery/email/initiate') + .send({ email: 'test@example.com' }) .expect(201); expect(response.body.sessionId).toBeDefined(); - expect(response.body.message).toContain("Recovery email sent"); + expect(response.body.message).toContain('Recovery email sent'); }); }); - describe("Delegated Signing", () => { + describe('Delegated Signing', () => { let delegatorWallet: Wallet; let delegateWallet: Wallet; let delegatorWalletId: string; @@ -276,7 +270,7 @@ describe("Advanced Wallet Authentication (e2e)", () => { // Link delegator wallet const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: delegatorWallet.address }) .expect(200); @@ -284,30 +278,28 @@ describe("Advanced Wallet Authentication (e2e)", () => { const signature = await delegatorWallet.signMessage(message); const linkRes = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: delegatorWallet.address, message, signature, - walletName: "Delegator Wallet", + walletName: 'Delegator Wallet', }) .expect(201); delegatorWalletId = linkRes.body.walletId; }); - it("should request delegation", async () => { + it('should request delegation', async () => { const response = await request(app.getHttpServer()) - .post("/auth/delegation/request") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/delegation/request') + .set('Authorization', `Bearer ${userToken}`) .send({ delegatorWalletId, delegateAddress: delegateWallet.address, - permissions: ["sign_messages", "authenticate"], - expiresAt: new Date( - Date.now() + 7 * 24 * 60 * 60 * 1000, - ).toISOString(), + permissions: ['sign_messages', 'authenticate'], + expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), }) .expect(201); @@ -315,37 +307,37 @@ describe("Advanced Wallet Authentication (e2e)", () => { expect(response.body.challenge).toBeDefined(); }); - it("should get user delegations", async () => { + it('should get user delegations', async () => { const response = await request(app.getHttpServer()) - .get("/auth/delegations") - .set("Authorization", `Bearer ${userToken}`) + .get('/auth/delegations') + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(response.body.granted).toBeDefined(); expect(response.body.received).toBeDefined(); }); - it("should get wallet delegations", async () => { + it('should get wallet delegations', async () => { const response = await request(app.getHttpServer()) .get(`/auth/delegations/wallet/${delegatorWalletId}`) - .set("Authorization", `Bearer ${userToken}`) + .set('Authorization', `Bearer ${userToken}`) .expect(200); expect(Array.isArray(response.body)).toBe(true); }); }); - describe("Security Tests", () => { - it("should reject unauthorized wallet access", async () => { + describe('Security Tests', () => { + it('should reject unauthorized wallet access', async () => { const otherUserToken = jwtService.sign({ - sub: "550e8400-e29b-41d4-a716-446655440999", - address: "0x9999999999999999999999999999999999999999", + sub: '550e8400-e29b-41d4-a716-446655440999', + address: '0x9999999999999999999999999999999999999999', role: UserRole.USER, }); await request(app.getHttpServer()) - .get("/auth/wallets") - .set("Authorization", `Bearer ${otherUserToken}`) + .get('/auth/wallets') + .set('Authorization', `Bearer ${otherUserToken}`) .expect(200) .expect((res) => { // Should return empty or different wallets @@ -353,11 +345,11 @@ describe("Advanced Wallet Authentication (e2e)", () => { }); }); - it("should prevent replay attacks with consumed challenges", async () => { + it('should prevent replay attacks with consumed challenges', async () => { const newWallet = Wallet.createRandom(); const challengeRes = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: newWallet.address }) .expect(200); @@ -366,8 +358,8 @@ describe("Advanced Wallet Authentication (e2e)", () => { // First attempt should succeed await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: newWallet.address, message, @@ -377,8 +369,8 @@ describe("Advanced Wallet Authentication (e2e)", () => { // Second attempt with same challenge should fail await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${userToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${userToken}`) .send({ walletAddress: newWallet.address, message, @@ -387,17 +379,15 @@ describe("Advanced Wallet Authentication (e2e)", () => { .expect(401); }); - it("should enforce rate limiting on sensitive endpoints", async () => { + it('should enforce rate limiting on sensitive endpoints', async () => { const newWallet = Wallet.createRandom(); // Make multiple rapid requests - const requests = Array(15) - .fill(null) - .map(() => - request(app.getHttpServer()) - .post("/auth/challenge") - .send({ address: newWallet.address }), - ); + const requests = Array(15).fill(null).map(() => + request(app.getHttpServer()) + .post('/auth/challenge') + .send({ address: newWallet.address }), + ); const responses = await Promise.all(requests); diff --git a/test/email-linking.spec.ts b/test/email-linking.spec.ts index 25d0981..62b4964 100644 --- a/test/email-linking.spec.ts +++ b/test/email-linking.spec.ts @@ -1,26 +1,21 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { getRepositoryToken } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; -import { - BadRequestException, - ConflictException, - NotFoundException, - UnauthorizedException, -} from "@nestjs/common"; -import { EmailLinkingService } from "../src/core/auth/email-linking.service"; -import { EmailService } from "../src/core/auth/email.service"; -import { User } from "../src/core/user/entities/user.entity"; -import { EmailVerification } from "../src/core/auth/entities/email-verification.entity"; - -describe("EmailLinkingService", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { BadRequestException, ConflictException, NotFoundException, UnauthorizedException } from '@nestjs/common'; +import { EmailLinkingService } from '../src/core/auth/email-linking.service'; +import { EmailService } from '../src/core/auth/email.service'; +import { User } from '../src/core/user/entities/user.entity'; +import { EmailVerification } from '../src/core/auth/entities/email-verification.entity'; + +describe('EmailLinkingService', () => { let service: EmailLinkingService; let userRepository: Repository; let emailVerificationRepository: Repository; let emailService: EmailService; const mockUser: User = { - id: "123", - walletAddress: "0x1234567890123456789012345678901234567890", + id: '123', + walletAddress: '0x1234567890123456789012345678901234567890', email: null, emailVerified: false, createdAt: new Date(), @@ -29,8 +24,8 @@ describe("EmailLinkingService", () => { const mockEmailService = { sendVerificationEmail: jest.fn().mockResolvedValue({ - messageId: "test-message-id", - previewUrl: "https://ethereal.email/message/test", + messageId: 'test-message-id', + previewUrl: 'https://ethereal.email/message/test', }), }; @@ -71,188 +66,163 @@ describe("EmailLinkingService", () => { emailService = module.get(EmailService); }); - describe("initiateEmailLinking", () => { - it("should initiate email linking for new user", async () => { - jest.spyOn(userRepository, "findOne").mockResolvedValue(null); - jest.spyOn(userRepository, "create").mockReturnValue(mockUser); - jest.spyOn(userRepository, "save").mockResolvedValue(mockUser); - jest - .spyOn(emailVerificationRepository, "delete") - .mockResolvedValue(undefined); - jest - .spyOn(emailVerificationRepository, "create") - .mockReturnValue({} as EmailVerification); - jest - .spyOn(emailVerificationRepository, "save") - .mockResolvedValue({} as EmailVerification); + describe('initiateEmailLinking', () => { + it('should initiate email linking for new user', async () => { + jest.spyOn(userRepository, 'findOne').mockResolvedValue(null); + jest.spyOn(userRepository, 'create').mockReturnValue(mockUser); + jest.spyOn(userRepository, 'save').mockResolvedValue(mockUser); + jest.spyOn(emailVerificationRepository, 'delete').mockResolvedValue(undefined); + jest.spyOn(emailVerificationRepository, 'create').mockReturnValue({} as EmailVerification); + jest.spyOn(emailVerificationRepository, 'save').mockResolvedValue({} as EmailVerification); const result = await service.initiateEmailLinking( - "0x1234567890123456789012345678901234567890", - "test@example.com", + '0x1234567890123456789012345678901234567890', + 'test@example.com', ); - expect(result.message).toContain("Verification email sent"); + expect(result.message).toContain('Verification email sent'); expect(emailService.sendVerificationEmail).toHaveBeenCalled(); }); - it("should reject invalid email format", async () => { + it('should reject invalid email format', async () => { await expect( service.initiateEmailLinking( - "0x1234567890123456789012345678901234567890", - "invalid-email", + '0x1234567890123456789012345678901234567890', + 'invalid-email', ), ).rejects.toThrow(BadRequestException); }); - it("should reject email already linked to another wallet", async () => { - const existingUser = { ...mockUser, walletAddress: "0xdifferent" }; - jest.spyOn(userRepository, "findOne").mockResolvedValue(existingUser); + it('should reject email already linked to another wallet', async () => { + const existingUser = { ...mockUser, walletAddress: '0xdifferent' }; + jest.spyOn(userRepository, 'findOne').mockResolvedValue(existingUser); await expect( service.initiateEmailLinking( - "0x1234567890123456789012345678901234567890", - "test@example.com", + '0x1234567890123456789012345678901234567890', + 'test@example.com', ), ).rejects.toThrow(ConflictException); }); - it("should reject if email already verified for this wallet", async () => { + it('should reject if email already verified for this wallet', async () => { const verifiedUser = { ...mockUser, - email: "test@example.com", + email: 'test@example.com', emailVerified: true, }; - jest - .spyOn(userRepository, "findOne") + jest.spyOn(userRepository, 'findOne') .mockResolvedValueOnce(null) // First call for email check .mockResolvedValueOnce(verifiedUser); // Second call for wallet check await expect( service.initiateEmailLinking( - "0x1234567890123456789012345678901234567890", - "test@example.com", + '0x1234567890123456789012345678901234567890', + 'test@example.com', ), ).rejects.toThrow(ConflictException); }); }); - describe("verifyEmailAndLink", () => { - it("should verify email and link to wallet", async () => { + describe('verifyEmailAndLink', () => { + it('should verify email and link to wallet', async () => { const verification: EmailVerification = { - id: "1", - email: "test@example.com", - token: "a".repeat(64), - walletAddress: "0x1234567890123456789012345678901234567890", + id: '1', + email: 'test@example.com', + token: 'a'.repeat(64), + walletAddress: '0x1234567890123456789012345678901234567890', expiresAt: new Date(Date.now() + 10 * 60 * 1000), createdAt: new Date(), }; - jest - .spyOn(emailVerificationRepository, "findOne") - .mockResolvedValue(verification); - jest.spyOn(userRepository, "findOne").mockResolvedValue(mockUser); - jest.spyOn(userRepository, "save").mockResolvedValue({ + jest.spyOn(emailVerificationRepository, 'findOne').mockResolvedValue(verification); + jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser); + jest.spyOn(userRepository, 'save').mockResolvedValue({ ...mockUser, - email: "test@example.com", + email: 'test@example.com', emailVerified: true, }); - jest - .spyOn(emailVerificationRepository, "delete") - .mockResolvedValue(undefined); + jest.spyOn(emailVerificationRepository, 'delete').mockResolvedValue(undefined); - const result = await service.verifyEmailAndLink("a".repeat(64)); + const result = await service.verifyEmailAndLink('a'.repeat(64)); - expect(result.message).toContain("successfully verified"); - expect(result.email).toBe("test@example.com"); + expect(result.message).toContain('successfully verified'); + expect(result.email).toBe('test@example.com'); }); - it("should reject invalid token", async () => { - jest - .spyOn(emailVerificationRepository, "findOne") - .mockResolvedValue(null); + it('should reject invalid token', async () => { + jest.spyOn(emailVerificationRepository, 'findOne').mockResolvedValue(null); - await expect(service.verifyEmailAndLink("invalid-token")).rejects.toThrow( + await expect(service.verifyEmailAndLink('invalid-token')).rejects.toThrow( NotFoundException, ); }); - it("should reject expired token", async () => { + it('should reject expired token', async () => { const expiredVerification: EmailVerification = { - id: "1", - email: "test@example.com", - token: "a".repeat(64), - walletAddress: "0x1234567890123456789012345678901234567890", + id: '1', + email: 'test@example.com', + token: 'a'.repeat(64), + walletAddress: '0x1234567890123456789012345678901234567890', expiresAt: new Date(Date.now() - 1000), // Expired createdAt: new Date(), }; - jest - .spyOn(emailVerificationRepository, "findOne") - .mockResolvedValue(expiredVerification); - jest - .spyOn(emailVerificationRepository, "delete") - .mockResolvedValue(undefined); + jest.spyOn(emailVerificationRepository, 'findOne').mockResolvedValue(expiredVerification); + jest.spyOn(emailVerificationRepository, 'delete').mockResolvedValue(undefined); - await expect(service.verifyEmailAndLink("a".repeat(64))).rejects.toThrow( + await expect(service.verifyEmailAndLink('a'.repeat(64))).rejects.toThrow( UnauthorizedException, ); }); }); - describe("getAccountInfo", () => { - it("should return account info for wallet with linked email", async () => { + describe('getAccountInfo', () => { + it('should return account info for wallet with linked email', async () => { const userWithEmail = { ...mockUser, - email: "test@example.com", + email: 'test@example.com', emailVerified: true, }; - jest.spyOn(userRepository, "findOne").mockResolvedValue(userWithEmail); + jest.spyOn(userRepository, 'findOne').mockResolvedValue(userWithEmail); - const result = await service.getAccountInfo( - "0x1234567890123456789012345678901234567890", - ); + const result = await service.getAccountInfo('0x1234567890123456789012345678901234567890'); - expect(result.email).toBe("test@example.com"); + expect(result.email).toBe('test@example.com'); expect(result.emailVerified).toBe(true); }); - it("should return null email for wallet without linked email", async () => { - jest.spyOn(userRepository, "findOne").mockResolvedValue(null); + it('should return null email for wallet without linked email', async () => { + jest.spyOn(userRepository, 'findOne').mockResolvedValue(null); - const result = await service.getAccountInfo( - "0x1234567890123456789012345678901234567890", - ); + const result = await service.getAccountInfo('0x1234567890123456789012345678901234567890'); expect(result.email).toBeNull(); expect(result.emailVerified).toBe(false); }); }); - describe("unlinkEmail", () => { - it("should unlink email from wallet", async () => { + describe('unlinkEmail', () => { + it('should unlink email from wallet', async () => { const userWithEmail = { ...mockUser, - email: "test@example.com", + email: 'test@example.com', emailVerified: true, }; - jest.spyOn(userRepository, "findOne").mockResolvedValue(userWithEmail); - jest.spyOn(userRepository, "save").mockResolvedValue(mockUser); - jest - .spyOn(emailVerificationRepository, "delete") - .mockResolvedValue(undefined); - - const result = await service.unlinkEmail( - "0x1234567890123456789012345678901234567890", - ); + jest.spyOn(userRepository, 'findOne').mockResolvedValue(userWithEmail); + jest.spyOn(userRepository, 'save').mockResolvedValue(mockUser); + jest.spyOn(emailVerificationRepository, 'delete').mockResolvedValue(undefined); + + const result = await service.unlinkEmail('0x1234567890123456789012345678901234567890'); - expect(result.message).toContain("successfully unlinked"); + expect(result.message).toContain('successfully unlinked'); }); - it("should throw error if no email linked", async () => { - jest.spyOn(userRepository, "findOne").mockResolvedValue(mockUser); + it('should throw error if no email linked', async () => { + jest.spyOn(userRepository, 'findOne').mockResolvedValue(mockUser); await expect( - service.unlinkEmail("0x1234567890123456789012345678901234567890"), + service.unlinkEmail('0x1234567890123456789012345678901234567890'), ).rejects.toThrow(NotFoundException); }); }); diff --git a/test/enhanced-auth.service.spec.ts b/test/enhanced-auth.service.spec.ts index c1a1782..9566a4e 100644 --- a/test/enhanced-auth.service.spec.ts +++ b/test/enhanced-auth.service.spec.ts @@ -196,4 +196,5 @@ describe("EnhancedAuthService", () => { expect(result).toHaveProperty("backupCodes"); }); }); -}); \ No newline at end of file +}); +/workspaces/alian-structure-api/test/enhanced-auth.service.spec.ts \ No newline at end of file diff --git a/test/oracle-e2e.spec.ts b/test/oracle-e2e.spec.ts index 60e334c..dab93be 100644 --- a/test/oracle-e2e.spec.ts +++ b/test/oracle-e2e.spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication, ValidationPipe } from "@nestjs/common"; -import * as request from "supertest"; -import { TypeOrmModule } from "@nestjs/typeorm"; -import { ConfigModule } from "@nestjs/config"; -import { JwtModule } from "@nestjs/jwt"; -import { Wallet } from "ethers"; -import { OracleModule } from "../src/blockchain/oracle/oracle.module"; -import { AuthModule } from "../src/core/auth/auth.module"; -import { UserModule } from "../src/core/user/user.module"; -import { SignedPayload } from "../src/blockchain/oracle/entities/signed-payload.entity"; -import { SubmissionNonce } from "../src/blockchain/oracle/entities/submission-nonce.entity"; -import { User } from "../src/core/user/entities/user.entity"; -import { EmailVerification } from "../src/core/auth/entities/email-verification.entity"; -import { PayloadType } from "../src/blockchain/oracle/entities/signed-payload.entity"; - -describe("Oracle E2E Tests", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; +import * as request from 'supertest'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ConfigModule } from '@nestjs/config'; +import { JwtModule } from '@nestjs/jwt'; +import { Wallet } from 'ethers'; +import { OracleModule } from '../src/blockchain/oracle/oracle.module'; +import { AuthModule } from '../src/core/auth/auth.module'; +import { UserModule } from '../src/core/user/user.module'; +import { SignedPayload } from '../src/blockchain/oracle/entities/signed-payload.entity'; +import { SubmissionNonce } from '../src/blockchain/oracle/entities/submission-nonce.entity'; +import { User } from '../src/core/user/entities/user.entity'; +import { EmailVerification } from '../src/core/auth/entities/email-verification.entity'; +import { PayloadType } from '../src/blockchain/oracle/entities/signed-payload.entity'; + +describe('Oracle E2E Tests', () => { let app: INestApplication; let jwtToken: string; let testWallet: Wallet; @@ -29,22 +29,22 @@ describe("Oracle E2E Tests", () => { imports: [ ConfigModule.forRoot({ isGlobal: true, - envFilePath: ".env.test", + envFilePath: '.env.test', }), TypeOrmModule.forRoot({ - type: "postgres", - host: process.env.DB_HOST || "localhost", - port: parseInt(process.env.DB_PORT || "5432"), - username: process.env.DB_USERNAME || "alian-structure", - password: process.env.DB_PASSWORD || "password", - database: process.env.DB_NAME || "alian-structure_test", + type: 'postgres', + host: process.env.DB_HOST || 'localhost', + port: parseInt(process.env.DB_PORT || '5432'), + username: process.env.DB_USERNAME || 'alian-structure', + password: process.env.DB_PASSWORD || 'password', + database: process.env.DB_NAME || 'alian-structure_test', entities: [SignedPayload, SubmissionNonce, User, EmailVerification], synchronize: true, dropSchema: true, }), JwtModule.register({ - secret: "test-secret", - signOptions: { expiresIn: "24h" }, + secret: 'test-secret', + signOptions: { expiresIn: '24h' }, }), OracleModule, AuthModule, @@ -57,7 +57,7 @@ describe("Oracle E2E Tests", () => { await app.init(); // Create JWT token for testing authenticated endpoints - const jwtService = app.get("JwtService"); + const jwtService = app.get('JwtService'); jwtToken = jwtService.sign({ address: userAddress.toLowerCase() }); }); @@ -65,46 +65,46 @@ describe("Oracle E2E Tests", () => { await app.close(); }); - describe("/oracle/health (GET)", () => { - it("should return health status", () => { + describe('/oracle/health (GET)', () => { + it('should return health status', () => { return request(app.getHttpServer()) - .get("/oracle/health") + .get('/oracle/health') .expect(200) .expect((res) => { - expect(res.body.status).toBe("healthy"); - expect(res.body.service).toBe("oracle"); + expect(res.body.status).toBe('healthy'); + expect(res.body.service).toBe('oracle'); }); }); }); - describe("/oracle/nonce/:address (GET)", () => { - it("should return nonce for an address", () => { + describe('/oracle/nonce/:address (GET)', () => { + it('should return nonce for an address', () => { return request(app.getHttpServer()) .get(`/oracle/nonce/${userAddress}`) .expect(200) .expect((res) => { expect(res.body.address).toBe(userAddress); expect(res.body.nonce).toBeDefined(); - expect(typeof res.body.nonce).toBe("string"); + expect(typeof res.body.nonce).toBe('string'); }); }); - it("should return 0 for new address", () => { + it('should return 0 for new address', () => { const newAddress = Wallet.createRandom().address; return request(app.getHttpServer()) .get(`/oracle/nonce/${newAddress}`) .expect(200) .expect((res) => { - expect(res.body.nonce).toBe("0"); + expect(res.body.nonce).toBe('0'); }); }); }); - describe("/oracle/my-nonce (GET)", () => { - it("should return nonce for authenticated user", () => { + describe('/oracle/my-nonce (GET)', () => { + it('should return nonce for authenticated user', () => { return request(app.getHttpServer()) - .get("/oracle/my-nonce") - .set("Authorization", `Bearer ${jwtToken}`) + .get('/oracle/my-nonce') + .set('Authorization', `Bearer ${jwtToken}`) .expect(200) .expect((res) => { expect(res.body.address).toBe(userAddress.toLowerCase()); @@ -112,22 +112,22 @@ describe("Oracle E2E Tests", () => { }); }); - it("should reject without authentication", () => { - return request(app.getHttpServer()).get("/oracle/my-nonce").expect(401); + it('should reject without authentication', () => { + return request(app.getHttpServer()).get('/oracle/my-nonce').expect(401); }); }); - describe("/oracle/payloads (POST)", () => { - it("should create a new payload", () => { + describe('/oracle/payloads (POST)', () => { + it('should create a new payload', () => { const createPayloadDto = { payloadType: PayloadType.ORACLE_UPDATE, payload: { value: 100, timestamp: Date.now() }, - metadata: { source: "test" }, + metadata: { source: 'test' }, }; return request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send(createPayloadDto) .expect(201) .expect((res) => { @@ -136,13 +136,13 @@ describe("Oracle E2E Tests", () => { expect(res.body.signerAddress).toBe(userAddress.toLowerCase()); expect(res.body.nonce).toBeDefined(); expect(res.body.payloadHash).toMatch(/^0x[a-fA-F0-9]{64}$/); - expect(res.body.status).toBe("pending"); + expect(res.body.status).toBe('pending'); }); }); - it("should reject without authentication", () => { + it('should reject without authentication', () => { return request(app.getHttpServer()) - .post("/oracle/payloads") + .post('/oracle/payloads') .send({ payloadType: PayloadType.ORACLE_UPDATE, payload: { value: 100 }, @@ -150,21 +150,21 @@ describe("Oracle E2E Tests", () => { .expect(401); }); - it("should reject invalid payload type", () => { + it('should reject invalid payload type', () => { return request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ - payloadType: "invalid_type", + payloadType: 'invalid_type', payload: { value: 100 }, }) .expect(400); }); - it("should reject missing payload data", () => { + it('should reject missing payload data', () => { return request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadType: PayloadType.ORACLE_UPDATE, }) @@ -172,14 +172,14 @@ describe("Oracle E2E Tests", () => { }); }); - describe("/oracle/payloads/:id (GET)", () => { + describe('/oracle/payloads/:id (GET)', () => { let payloadId: string; beforeAll(async () => { // Create a test payload const res = await request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadType: PayloadType.ORACLE_UPDATE, payload: { value: 200 }, @@ -187,10 +187,10 @@ describe("Oracle E2E Tests", () => { payloadId = res.body.id; }); - it("should get a payload by ID", () => { + it('should get a payload by ID', () => { return request(app.getHttpServer()) .get(`/oracle/payloads/${payloadId}`) - .set("Authorization", `Bearer ${jwtToken}`) + .set('Authorization', `Bearer ${jwtToken}`) .expect(200) .expect((res) => { expect(res.body.id).toBe(payloadId); @@ -198,21 +198,21 @@ describe("Oracle E2E Tests", () => { }); }); - it("should return 404 for non-existent payload", () => { + it('should return 404 for non-existent payload', () => { return request(app.getHttpServer()) - .get("/oracle/payloads/00000000-0000-0000-0000-000000000000") - .set("Authorization", `Bearer ${jwtToken}`) + .get('/oracle/payloads/00000000-0000-0000-0000-000000000000') + .set('Authorization', `Bearer ${jwtToken}`) .expect(404); }); }); - describe("/oracle/my-payloads (GET)", () => { + describe('/oracle/my-payloads (GET)', () => { beforeAll(async () => { // Create multiple payloads for (let i = 0; i < 3; i++) { await request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadType: PayloadType.AGENT_RESULT, payload: { resultId: i }, @@ -220,10 +220,10 @@ describe("Oracle E2E Tests", () => { } }); - it("should get all payloads for authenticated user", () => { + it('should get all payloads for authenticated user', () => { return request(app.getHttpServer()) - .get("/oracle/my-payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .get('/oracle/my-payloads') + .set('Authorization', `Bearer ${jwtToken}`) .expect(200) .expect((res) => { expect(Array.isArray(res.body)).toBe(true); @@ -234,23 +234,23 @@ describe("Oracle E2E Tests", () => { }); }); - it("should filter by status", () => { + it('should filter by status', () => { return request(app.getHttpServer()) - .get("/oracle/my-payloads?status=pending") - .set("Authorization", `Bearer ${jwtToken}`) + .get('/oracle/my-payloads?status=pending') + .set('Authorization', `Bearer ${jwtToken}`) .expect(200) .expect((res) => { expect(Array.isArray(res.body)).toBe(true); res.body.forEach((payload: any) => { - expect(payload.status).toBe("pending"); + expect(payload.status).toBe('pending'); }); }); }); - it("should respect limit parameter", () => { + it('should respect limit parameter', () => { return request(app.getHttpServer()) - .get("/oracle/my-payloads?limit=2") - .set("Authorization", `Bearer ${jwtToken}`) + .get('/oracle/my-payloads?limit=2') + .set('Authorization', `Bearer ${jwtToken}`) .expect(200) .expect((res) => { expect(res.body.length).toBeLessThanOrEqual(2); @@ -258,29 +258,29 @@ describe("Oracle E2E Tests", () => { }); }); - describe("/oracle/stats (GET)", () => { - it("should return oracle statistics", () => { + describe('/oracle/stats (GET)', () => { + it('should return oracle statistics', () => { return request(app.getHttpServer()) - .get("/oracle/stats") + .get('/oracle/stats') .expect(200) .expect((res) => { expect(res.body.payloads).toBeDefined(); expect(res.body.nonces).toBeDefined(); expect(res.body.submissions).toBeDefined(); - expect(typeof res.body.payloads.pending).toBe("number"); - expect(typeof res.body.nonces.totalAddresses).toBe("number"); + expect(typeof res.body.payloads.pending).toBe('number'); + expect(typeof res.body.nonces.totalAddresses).toBe('number'); }); }); }); - describe("/oracle/payloads/:id/sign (POST)", () => { + describe('/oracle/payloads/:id/sign (POST)', () => { let payloadId: string; beforeEach(async () => { // Create a new payload for signing const res = await request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadType: PayloadType.PRICE_FEED, payload: { price: 1000 }, @@ -288,10 +288,10 @@ describe("Oracle E2E Tests", () => { payloadId = res.body.id; }); - it("should sign a payload", () => { + it('should sign a payload', () => { return request(app.getHttpServer()) .post(`/oracle/payloads/${payloadId}/sign`) - .set("Authorization", `Bearer ${jwtToken}`) + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadId, privateKey: testWallet.privateKey, @@ -300,15 +300,15 @@ describe("Oracle E2E Tests", () => { .expect((res) => { expect(res.body.signature).toBeDefined(); expect(res.body.signature).toMatch(/^0x[a-fA-F0-9]{130}$/); - expect(res.body.status).toBe("pending"); + expect(res.body.status).toBe('pending'); }); }); - it("should reject signing with wrong private key", () => { + it('should reject signing with wrong private key', () => { const wrongWallet = Wallet.createRandom(); return request(app.getHttpServer()) .post(`/oracle/payloads/${payloadId}/sign`) - .set("Authorization", `Bearer ${jwtToken}`) + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadId, privateKey: wrongWallet.privateKey, @@ -316,20 +316,20 @@ describe("Oracle E2E Tests", () => { .expect(400); }); - it("should reject invalid private key format", () => { + it('should reject invalid private key format', () => { return request(app.getHttpServer()) .post(`/oracle/payloads/${payloadId}/sign`) - .set("Authorization", `Bearer ${jwtToken}`) + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadId, - privateKey: "invalid-key", + privateKey: 'invalid-key', }) .expect(400); }); }); - describe("Nonce increment on payload creation", () => { - it("should increment nonce with each payload creation", async () => { + describe('Nonce increment on payload creation', () => { + it('should increment nonce with each payload creation', async () => { const initialNonceRes = await request(app.getHttpServer()) .get(`/oracle/nonce/${userAddress}`) .expect(200); @@ -338,11 +338,11 @@ describe("Oracle E2E Tests", () => { // Create a payload await request(app.getHttpServer()) - .post("/oracle/payloads") - .set("Authorization", `Bearer ${jwtToken}`) + .post('/oracle/payloads') + .set('Authorization', `Bearer ${jwtToken}`) .send({ payloadType: PayloadType.COMPUTE_PROOF, - payload: { computeId: "test-123" }, + payload: { computeId: 'test-123' }, }) .expect(201); diff --git a/test/oracle/payload-signing.service.spec.ts b/test/oracle/payload-signing.service.spec.ts index eeec7e2..e6bd94c 100644 --- a/test/oracle/payload-signing.service.spec.ts +++ b/test/oracle/payload-signing.service.spec.ts @@ -1,9 +1,9 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { ConfigService } from "@nestjs/config"; -import { Wallet } from "ethers"; -import { PayloadSigningService } from "../../src/blockchain/oracle/services/payload-signing.service"; +import { Test, TestingModule } from '@nestjs/testing'; +import { ConfigService } from '@nestjs/config'; +import { Wallet } from 'ethers'; +import { PayloadSigningService } from '../../src/blockchain/oracle/services/payload-signing.service'; -describe("PayloadSigningService", () => { +describe('PayloadSigningService', () => { let service: PayloadSigningService; let testWallet: Wallet; let configService: ConfigService; @@ -16,8 +16,8 @@ describe("PayloadSigningService", () => { const mockConfigService = { get: jest.fn((key: string, defaultValue?: any) => { const config: Record = { - CHAIN_ID: "1", - ORACLE_CONTRACT_ADDRESS: "0x1234567890123456789012345678901234567890", + CHAIN_ID: '1', + ORACLE_CONTRACT_ADDRESS: '0x1234567890123456789012345678901234567890', }; return config[key] || defaultValue; }), @@ -37,13 +37,13 @@ describe("PayloadSigningService", () => { configService = module.get(ConfigService); }); - it("should be defined", () => { + it('should be defined', () => { expect(service).toBeDefined(); }); - describe("hashPayload", () => { - it("should hash a payload consistently", () => { - const payload = { foo: "bar", baz: 123 }; + describe('hashPayload', () => { + it('should hash a payload consistently', () => { + const payload = { foo: 'bar', baz: 123 }; const hash1 = service.hashPayload(payload); const hash2 = service.hashPayload(payload); @@ -51,9 +51,9 @@ describe("PayloadSigningService", () => { expect(hash1).toMatch(/^0x[a-fA-F0-9]{64}$/); }); - it("should produce different hashes for different payloads", () => { - const payload1 = { foo: "bar" }; - const payload2 = { foo: "baz" }; + it('should produce different hashes for different payloads', () => { + const payload1 = { foo: 'bar' }; + const payload2 = { foo: 'baz' }; const hash1 = service.hashPayload(payload1); const hash2 = service.hashPayload(payload2); @@ -62,11 +62,11 @@ describe("PayloadSigningService", () => { }); }); - describe("createStructuredData", () => { - it("should create EIP-712 structured data", () => { - const payloadType = "oracle_update"; - const payloadHash = "0x" + "1".repeat(64); - const nonce = "0"; + describe('createStructuredData', () => { + it('should create EIP-712 structured data', () => { + const payloadType = 'oracle_update'; + const payloadHash = '0x' + '1'.repeat(64); + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const data = { value: 100 }; @@ -79,8 +79,8 @@ describe("PayloadSigningService", () => { ); expect(structuredData.domain).toBeDefined(); - expect(structuredData.domain.name).toBe("alian-structure Oracle"); - expect(structuredData.domain.version).toBe("1"); + expect(structuredData.domain.name).toBe('alian-structure Oracle'); + expect(structuredData.domain.version).toBe('1'); expect(structuredData.domain.chainId).toBe(1); expect(structuredData.types).toBeDefined(); expect(structuredData.value).toBeDefined(); @@ -89,12 +89,12 @@ describe("PayloadSigningService", () => { }); }); - describe("signPayload", () => { - it("should sign a payload and return signature", async () => { - const payloadType = "oracle_update"; + describe('signPayload', () => { + it('should sign a payload and return signature', async () => { + const payloadType = 'oracle_update'; const payload = { value: 100 }; const payloadHash = service.hashPayload(payload); - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const result = await service.signPayload( @@ -111,11 +111,11 @@ describe("PayloadSigningService", () => { expect(result.signerAddress).toBe(testWallet.address); }); - it("should produce different signatures for different payloads", async () => { - const payloadType = "oracle_update"; + it('should produce different signatures for different payloads', async () => { + const payloadType = 'oracle_update'; const payload1 = { value: 100 }; const payload2 = { value: 200 }; - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const result1 = await service.signPayload( @@ -140,12 +140,12 @@ describe("PayloadSigningService", () => { }); }); - describe("verifySignature", () => { - it("should verify a valid signature", async () => { - const payloadType = "oracle_update"; + describe('verifySignature', () => { + it('should verify a valid signature', async () => { + const payloadType = 'oracle_update'; const payload = { value: 100 }; const payloadHash = service.hashPayload(payload); - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const { signature, signerAddress } = await service.signPayload( @@ -170,13 +170,13 @@ describe("PayloadSigningService", () => { expect(isValid).toBe(true); }); - it("should reject an invalid signature", () => { - const payloadType = "oracle_update"; + it('should reject an invalid signature', () => { + const payloadType = 'oracle_update'; const payload = { value: 100 }; const payloadHash = service.hashPayload(payload); - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; - const fakeSignature = "0x" + "1".repeat(130); + const fakeSignature = '0x' + '1'.repeat(130); const isValid = service.verifySignature( fakeSignature, @@ -191,11 +191,11 @@ describe("PayloadSigningService", () => { expect(isValid).toBe(false); }); - it("should reject signature from different signer", async () => { - const payloadType = "oracle_update"; + it('should reject signature from different signer', async () => { + const payloadType = 'oracle_update'; const payload = { value: 100 }; const payloadHash = service.hashPayload(payload); - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const { signature } = await service.signPayload( @@ -222,11 +222,11 @@ describe("PayloadSigningService", () => { expect(isValid).toBe(false); }); - it("should reject signature for modified payload", async () => { - const payloadType = "oracle_update"; + it('should reject signature for modified payload', async () => { + const payloadType = 'oracle_update'; const payload = { value: 100 }; const payloadHash = service.hashPayload(payload); - const nonce = "0"; + const nonce = '0'; const expiresAt = Math.floor(Date.now() / 1000) + 3600; const { signature, signerAddress } = await service.signPayload( @@ -256,30 +256,30 @@ describe("PayloadSigningService", () => { }); }); - describe("getDomain", () => { - it("should return the EIP-712 domain", () => { + describe('getDomain', () => { + it('should return the EIP-712 domain', () => { const domain = service.getDomain(); - expect(domain.name).toBe("alian-structure Oracle"); - expect(domain.version).toBe("1"); + expect(domain.name).toBe('alian-structure Oracle'); + expect(domain.version).toBe('1'); expect(domain.chainId).toBe(1); expect(domain.verifyingContract).toBe( - "0x1234567890123456789012345678901234567890", + '0x1234567890123456789012345678901234567890', ); }); }); - describe("getTypes", () => { - it("should return the EIP-712 types", () => { + describe('getTypes', () => { + it('should return the EIP-712 types', () => { const types = service.getTypes(); expect(types.OraclePayload).toBeDefined(); expect(types.OraclePayload).toHaveLength(5); - expect(types.OraclePayload[0].name).toBe("payloadType"); - expect(types.OraclePayload[1].name).toBe("payloadHash"); - expect(types.OraclePayload[2].name).toBe("nonce"); - expect(types.OraclePayload[3].name).toBe("expiresAt"); - expect(types.OraclePayload[4].name).toBe("data"); + expect(types.OraclePayload[0].name).toBe('payloadType'); + expect(types.OraclePayload[1].name).toBe('payloadHash'); + expect(types.OraclePayload[2].name).toBe('nonce'); + expect(types.OraclePayload[3].name).toBe('expiresAt'); + expect(types.OraclePayload[4].name).toBe('data'); }); }); }); diff --git a/test/portfolio/mpt.spec.ts b/test/portfolio/mpt.spec.ts index 6d19533..f162b7c 100644 --- a/test/portfolio/mpt.spec.ts +++ b/test/portfolio/mpt.spec.ts @@ -1,26 +1,28 @@ -import { ModernPortfolioTheory } from "../../src/investment/portfolio/algorithms/modern-portfolio-theory"; +import { ModernPortfolioTheory } from '../../src/investment/portfolio/algorithms/modern-portfolio-theory'; -describe("ModernPortfolioTheory", () => { - describe("calculatePortfolioMetrics", () => { - it("should calculate portfolio metrics correctly", () => { +describe('ModernPortfolioTheory', () => { + describe('calculatePortfolioMetrics', () => { + it('should calculate portfolio metrics correctly', () => { const weights = [0.6, 0.4]; const expectedReturns = [0.08, 0.12]; const correlationMatrix = [ [1, 0.5], [0.5, 1], ]; - const volatilities = [0.15, 0.2]; + const volatilities = [0.15, 0.20]; - const covarianceMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covarianceMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); - const metrics = ModernPortfolioTheory.calculatePortfolioMetrics( - weights, - expectedReturns, - covarianceMatrix, - ); + const metrics = + ModernPortfolioTheory.calculatePortfolioMetrics( + weights, + expectedReturns, + covarianceMatrix, + ); expect(metrics.weights).toEqual(weights); expect(metrics.expectedReturn).toBeCloseTo(0.096); @@ -29,18 +31,19 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("calculateCovarianceMatrix", () => { - it("should calculate covariance matrix from correlation and volatilities", () => { - const volatilities = [0.15, 0.2]; + describe('calculateCovarianceMatrix', () => { + it('should calculate covariance matrix from correlation and volatilities', () => { + const volatilities = [0.15, 0.20]; const correlationMatrix = [ [1, 0.5], [0.5, 1], ]; - const covMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); expect(covMatrix[0][0]).toBeCloseTo(0.0225); // 0.15^2 expect(covMatrix[1][1]).toBeCloseTo(0.04); // 0.20^2 @@ -48,45 +51,49 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("pearsonCorrelation", () => { - it("should calculate Pearson correlation correctly", () => { + describe('pearsonCorrelation', () => { + it('should calculate Pearson correlation correctly', () => { const x = [1, 2, 3, 4, 5]; const y = [2, 4, 6, 8, 10]; - const correlation = ModernPortfolioTheory.pearsonCorrelation(x, y); + const correlation = + ModernPortfolioTheory.pearsonCorrelation(x, y); expect(correlation).toBeCloseTo(1, 5); // Perfect positive correlation }); - it("should handle negative correlation", () => { + it('should handle negative correlation', () => { const x = [1, 2, 3, 4, 5]; const y = [10, 8, 6, 4, 2]; - const correlation = ModernPortfolioTheory.pearsonCorrelation(x, y); + const correlation = + ModernPortfolioTheory.pearsonCorrelation(x, y); expect(correlation).toBeCloseTo(-1, 5); // Perfect negative correlation }); }); - describe("meanVarianceOptimization", () => { - it("should optimize portfolio using mean-variance", () => { - const expectedReturns = [0.08, 0.1, 0.12]; + describe('meanVarianceOptimization', () => { + it('should optimize portfolio using mean-variance', () => { + const expectedReturns = [0.08, 0.10, 0.12]; const correlationMatrix = [ [1, 0.5, 0.3], [0.5, 1, 0.4], [0.3, 0.4, 1], ]; - const volatilities = [0.15, 0.18, 0.2]; + const volatilities = [0.15, 0.18, 0.20]; - const covarianceMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covarianceMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); - const weights = ModernPortfolioTheory.meanVarianceOptimization( - expectedReturns, - covarianceMatrix, - ); + const weights = + ModernPortfolioTheory.meanVarianceOptimization( + expectedReturns, + covarianceMatrix, + ); const sum = weights.reduce((a, b) => a + b); expect(sum).toBeCloseTo(1, 5); @@ -94,21 +101,24 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("minVarianceOptimization", () => { - it("should find minimum variance portfolio", () => { + describe('minVarianceOptimization', () => { + it('should find minimum variance portfolio', () => { const correlationMatrix = [ [1, 0.5], [0.5, 1], ]; - const volatilities = [0.15, 0.2]; + const volatilities = [0.15, 0.20]; - const covarianceMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covarianceMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); const weights = - ModernPortfolioTheory.minVarianceOptimization(covarianceMatrix); + ModernPortfolioTheory.minVarianceOptimization( + covarianceMatrix, + ); const sum = weights.reduce((a, b) => a + b); expect(sum).toBeCloseTo(1, 5); @@ -116,21 +126,24 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("riskParityOptimization", () => { - it("should create risk parity portfolio", () => { + describe('riskParityOptimization', () => { + it('should create risk parity portfolio', () => { const correlationMatrix = [ [1, 0.3], [0.3, 1], ]; - const volatilities = [0.1, 0.2]; + const volatilities = [0.10, 0.20]; - const covarianceMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covarianceMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); const weights = - ModernPortfolioTheory.riskParityOptimization(covarianceMatrix); + ModernPortfolioTheory.riskParityOptimization( + covarianceMatrix, + ); const sum = weights.reduce((a, b) => a + b); expect(sum).toBeCloseTo(1, 5); @@ -140,40 +153,43 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("calculateValueAtRisk", () => { - it("should calculate VaR correctly", () => { - const var95 = ModernPortfolioTheory.calculateValueAtRisk( - 0.05, - 0.15, - 0.95, - 100000, - ); + describe('calculateValueAtRisk', () => { + it('should calculate VaR correctly', () => { + const var95 = + ModernPortfolioTheory.calculateValueAtRisk( + 0.05, + 0.15, + 0.95, + 100000, + ); expect(var95).toBeGreaterThan(0); expect(var95).toBeLessThan(100000); }); }); - describe("efficientFrontier", () => { - it("should generate efficient frontier", () => { - const expectedReturns = [0.08, 0.1, 0.12]; + describe('efficientFrontier', () => { + it('should generate efficient frontier', () => { + const expectedReturns = [0.08, 0.10, 0.12]; const correlationMatrix = [ [1, 0.5, 0.3], [0.5, 1, 0.4], [0.3, 0.4, 1], ]; - const volatilities = [0.15, 0.18, 0.2]; + const volatilities = [0.15, 0.18, 0.20]; - const covarianceMatrix = ModernPortfolioTheory.calculateCovarianceMatrix( - volatilities, - correlationMatrix, - ); + const covarianceMatrix = + ModernPortfolioTheory.calculateCovarianceMatrix( + volatilities, + correlationMatrix, + ); - const frontier = ModernPortfolioTheory.efficientFrontier( - expectedReturns, - covarianceMatrix, - 10, - ); + const frontier = + ModernPortfolioTheory.efficientFrontier( + expectedReturns, + covarianceMatrix, + 10, + ); expect(frontier.length).toBe(10); expect(frontier[0].volatility).toBeLessThanOrEqual( @@ -182,18 +198,19 @@ describe("ModernPortfolioTheory", () => { }); }); - describe("applyConstraints", () => { - it("should apply weight constraints", () => { + describe('applyConstraints', () => { + it('should apply weight constraints', () => { const weights = [0.3, 0.5, 0.2]; const constraints = { minWeight: 0.1, maxWeight: 0.6, }; - const constrained = ModernPortfolioTheory.applyConstraints( - weights, - constraints, - ); + const constrained = + ModernPortfolioTheory.applyConstraints( + weights, + constraints, + ); for (const w of constrained) { expect(w).toBeGreaterThanOrEqual(0.1); diff --git a/test/portfolio/portfolio-management.e2e-spec.ts b/test/portfolio/portfolio-management.e2e-spec.ts index b93534b..37d6492 100644 --- a/test/portfolio/portfolio-management.e2e-spec.ts +++ b/test/portfolio/portfolio-management.e2e-spec.ts @@ -116,3 +116,4 @@ describe("Portfolio Management REST API", () => { expect([400, 404, 401]).toContain(res.status); }, 15_000); }); + diff --git a/test/portfolio/portfolio.service.spec.ts b/test/portfolio/portfolio.service.spec.ts index a372771..4f20439 100644 --- a/test/portfolio/portfolio.service.spec.ts +++ b/test/portfolio/portfolio.service.spec.ts @@ -1,22 +1,15 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { getRepositoryToken } from "@nestjs/typeorm"; -import { PortfolioService } from "../../src/investment/portfolio/services/portfolio.service"; -import { Portfolio } from "../../src/investment/portfolio/entities/portfolio.entity"; -import { - PortfolioAsset, - Chain, - AssetType, -} from "../../src/investment/portfolio/entities/portfolio-asset.entity"; -import { OptimizationHistory } from "../../src/investment/portfolio/entities/optimization-history.entity"; -import { RiskProfile } from "../../src/investment/portfolio/entities/risk-profile.entity"; -import { CreatePortfolioDto } from "../../src/investment/portfolio/dto/portfolio.dto"; -import { OptimizationMethod } from "../../src/investment/portfolio/entities/optimization-history.entity"; -import { - AddHoldingDto, - UpdateHoldingDto, -} from "../../src/investment/portfolio/dto/portfolio-asset.dto"; - -describe("PortfolioService", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { PortfolioService } from '../../src/investment/portfolio/services/portfolio.service'; +import { Portfolio } from '../../src/investment/portfolio/entities/portfolio.entity'; +import { PortfolioAsset, Chain, AssetType } from '../../src/investment/portfolio/entities/portfolio-asset.entity'; +import { OptimizationHistory } from '../../src/investment/portfolio/entities/optimization-history.entity'; +import { RiskProfile } from '../../src/investment/portfolio/entities/risk-profile.entity'; +import { CreatePortfolioDto } from '../../src/investment/portfolio/dto/portfolio.dto'; +import { OptimizationMethod } from '../../src/investment/portfolio/entities/optimization-history.entity'; +import { AddHoldingDto, UpdateHoldingDto } from '../../src/investment/portfolio/dto/portfolio-asset.dto'; + +describe('PortfolioService', () => { let service: PortfolioService; let portfolioRepository: any; let assetRepository: any; @@ -42,9 +35,9 @@ describe("PortfolioService", () => { }; const mockAsset = { - id: "asset-1", - ticker: "AAPL", - name: "Apple", + id: 'asset-1', + ticker: 'AAPL', + name: 'Apple', chain: Chain.OTHER, quantity: 100, currentPrice: 150, @@ -444,11 +437,11 @@ describe("PortfolioService", () => { }); }); - describe("addHolding", () => { - it("should add a new holding to portfolio", async () => { + describe('addHolding', () => { + it('should add a new holding to portfolio', async () => { const dto: AddHoldingDto = { - ticker: "ETH", - name: "Ethereum", + ticker: 'ETH', + name: 'Ethereum', chain: Chain.ETHEREUM, quantity: 10, currentPrice: 2000, @@ -459,14 +452,10 @@ describe("PortfolioService", () => { assetRepository.create.mockReturnValue({ ...mockAsset, ...dto }); assetRepository.save.mockResolvedValue({ ...mockAsset, ...dto }); - const result = await service.addHolding("test-portfolio-1", dto); + const result = await service.addHolding('test-portfolio-1', dto); expect(assetRepository.findOne).toHaveBeenCalledWith({ - where: { - portfolioId: "test-portfolio-1", - ticker: dto.ticker, - chain: dto.chain, - }, + where: { portfolioId: 'test-portfolio-1', ticker: dto.ticker, chain: dto.chain }, }); expect(assetRepository.create).toHaveBeenCalled(); expect(assetRepository.save).toHaveBeenCalled(); @@ -474,10 +463,10 @@ describe("PortfolioService", () => { expect(result.chain).toBe(dto.chain); }); - it("should throw error if holding already exists", async () => { + it('should throw error if holding already exists', async () => { const dto: AddHoldingDto = { - ticker: "ETH", - name: "Ethereum", + ticker: 'ETH', + name: 'Ethereum', chain: Chain.ETHEREUM, quantity: 10, currentPrice: 2000, @@ -486,14 +475,14 @@ describe("PortfolioService", () => { assetRepository.findOne.mockResolvedValue(mockAsset); - await expect(service.addHolding("test-portfolio-1", dto)).rejects.toThrow( - "Holding with same ticker and chain already exists", - ); + await expect( + service.addHolding('test-portfolio-1', dto), + ).rejects.toThrow('Holding with same ticker and chain already exists'); }); }); - describe("updateHolding", () => { - it("should update holding in portfolio", async () => { + describe('updateHolding', () => { + it('should update holding in portfolio', async () => { const dto: UpdateHoldingDto = { quantity: 20, currentPrice: 2500, @@ -503,47 +492,43 @@ describe("PortfolioService", () => { assetRepository.findOne.mockResolvedValue(mockAsset); assetRepository.save.mockResolvedValue(updatedAsset); - const result = await service.updateHolding( - "test-portfolio-1", - "asset-1", - dto, - ); + const result = await service.updateHolding('test-portfolio-1', 'asset-1', dto); expect(assetRepository.findOne).toHaveBeenCalledWith({ - where: { id: "asset-1", portfolioId: "test-portfolio-1" }, + where: { id: 'asset-1', portfolioId: 'test-portfolio-1' }, }); expect(assetRepository.save).toHaveBeenCalled(); }); - it("should throw error if holding not found", async () => { + it('should throw error if holding not found', async () => { const dto: UpdateHoldingDto = { quantity: 20 }; assetRepository.findOne.mockResolvedValue(null); await expect( - service.updateHolding("test-portfolio-1", "non-existent", dto), - ).rejects.toThrow("Holding not found"); + service.updateHolding('test-portfolio-1', 'non-existent', dto), + ).rejects.toThrow('Holding not found'); }); }); - describe("removeHolding", () => { - it("should remove holding from portfolio", async () => { + describe('removeHolding', () => { + it('should remove holding from portfolio', async () => { assetRepository.findOne.mockResolvedValue(mockAsset); assetRepository.remove.mockResolvedValue(null); - await service.removeHolding("test-portfolio-1", "asset-1"); + await service.removeHolding('test-portfolio-1', 'asset-1'); expect(assetRepository.findOne).toHaveBeenCalledWith({ - where: { id: "asset-1", portfolioId: "test-portfolio-1" }, + where: { id: 'asset-1', portfolioId: 'test-portfolio-1' }, }); expect(assetRepository.remove).toHaveBeenCalledWith(mockAsset); }); - it("should throw error if holding not found", async () => { + it('should throw error if holding not found', async () => { assetRepository.findOne.mockResolvedValue(null); await expect( - service.removeHolding("test-portfolio-1", "non-existent"), - ).rejects.toThrow("Holding not found"); + service.removeHolding('test-portfolio-1', 'non-existent'), + ).rejects.toThrow('Holding not found'); }); }); }); diff --git a/test/recovery.spec.ts b/test/recovery.spec.ts index 2df4fbb..e712f29 100644 --- a/test/recovery.spec.ts +++ b/test/recovery.spec.ts @@ -1,21 +1,21 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { NotFoundException } from "@nestjs/common"; -import { RecoveryService } from "../src/core/auth/recovery.service"; -import { EmailLinkingService } from "../src/core/auth/email-linking.service"; -import { EmailService } from "../src/core/auth/email.service"; -import { ChallengeService } from "../src/core/auth/challenge.service"; -import { User } from "../src/core/user/entities/user.entity"; - -describe("RecoveryService", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { NotFoundException } from '@nestjs/common'; +import { RecoveryService } from '../src/core/auth/recovery.service'; +import { EmailLinkingService } from '../src/core/auth/email-linking.service'; +import { EmailService } from '../src/core/auth/email.service'; +import { ChallengeService } from '../src/core/auth/challenge.service'; +import { User } from '../src/core/user/entities/user.entity'; + +describe('RecoveryService', () => { let service: RecoveryService; let emailLinkingService: EmailLinkingService; let emailService: EmailService; let challengeService: ChallengeService; const mockUser: User = { - id: "123", - walletAddress: "0x1234567890123456789012345678901234567890", - email: "test@example.com", + id: '123', + walletAddress: '0x1234567890123456789012345678901234567890', + email: 'test@example.com', emailVerified: true, createdAt: new Date(), updatedAt: new Date(), @@ -27,15 +27,15 @@ describe("RecoveryService", () => { const mockEmailService = { sendRecoveryEmail: jest.fn().mockResolvedValue({ - messageId: "test-message-id", - previewUrl: "https://ethereal.email/message/test", + messageId: 'test-message-id', + previewUrl: 'https://ethereal.email/message/test', }), }; const mockChallengeService = { - issueChallengeForAddress: jest - .fn() - .mockReturnValue("Sign this message to authenticate: abc123"), + issueChallengeForAddress: jest.fn().mockReturnValue( + 'Sign this message to authenticate: abc123', + ), }; beforeEach(async () => { @@ -63,63 +63,54 @@ describe("RecoveryService", () => { challengeService = module.get(ChallengeService); }); - describe("requestRecovery", () => { - it("should send recovery email for verified account", async () => { - jest - .spyOn(emailLinkingService, "getUserByEmail") - .mockResolvedValue(mockUser); + describe('requestRecovery', () => { + it('should send recovery email for verified account', async () => { + jest.spyOn(emailLinkingService, 'getUserByEmail').mockResolvedValue(mockUser); - const result = await service.requestRecovery("test@example.com"); + const result = await service.requestRecovery('test@example.com'); - expect(result.message).toContain("Recovery information sent"); + expect(result.message).toContain('Recovery information sent'); expect(emailService.sendRecoveryEmail).toHaveBeenCalledWith( - "test@example.com", + 'test@example.com', mockUser.walletAddress, ); }); - it("should throw error for non-existent email", async () => { - jest.spyOn(emailLinkingService, "getUserByEmail").mockResolvedValue(null); + it('should throw error for non-existent email', async () => { + jest.spyOn(emailLinkingService, 'getUserByEmail').mockResolvedValue(null); - await expect( - service.requestRecovery("nonexistent@example.com"), - ).rejects.toThrow(NotFoundException); + await expect(service.requestRecovery('nonexistent@example.com')).rejects.toThrow( + NotFoundException, + ); }); - it("should normalize email to lowercase", async () => { - jest - .spyOn(emailLinkingService, "getUserByEmail") - .mockResolvedValue(mockUser); + it('should normalize email to lowercase', async () => { + jest.spyOn(emailLinkingService, 'getUserByEmail').mockResolvedValue(mockUser); - await service.requestRecovery("TEST@EXAMPLE.COM"); + await service.requestRecovery('TEST@EXAMPLE.COM'); - expect(emailLinkingService.getUserByEmail).toHaveBeenCalledWith( - "test@example.com", - ); + expect(emailLinkingService.getUserByEmail).toHaveBeenCalledWith('test@example.com'); }); }); - describe("verifyRecoveryAndGetChallenge", () => { - it("should return challenge for verified email", async () => { - jest - .spyOn(emailLinkingService, "getUserByEmail") - .mockResolvedValue(mockUser); + describe('verifyRecoveryAndGetChallenge', () => { + it('should return challenge for verified email', async () => { + jest.spyOn(emailLinkingService, 'getUserByEmail').mockResolvedValue(mockUser); - const result = - await service.verifyRecoveryAndGetChallenge("test@example.com"); + const result = await service.verifyRecoveryAndGetChallenge('test@example.com'); - expect(result.message).toContain("Sign this message"); + expect(result.message).toContain('Sign this message'); expect(result.walletAddress).toBe(mockUser.walletAddress); expect(challengeService.issueChallengeForAddress).toHaveBeenCalledWith( mockUser.walletAddress, ); }); - it("should throw error for non-existent email", async () => { - jest.spyOn(emailLinkingService, "getUserByEmail").mockResolvedValue(null); + it('should throw error for non-existent email', async () => { + jest.spyOn(emailLinkingService, 'getUserByEmail').mockResolvedValue(null); await expect( - service.verifyRecoveryAndGetChallenge("nonexistent@example.com"), + service.verifyRecoveryAndGetChallenge('nonexistent@example.com'), ).rejects.toThrow(NotFoundException); }); }); diff --git a/test/traditional-auth.e2e-spec.ts b/test/traditional-auth.e2e-spec.ts index fe7375d..66c4cb8 100644 --- a/test/traditional-auth.e2e-spec.ts +++ b/test/traditional-auth.e2e-spec.ts @@ -1,9 +1,9 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication, ValidationPipe } from "@nestjs/common"; -import * as request from "supertest"; -import { AuthModule } from "../src/core/auth/auth.module"; +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; +import * as request from 'supertest'; +import { AuthModule } from '../src/core/auth/auth.module'; -describe("Traditional Authentication (e2e)", () => { +describe('Traditional Authentication (e2e)', () => { let app: INestApplication; beforeAll(async () => { @@ -20,180 +20,188 @@ describe("Traditional Authentication (e2e)", () => { await app.close(); }); - describe("/auth/register (POST)", () => { - it("should register a new user", () => { + describe('/auth/register (POST)', () => { + it('should register a new user', () => { return request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "test@example.com", - password: "password123", - username: "testuser", + email: 'test@example.com', + password: 'password123', + username: 'testuser', }) .expect(201) .expect((res) => { - expect(res.body).toHaveProperty("token"); - expect(res.body).toHaveProperty("user"); - expect(res.body.user.email).toBe("test@example.com"); - expect(res.body.user.username).toBe("testuser"); + expect(res.body).toHaveProperty('token'); + expect(res.body).toHaveProperty('user'); + expect(res.body.user.email).toBe('test@example.com'); + expect(res.body.user.username).toBe('testuser'); }); }); - it("should reject registration with existing email", async () => { + it('should reject registration with existing email', async () => { // First register a user - await request(app.getHttpServer()).post("/auth/register").send({ - email: "duplicate@example.com", - password: "password123", - username: "user1", - }); + await request(app.getHttpServer()) + .post('/auth/register') + .send({ + email: 'duplicate@example.com', + password: 'password123', + username: 'user1', + }); // Try to register again with same email return request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "duplicate@example.com", - password: "password456", - username: "user2", + email: 'duplicate@example.com', + password: 'password456', + username: 'user2', }) .expect(409); }); - it("should reject registration with invalid email", () => { + it('should reject registration with invalid email', () => { return request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "invalid-email", - password: "password123", - username: "testuser", + email: 'invalid-email', + password: 'password123', + username: 'testuser', }) .expect(400); }); - it("should reject registration with short password", () => { + it('should reject registration with short password', () => { return request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "test@example.com", - password: "123", - username: "testuser", + email: 'test@example.com', + password: '123', + username: 'testuser', }) .expect(400); }); }); - describe("/auth/login (POST)", () => { + describe('/auth/login (POST)', () => { beforeEach(async () => { // Register a test user - await request(app.getHttpServer()).post("/auth/register").send({ - email: "login@example.com", - password: "password123", - username: "logintest", - }); + await request(app.getHttpServer()) + .post('/auth/register') + .send({ + email: 'login@example.com', + password: 'password123', + username: 'logintest', + }); }); - it("should login with correct credentials", () => { + it('should login with correct credentials', () => { return request(app.getHttpServer()) - .post("/auth/login") + .post('/auth/login') .send({ - email: "login@example.com", - password: "password123", + email: 'login@example.com', + password: 'password123', }) .expect(201) .expect((res) => { - expect(res.body).toHaveProperty("token"); - expect(res.body).toHaveProperty("user"); - expect(res.body.user.email).toBe("login@example.com"); + expect(res.body).toHaveProperty('token'); + expect(res.body).toHaveProperty('user'); + expect(res.body.user.email).toBe('login@example.com'); }); }); - it("should reject login with wrong password", () => { + it('should reject login with wrong password', () => { return request(app.getHttpServer()) - .post("/auth/login") + .post('/auth/login') .send({ - email: "login@example.com", - password: "wrongpassword", + email: 'login@example.com', + password: 'wrongpassword', }) .expect(401); }); - it("should reject login with non-existent email", () => { + it('should reject login with non-existent email', () => { return request(app.getHttpServer()) - .post("/auth/login") + .post('/auth/login') .send({ - email: "nonexistent@example.com", - password: "password123", + email: 'nonexistent@example.com', + password: 'password123', }) .expect(401); }); }); - describe("/auth/status (GET)", () => { + describe('/auth/status (GET)', () => { let token: string; beforeEach(async () => { // Register and login to get token const registerResponse = await request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "status@example.com", - password: "password123", - username: "statustest", + email: 'status@example.com', + password: 'password123', + username: 'statustest', }); token = registerResponse.body.token; }); - it("should return auth status for authenticated user", () => { + it('should return auth status for authenticated user', () => { return request(app.getHttpServer()) - .get("/auth/status") - .set("Authorization", `Bearer ${token}`) + .get('/auth/status') + .set('Authorization', `Bearer ${token}`) .expect(200) .expect((res) => { expect(res.body.isAuthenticated).toBe(true); - expect(res.body.user.email).toBe("status@example.com"); - expect(res.body.user.username).toBe("statustest"); + expect(res.body.user.email).toBe('status@example.com'); + expect(res.body.user.username).toBe('statustest'); }); }); - it("should reject request without token", () => { - return request(app.getHttpServer()).get("/auth/status").expect(401); + it('should reject request without token', () => { + return request(app.getHttpServer()) + .get('/auth/status') + .expect(401); }); - it("should reject request with invalid token", () => { + it('should reject request with invalid token', () => { return request(app.getHttpServer()) - .get("/auth/status") - .set("Authorization", "Bearer invalid-token") + .get('/auth/status') + .set('Authorization', 'Bearer invalid-token') .expect(401); }); }); - describe("/auth/logout (POST)", () => { + describe('/auth/logout (POST)', () => { let token: string; beforeEach(async () => { // Register and login to get token const registerResponse = await request(app.getHttpServer()) - .post("/auth/register") + .post('/auth/register') .send({ - email: "logout@example.com", - password: "password123", - username: "logouttest", + email: 'logout@example.com', + password: 'password123', + username: 'logouttest', }); token = registerResponse.body.token; }); - it("should logout successfully", () => { + it('should logout successfully', () => { return request(app.getHttpServer()) - .post("/auth/logout") - .set("Authorization", `Bearer ${token}`) + .post('/auth/logout') + .set('Authorization', `Bearer ${token}`) .expect(201) .expect((res) => { - expect(res.body.message).toBe("Logged out successfully"); + expect(res.body.message).toBe('Logged out successfully'); }); }); - it("should reject logout without token", () => { - return request(app.getHttpServer()).post("/auth/logout").expect(401); + it('should reject logout without token', () => { + return request(app.getHttpServer()) + .post('/auth/logout') + .expect(401); }); }); -}); +}); \ No newline at end of file diff --git a/test/wallet-auth.spec.ts b/test/wallet-auth.spec.ts index 934f753..9336037 100644 --- a/test/wallet-auth.spec.ts +++ b/test/wallet-auth.spec.ts @@ -1,11 +1,11 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { JwtService } from "@nestjs/jwt"; -import { UnauthorizedException } from "@nestjs/common"; -import { WalletAuthService } from "../src/core/auth/wallet-auth.service"; -import { ChallengeService } from "../src/core/auth/challenge.service"; -import { Wallet } from "ethers"; - -describe("Wallet Authentication", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { JwtService } from '@nestjs/jwt'; +import { UnauthorizedException } from '@nestjs/common'; +import { WalletAuthService } from '../src/core/auth/wallet-auth.service'; +import { ChallengeService } from '../src/core/auth/challenge.service'; +import { Wallet } from 'ethers'; + +describe('Wallet Authentication', () => { let walletAuthService: WalletAuthService; let challengeService: ChallengeService; let jwtService: JwtService; @@ -20,13 +20,13 @@ describe("Wallet Authentication", () => { provide: JwtService, useValue: { sign: (payload) => { - return "test-token-" + JSON.stringify(payload); + return 'test-token-' + JSON.stringify(payload); }, verify: (token) => { - if (token.startsWith("test-token-")) { - return JSON.parse(token.replace("test-token-", "")); + if (token.startsWith('test-token-')) { + return JSON.parse(token.replace('test-token-', '')); } - throw new Error("Invalid token"); + throw new Error('Invalid token'); }, }, }, @@ -41,16 +41,16 @@ describe("Wallet Authentication", () => { testWallet = Wallet.createRandom(); }); - describe("Challenge Issuance", () => { - it("should issue a valid challenge for an address", () => { + describe('Challenge Issuance', () => { + it('should issue a valid challenge for an address', () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); - expect(message).toContain("Sign this message to authenticate:"); + expect(message).toContain('Sign this message to authenticate:'); expect(message).toBeTruthy(); }); - it("should extract challenge ID from message", () => { + it('should extract challenge ID from message', () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); const challengeId = challengeService.extractChallengeId(message); @@ -59,7 +59,7 @@ describe("Wallet Authentication", () => { expect(challengeId).toHaveLength(64); // 32 bytes hex }); - it("should store challenge with expiration", () => { + it('should store challenge with expiration', () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); const challengeId = challengeService.extractChallengeId(message); @@ -72,8 +72,8 @@ describe("Wallet Authentication", () => { }); }); - describe("Signature Verification", () => { - it("should verify a valid signature and return JWT token", async () => { + describe('Signature Verification', () => { + it('should verify a valid signature and return JWT token', async () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); @@ -89,23 +89,20 @@ describe("Wallet Authentication", () => { expect(result.address).toBe(address.toLowerCase()); }); - it("should reject an invalid signature", async () => { + it('should reject an invalid signature', async () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); // Create an invalid signature const invalidSignature = - "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + '0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; await expect( - walletAuthService.verifySignatureAndIssueToken( - message, - invalidSignature, - ), + walletAuthService.verifySignatureAndIssueToken(message, invalidSignature), ).rejects.toThrow(UnauthorizedException); }); - it("should reject signature from different address", async () => { + it('should reject signature from different address', async () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); @@ -118,7 +115,7 @@ describe("Wallet Authentication", () => { ).rejects.toThrow(UnauthorizedException); }); - it("should reject expired challenge", async () => { + it('should reject expired challenge', async () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); const challengeId = challengeService.extractChallengeId(message); @@ -132,12 +129,12 @@ describe("Wallet Authentication", () => { walletAuthService.verifySignatureAndIssueToken(message, signature), ).rejects.toThrow( new UnauthorizedException( - "Challenge not found or expired. Please request a new challenge.", + 'Challenge not found or expired. Please request a new challenge.', ), ); }); - it("should consume challenge after successful verification", async () => { + it('should consume challenge after successful verification', async () => { const address = testWallet.address; const message = challengeService.issueChallengeForAddress(address); const challengeId = challengeService.extractChallengeId(message); @@ -152,8 +149,8 @@ describe("Wallet Authentication", () => { }); }); - describe("JWT Token Validation", () => { - it("should validate a correct token", () => { + describe('JWT Token Validation', () => { + it('should validate a correct token', () => { const payload = { address: testWallet.address.toLowerCase(), iat: 0 }; const token = jwtService.sign(payload); @@ -162,8 +159,8 @@ describe("Wallet Authentication", () => { expect(result.address).toBe(payload.address); }); - it("should reject an invalid token", () => { - const invalidToken = "invalid-token"; + it('should reject an invalid token', () => { + const invalidToken = 'invalid-token'; expect(() => { walletAuthService.validateToken(invalidToken); @@ -171,13 +168,13 @@ describe("Wallet Authentication", () => { }); }); - describe("End-to-End Authentication Flow", () => { - it("should complete full authentication flow", async () => { + describe('End-to-End Authentication Flow', () => { + it('should complete full authentication flow', async () => { const address = testWallet.address; // 1. Request challenge const message = challengeService.issueChallengeForAddress(address); - expect(message).toContain("Sign this message to authenticate:"); + expect(message).toContain('Sign this message to authenticate:'); // 2. Sign message const signature = await testWallet.signMessage(message); diff --git a/test/wallet-management.e2e-spec.ts b/test/wallet-management.e2e-spec.ts index 7dbe39b..e43a721 100644 --- a/test/wallet-management.e2e-spec.ts +++ b/test/wallet-management.e2e-spec.ts @@ -1,20 +1,20 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication, ValidationPipe } from "@nestjs/common"; -import * as request from "supertest"; -import { AppModule } from "../src/app.module"; -import { getRepositoryToken } from "@nestjs/typeorm"; -import { User, UserRole } from "../src/core/user/entities/user.entity"; -import { Repository } from "typeorm"; - -describe("Wallet Management (e2e)", () => { +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from '../src/app.module'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { User, UserRole } from '../src/core/user/entities/user.entity'; +import { Repository } from 'typeorm'; + +describe('Wallet Management (e2e)', () => { let app: INestApplication; let userRepository: Repository; let authToken: string; let testUser: User; - const testWalletAddress = "0x1234567890abcdef1234567890abcdef12345678"; - const newWalletAddress = "0xabcdefabcdefabcdefabcdefabcdefabcdefabcd"; - const testEmail = "test@example.com"; + const testWalletAddress = '0x1234567890abcdef1234567890abcdef12345678'; + const newWalletAddress = '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd'; + const testEmail = 'test@example.com'; beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ @@ -40,13 +40,13 @@ describe("Wallet Management (e2e)", () => { // Get auth token const challengeResponse = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: testWalletAddress }) .expect(201); // In real test, you would sign the challenge // For now, we'll mock the token - authToken = "mock-jwt-token"; + authToken = 'mock-jwt-token'; }); afterAll(async () => { @@ -57,53 +57,53 @@ describe("Wallet Management (e2e)", () => { await app.close(); }); - describe("POST /auth/link-wallet", () => { - it("should require authentication", async () => { + describe('POST /auth/link-wallet', () => { + it('should require authentication', async () => { return request(app.getHttpServer()) - .post("/auth/link-wallet") + .post('/auth/link-wallet') .send({ walletAddress: newWalletAddress, - message: "test message", - signature: "0x" + "1".repeat(130), + message: 'test message', + signature: '0x' + '1'.repeat(130), }) .expect(401); }); - it("should validate wallet address format", async () => { + it('should validate wallet address format', async () => { return request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ - walletAddress: "invalid-address", - message: "test message", - signature: "0x" + "1".repeat(130), + walletAddress: 'invalid-address', + message: 'test message', + signature: '0x' + '1'.repeat(130), }) .expect(400); }); - it("should validate signature length", async () => { + it('should validate signature length', async () => { return request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ walletAddress: newWalletAddress, - message: "test message", - signature: "0x123", // Too short + message: 'test message', + signature: '0x123', // Too short }) .expect(400); }); - it("should enforce rate limiting", async () => { + it('should enforce rate limiting', async () => { const requests = []; for (let i = 0; i < 6; i++) { requests.push( request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ walletAddress: newWalletAddress, - message: "test message", - signature: "0x" + "1".repeat(130), + message: 'test message', + signature: '0x' + '1'.repeat(130), }), ); } @@ -114,51 +114,51 @@ describe("Wallet Management (e2e)", () => { }); }); - describe("POST /auth/unlink-wallet", () => { - it("should require authentication", async () => { + describe('POST /auth/unlink-wallet', () => { + it('should require authentication', async () => { return request(app.getHttpServer()) - .post("/auth/unlink-wallet") + .post('/auth/unlink-wallet') .send({ walletAddress: testWalletAddress }) .expect(401); }); - it("should validate wallet address format", async () => { + it('should validate wallet address format', async () => { return request(app.getHttpServer()) - .post("/auth/unlink-wallet") - .set("Authorization", `Bearer ${authToken}`) - .send({ walletAddress: "invalid-address" }) + .post('/auth/unlink-wallet') + .set('Authorization', `Bearer ${authToken}`) + .send({ walletAddress: 'invalid-address' }) .expect(400); }); - it("should require verified email before unlinking", async () => { + it('should require verified email before unlinking', async () => { // Create user without verified email const unverifiedUser = userRepository.create({ - walletAddress: "0x9999999999999999999999999999999999999999", - email: "unverified@example.com", + walletAddress: '0x9999999999999999999999999999999999999999', + email: 'unverified@example.com', emailVerified: false, role: UserRole.USER, }); await userRepository.save(unverifiedUser); const response = await request(app.getHttpServer()) - .post("/auth/unlink-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/unlink-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ walletAddress: unverifiedUser.walletAddress }) .expect(400); - expect(response.body.message).toContain("Email must be verified"); + expect(response.body.message).toContain('Email must be verified'); // Cleanup await userRepository.remove(unverifiedUser); }); - it("should enforce rate limiting", async () => { + it('should enforce rate limiting', async () => { const requests = []; for (let i = 0; i < 6; i++) { requests.push( request(app.getHttpServer()) - .post("/auth/unlink-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/unlink-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ walletAddress: testWalletAddress }), ); } @@ -169,51 +169,51 @@ describe("Wallet Management (e2e)", () => { }); }); - describe("POST /auth/recover-wallet", () => { - it("should validate email format", async () => { + describe('POST /auth/recover-wallet', () => { + it('should validate email format', async () => { return request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ - email: "invalid-email", - recoveryToken: "a".repeat(64), + email: 'invalid-email', + recoveryToken: 'a'.repeat(64), }) .expect(400); }); - it("should validate recovery token length", async () => { + it('should validate recovery token length', async () => { return request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ email: testEmail, - recoveryToken: "short", + recoveryToken: 'short', }) .expect(400); }); - it("should return challenge for valid recovery request", async () => { + it('should return challenge for valid recovery request', async () => { const response = await request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ email: testEmail, - recoveryToken: "a".repeat(64), + recoveryToken: 'a'.repeat(64), }) .expect(201); - expect(response.body).toHaveProperty("message"); - expect(response.body).toHaveProperty("walletAddress"); - expect(response.body).toHaveProperty("challenge"); + expect(response.body).toHaveProperty('message'); + expect(response.body).toHaveProperty('walletAddress'); + expect(response.body).toHaveProperty('challenge'); expect(response.body.walletAddress).toBe(testWalletAddress.toLowerCase()); }); - it("should enforce strict rate limiting (3 requests per minute)", async () => { + it('should enforce strict rate limiting (3 requests per minute)', async () => { const requests = []; for (let i = 0; i < 4; i++) { requests.push( request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ email: testEmail, - recoveryToken: "a".repeat(64), + recoveryToken: 'a'.repeat(64), }), ); } @@ -223,62 +223,62 @@ describe("Wallet Management (e2e)", () => { expect(rateLimited).toBe(true); }); - it("should return error for non-existent email", async () => { + it('should return error for non-existent email', async () => { return request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ - email: "nonexistent@example.com", - recoveryToken: "a".repeat(64), + email: 'nonexistent@example.com', + recoveryToken: 'a'.repeat(64), }) .expect(400); }); }); - describe("Wallet Management Flow", () => { - it("should complete full wallet linking flow", async () => { + describe('Wallet Management Flow', () => { + it('should complete full wallet linking flow', async () => { // 1. Request challenge for new wallet const challengeResponse = await request(app.getHttpServer()) - .post("/auth/challenge") + .post('/auth/challenge') .send({ address: newWalletAddress }) .expect(201); - expect(challengeResponse.body).toHaveProperty("message"); - expect(challengeResponse.body).toHaveProperty("address"); + expect(challengeResponse.body).toHaveProperty('message'); + expect(challengeResponse.body).toHaveProperty('address'); // 2. Link new wallet (would require real signature in production) // This would fail without proper signature, but tests the endpoint structure const linkResponse = await request(app.getHttpServer()) - .post("/auth/link-wallet") - .set("Authorization", `Bearer ${authToken}`) + .post('/auth/link-wallet') + .set('Authorization', `Bearer ${authToken}`) .send({ walletAddress: newWalletAddress, message: challengeResponse.body.message, - signature: "0x" + "1".repeat(130), + signature: '0x' + '1'.repeat(130), }); // Expect either success or signature validation error expect([200, 201, 401]).toContain(linkResponse.status); }); - it("should complete full wallet recovery flow", async () => { + it('should complete full wallet recovery flow', async () => { // 1. Request recovery const recoveryResponse = await request(app.getHttpServer()) - .post("/auth/recover-wallet") + .post('/auth/recover-wallet') .send({ email: testEmail, - recoveryToken: "a".repeat(64), + recoveryToken: 'a'.repeat(64), }) .expect(201); - expect(recoveryResponse.body).toHaveProperty("challenge"); - expect(recoveryResponse.body).toHaveProperty("walletAddress"); + expect(recoveryResponse.body).toHaveProperty('challenge'); + expect(recoveryResponse.body).toHaveProperty('walletAddress'); // 2. User would sign the challenge and verify const verifyResponse = await request(app.getHttpServer()) - .post("/auth/verify") + .post('/auth/verify') .send({ message: recoveryResponse.body.challenge, - signature: "0x" + "1".repeat(130), + signature: '0x' + '1'.repeat(130), }); // Expect either success or signature validation error diff --git a/tsconfig.json b/tsconfig.json index ba657f4..bd20141 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "target": "ES2021", "sourceMap": true, "outDir": "./dist", - "rootDir": "./", + "rootDir": "./src", "baseUrl": "./", "types": ["node", "jest"], "moduleResolution": "node", @@ -32,6 +32,6 @@ "src/*": ["src/*"] } }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules", "dist"] + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] } \ No newline at end of file