Files
defi-arbitrage/risk-control.service.ts

120 lines
3.3 KiB
TypeScript
Raw Permalink Normal View History

Initial commit: Deal orchestration tool - Freeze-resistant arbitrage loop - Implemented complete arbitrage loop (Steps 0-4) - Risk control service with hard caps (30% LTV, 25% USDTz exposure) - Progressive redemption testing (0k → 50k → cd /home/intlc/projects/proxmox/dbis_core/src/core/defi/arbitrage && git commit -m "Initial commit: Deal orchestration tool - Freeze-resistant arbitrage loop - Implemented complete arbitrage loop (Steps 0-4) - Risk control service with hard caps (30% LTV, 25% USDTz exposure) - Progressive redemption testing ($50k → $250k → $1M+) - Graceful failure handling and state management - CLI interface and programmatic API - Comprehensive documentation Features: - Capital split into three buckets (Core ETH, Working Liquidity, Opportunistic) - ETH wrapping and collateral supply - USDT borrowing at controlled LTV - Discount arbitrage execution - Partial monetization with redemption testing - Loop closing with profit capture Design Principles: - One-way risk only - Anchor asset (ETH) untouchable - No leverage on discounted assets - Independent leg settlement"M+) - Graceful failure handling and state management - CLI interface and programmatic API - Comprehensive documentation Features: - Capital split into three buckets (Core ETH, Working Liquidity, Opportunistic) - ETH wrapping and collateral supply - USDT borrowing at controlled LTV - Discount arbitrage execution - Partial monetization with redemption testing - Loop closing with profit capture Design Principles: - One-way risk only - Anchor asset (ETH) untouchable - No leverage on discounted assets - Independent leg settlement
2026-01-27 14:45:19 -08:00
// Risk Control Service
// Enforces hard caps and validates deal parameters
import { Decimal } from '@prisma/client/runtime/library';
import { logger } from '@/infrastructure/monitoring/logger';
import { DEFAULT_RISK_PARAMS } from './config';
import { RiskCheckResult, CapitalBuckets, DealExecutionRequest } from './types';
export class RiskControlService {
async validateDealRequest(
request: DealExecutionRequest,
currentNav: Decimal
): Promise<RiskCheckResult> {
const errors: string[] = [];
const maxLtv = new Decimal(request.maxLtv ?? DEFAULT_RISK_PARAMS.MAX_LTV);
const maxUsdtzExposure = currentNav.mul(
DEFAULT_RISK_PARAMS.MAX_USDTZ_EXPOSURE_PCT
);
if (maxLtv.gt(DEFAULT_RISK_PARAMS.MAX_LTV)) {
errors.push(
`Requested LTV ${maxLtv.toString()} exceeds maximum ${DEFAULT_RISK_PARAMS.MAX_LTV}`
);
}
const totalEth = new Decimal(request.totalEthValue);
const workingLiquidity = totalEth.mul(0.30);
const estimatedBorrow = workingLiquidity.mul(maxLtv);
const estimatedUsdtzPurchase = estimatedBorrow.div(
new Decimal(1).minus(
new Decimal(request.usdtzDiscountRate ?? DEFAULT_RISK_PARAMS.DEFAULT_USDTZ_DISCOUNT)
)
);
if (estimatedUsdtzPurchase.gt(maxUsdtzExposure)) {
errors.push(
`Estimated USDTz exposure ${estimatedUsdtzPurchase.toString()} exceeds maximum ${maxUsdtzExposure.toString()}`
);
}
return {
passed: errors.length === 0,
maxLtv: new Decimal(DEFAULT_RISK_PARAMS.MAX_LTV),
maxUsdtzExposure,
totalNav: currentNav,
errors,
};
}
async checkLtvCompliance(
collateralValue: Decimal,
borrowAmount: Decimal,
maxLtv: Decimal = new Decimal(DEFAULT_RISK_PARAMS.MAX_LTV)
): Promise<RiskCheckResult> {
const errors: string[] = [];
const ltv = borrowAmount.div(collateralValue);
if (ltv.gt(maxLtv)) {
errors.push(
`LTV ${ltv.mul(100).toFixed(2)}% exceeds maximum ${maxLtv.mul(100).toFixed(2)}%`
);
}
logger.info('LTV Check', {
collateralValue: collateralValue.toString(),
borrowAmount: borrowAmount.toString(),
ltv: ltv.mul(100).toFixed(2) + '%',
maxLtv: maxLtv.mul(100).toFixed(2) + '%',
passed: errors.length === 0,
});
return {
passed: errors.length === 0,
ltv,
maxLtv,
errors,
};
}
async checkUsdtzExposure(
usdtzAmount: Decimal,
totalNav: Decimal
): Promise<RiskCheckResult> {
const errors: string[] = [];
const maxExposure = totalNav.mul(DEFAULT_RISK_PARAMS.MAX_USDTZ_EXPOSURE_PCT);
if (usdtzAmount.gt(maxExposure)) {
errors.push(
`USDTz exposure ${usdtzAmount.toString()} exceeds maximum ${maxExposure.toString()}`
);
}
return {
passed: errors.length === 0,
usdtzExposure: usdtzAmount,
maxUsdtzExposure: maxExposure,
totalNav,
errors,
};
}
async validateNoRehypothecation(
usdtzAmount: Decimal,
collateralAssets: string[]
): Promise<RiskCheckResult> {
const errors: string[] = [];
if (collateralAssets.includes('USDTz')) {
errors.push('USDTz cannot be used as collateral (no rehypothecation)');
}
return {
passed: errors.length === 0,
errors,
};
}
}
export const riskControlService = new RiskControlService();