feat: Implement comprehensive DeFi platform in Digital Assets dashboard
Add a complete DeFi platform with the following features: - Tabbed interface for different DeFi functionalities - Lending & Borrowing system with APY calculations - Liquidity Pools with LP token rewards - Staking options for tokens and digital assets - Token Swap interface with real-time exchange rates - Collateralization system for loans and synthetic assets - Interactive JavaScript functionality for real-time calculations This enhancement provides users with a complete suite of DeFi tools directly integrated into the Digital Assets dashboard.
This commit is contained in:
		
							
								
								
									
										571
									
								
								actix_mvc_app/static/js/defi.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										571
									
								
								actix_mvc_app/static/js/defi.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,571 @@
 | 
			
		||||
// DeFi Platform JavaScript Functionality
 | 
			
		||||
 | 
			
		||||
document.addEventListener('DOMContentLoaded', function() {
 | 
			
		||||
    // Initialize tooltips
 | 
			
		||||
    var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
 | 
			
		||||
    var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
 | 
			
		||||
        return new bootstrap.Tooltip(tooltipTriggerEl);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // =============== LENDING & BORROWING TAB ===============
 | 
			
		||||
    // Lending form calculations
 | 
			
		||||
    const lendingAmountInput = document.getElementById('lendingAmount');
 | 
			
		||||
    const lendingAssetSelect = document.getElementById('lendingAsset');
 | 
			
		||||
    const lendingTermSelect = document.getElementById('lendingTerm');
 | 
			
		||||
    const estimatedReturnsElement = document.getElementById('estimatedReturns');
 | 
			
		||||
    const totalReturnElement = document.getElementById('totalReturn');
 | 
			
		||||
 | 
			
		||||
    if (lendingAmountInput && lendingAssetSelect && lendingTermSelect) {
 | 
			
		||||
        const calculateLendingReturns = () => {
 | 
			
		||||
            const amount = parseFloat(lendingAmountInput.value) || 0;
 | 
			
		||||
            const asset = lendingAssetSelect.value;
 | 
			
		||||
            const termDays = parseInt(lendingTermSelect.value) || 30;
 | 
			
		||||
            
 | 
			
		||||
            // Get APY from the selected option's text
 | 
			
		||||
            const selectedOption = lendingTermSelect.options[lendingTermSelect.selectedIndex];
 | 
			
		||||
            const apyMatch = selectedOption.text.match(/\((\d+\.\d+)%\)/);
 | 
			
		||||
            const apy = apyMatch ? parseFloat(apyMatch[1]) / 100 : 0.05; // Default to 5% if not found
 | 
			
		||||
            
 | 
			
		||||
            // Calculate returns (simple interest for demonstration)
 | 
			
		||||
            const returns = amount * apy * (termDays / 365);
 | 
			
		||||
            const total = amount + returns;
 | 
			
		||||
            
 | 
			
		||||
            if (estimatedReturnsElement) {
 | 
			
		||||
                estimatedReturnsElement.textContent = returns.toFixed(2) + ' ' + asset;
 | 
			
		||||
            }
 | 
			
		||||
            if (totalReturnElement) {
 | 
			
		||||
                totalReturnElement.textContent = total.toFixed(2) + ' ' + asset;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        lendingAmountInput.addEventListener('input', calculateLendingReturns);
 | 
			
		||||
        lendingAssetSelect.addEventListener('change', calculateLendingReturns);
 | 
			
		||||
        lendingTermSelect.addEventListener('change', calculateLendingReturns);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Borrowing form calculations
 | 
			
		||||
    const borrowingAmountInput = document.getElementById('borrowingAmount');
 | 
			
		||||
    const borrowingAssetSelect = document.getElementById('borrowingAsset');
 | 
			
		||||
    const borrowingTermSelect = document.getElementById('borrowingTerm');
 | 
			
		||||
    const borrowingCollateralSelect = document.getElementById('collateralAsset');
 | 
			
		||||
    const borrowingCollateralAmountInput = document.getElementById('collateralAmount');
 | 
			
		||||
    const interestDueElement = document.getElementById('interestDue');
 | 
			
		||||
    const totalRepaymentElement = document.getElementById('totalRepayment');
 | 
			
		||||
    const borrowingCollateralRatioElement = document.getElementById('collateralRatio');
 | 
			
		||||
 | 
			
		||||
    if (borrowingAmountInput && borrowingAssetSelect && borrowingCollateralSelect && borrowingCollateralAmountInput) {
 | 
			
		||||
        const calculateBorrowingDetails = () => {
 | 
			
		||||
            const amount = parseFloat(borrowingAmountInput.value) || 0;
 | 
			
		||||
            const asset = borrowingAssetSelect.value;
 | 
			
		||||
            const termDays = parseInt(borrowingTermSelect.value) || 30;
 | 
			
		||||
            
 | 
			
		||||
            // Get APR from the selected option's text
 | 
			
		||||
            const selectedOption = borrowingTermSelect.options[borrowingTermSelect.selectedIndex];
 | 
			
		||||
            const aprMatch = selectedOption.text.match(/\((\d+\.\d+)%\)/);
 | 
			
		||||
            const apr = aprMatch ? parseFloat(aprMatch[1]) / 100 : 0.08; // Default to 8% if not found
 | 
			
		||||
            
 | 
			
		||||
            // Calculate interest and total repayment
 | 
			
		||||
            const interest = amount * apr * (termDays / 365);
 | 
			
		||||
            const total = amount + interest;
 | 
			
		||||
            
 | 
			
		||||
            if (interestDueElement) {
 | 
			
		||||
                interestDueElement.textContent = interest.toFixed(2) + ' ' + asset;
 | 
			
		||||
            }
 | 
			
		||||
            if (totalRepaymentElement) {
 | 
			
		||||
                totalRepaymentElement.textContent = total.toFixed(2) + ' ' + asset;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Calculate collateral ratio
 | 
			
		||||
            const collateralAmount = parseFloat(borrowingCollateralAmountInput.value) || 0;
 | 
			
		||||
            const collateralAsset = borrowingCollateralSelect.value;
 | 
			
		||||
            let collateralValue = 0;
 | 
			
		||||
            
 | 
			
		||||
            // Mock prices for demonstration
 | 
			
		||||
            const assetPrices = {
 | 
			
		||||
                'TFT': 0.5,
 | 
			
		||||
                'ZAZ': 0.5,
 | 
			
		||||
                'USDT': 1.0
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            if (collateralAsset in assetPrices) {
 | 
			
		||||
                collateralValue = collateralAmount * assetPrices[collateralAsset];
 | 
			
		||||
            } else {
 | 
			
		||||
                // For other assets, assume the value is the amount (simplified)
 | 
			
		||||
                collateralValue = collateralAmount;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            const borrowValue = amount * (asset === 'USDT' ? 1 : assetPrices[asset] || 0.5);
 | 
			
		||||
            const ratio = borrowValue > 0 ? (collateralValue / borrowValue * 100) : 0;
 | 
			
		||||
            
 | 
			
		||||
            if (borrowingCollateralRatioElement) {
 | 
			
		||||
                borrowingCollateralRatioElement.textContent = ratio.toFixed(0) + '%';
 | 
			
		||||
                
 | 
			
		||||
                // Update color based on ratio
 | 
			
		||||
                if (ratio >= 200) {
 | 
			
		||||
                    borrowingCollateralRatioElement.className = 'text-success';
 | 
			
		||||
                } else if (ratio >= 150) {
 | 
			
		||||
                    borrowingCollateralRatioElement.className = 'text-warning';
 | 
			
		||||
                } else {
 | 
			
		||||
                    borrowingCollateralRatioElement.className = 'text-danger';
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        borrowingAmountInput.addEventListener('input', calculateBorrowingDetails);
 | 
			
		||||
        borrowingAssetSelect.addEventListener('change', calculateBorrowingDetails);
 | 
			
		||||
        borrowingTermSelect.addEventListener('change', calculateBorrowingDetails);
 | 
			
		||||
        borrowingCollateralSelect.addEventListener('change', calculateBorrowingDetails);
 | 
			
		||||
        borrowingCollateralAmountInput.addEventListener('input', calculateBorrowingDetails);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =============== LIQUIDITY POOLS TAB ===============
 | 
			
		||||
    // Add Liquidity form calculations
 | 
			
		||||
    const poolSelect = document.getElementById('liquidityPool');
 | 
			
		||||
    const token1AmountInput = document.getElementById('token1Amount');
 | 
			
		||||
    const token2AmountInput = document.getElementById('token2Amount');
 | 
			
		||||
    const lpTokensElement = document.getElementById('lpTokensReceived');
 | 
			
		||||
    const poolShareElement = document.getElementById('poolShare');
 | 
			
		||||
 | 
			
		||||
    if (poolSelect && token1AmountInput && token2AmountInput) {
 | 
			
		||||
        const calculateLiquidityDetails = () => {
 | 
			
		||||
            const token1Amount = parseFloat(token1AmountInput.value) || 0;
 | 
			
		||||
            const token2Amount = parseFloat(token2AmountInput.value) || 0;
 | 
			
		||||
            
 | 
			
		||||
            // Mock calculations for demonstration
 | 
			
		||||
            const lpTokens = Math.sqrt(token1Amount * token2Amount);
 | 
			
		||||
            const poolShare = token1Amount > 0 ? (lpTokens / (lpTokens + 1000) * 100) : 0;
 | 
			
		||||
            
 | 
			
		||||
            if (lpTokensElement) {
 | 
			
		||||
                lpTokensElement.textContent = lpTokens.toFixed(2);
 | 
			
		||||
            }
 | 
			
		||||
            if (poolShareElement) {
 | 
			
		||||
                poolShareElement.textContent = poolShare.toFixed(2) + '%';
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        token1AmountInput.addEventListener('input', calculateLiquidityDetails);
 | 
			
		||||
        token2AmountInput.addEventListener('input', calculateLiquidityDetails);
 | 
			
		||||
        
 | 
			
		||||
        // Handle pool selection to update token labels
 | 
			
		||||
        poolSelect.addEventListener('change', function() {
 | 
			
		||||
            const selectedOption = poolSelect.options[poolSelect.selectedIndex];
 | 
			
		||||
            const token1Label = document.getElementById('token1Label');
 | 
			
		||||
            const token2Label = document.getElementById('token2Label');
 | 
			
		||||
            
 | 
			
		||||
            if (selectedOption.value === 'tft-zaz') {
 | 
			
		||||
                if (token1Label) token1Label.textContent = 'TFT';
 | 
			
		||||
                if (token2Label) token2Label.textContent = 'ZAZ';
 | 
			
		||||
            } else if (selectedOption.value === 'zaz-usdt') {
 | 
			
		||||
                if (token1Label) token1Label.textContent = 'ZAZ';
 | 
			
		||||
                if (token2Label) token2Label.textContent = 'USDT';
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            calculateLiquidityDetails();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =============== STAKING TAB ===============
 | 
			
		||||
    // TFT Staking calculations
 | 
			
		||||
    const tftStakeAmountInput = document.getElementById('tftStakeAmount');
 | 
			
		||||
    const tftStakingPeriodSelect = document.getElementById('tftStakingPeriod');
 | 
			
		||||
    const tftEstimatedRewardsElement = document.getElementById('tftEstimatedRewards');
 | 
			
		||||
 | 
			
		||||
    if (tftStakeAmountInput && tftStakingPeriodSelect && tftEstimatedRewardsElement) {
 | 
			
		||||
        const calculateTftStakingRewards = () => {
 | 
			
		||||
            const amount = parseFloat(tftStakeAmountInput.value) || 0;
 | 
			
		||||
            const termDays = parseInt(tftStakingPeriodSelect.value) || 30;
 | 
			
		||||
            
 | 
			
		||||
            // Get APY from the selected option's text
 | 
			
		||||
            const selectedOption = tftStakingPeriodSelect.options[tftStakingPeriodSelect.selectedIndex];
 | 
			
		||||
            const apyMatch = selectedOption.text.match(/\((\d+\.\d+)%\)/);
 | 
			
		||||
            const apy = apyMatch ? parseFloat(apyMatch[1]) / 100 : 0.085; // Default to 8.5% if not found
 | 
			
		||||
            
 | 
			
		||||
            // Calculate rewards (simple interest for demonstration)
 | 
			
		||||
            const rewards = amount * apy * (termDays / 365);
 | 
			
		||||
            
 | 
			
		||||
            tftEstimatedRewardsElement.textContent = rewards.toFixed(2) + ' TFT';
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        tftStakeAmountInput.addEventListener('input', calculateTftStakingRewards);
 | 
			
		||||
        tftStakingPeriodSelect.addEventListener('change', calculateTftStakingRewards);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ZAZ Staking calculations
 | 
			
		||||
    const zazStakeAmountInput = document.getElementById('zazStakeAmount');
 | 
			
		||||
    const zazStakingPeriodSelect = document.getElementById('zazStakingPeriod');
 | 
			
		||||
    const zazEstimatedRewardsElement = document.getElementById('zazEstimatedRewards');
 | 
			
		||||
 | 
			
		||||
    if (zazStakeAmountInput && zazStakingPeriodSelect && zazEstimatedRewardsElement) {
 | 
			
		||||
        const calculateZazStakingRewards = () => {
 | 
			
		||||
            const amount = parseFloat(zazStakeAmountInput.value) || 0;
 | 
			
		||||
            const termDays = parseInt(zazStakingPeriodSelect.value) || 30;
 | 
			
		||||
            
 | 
			
		||||
            // Get APY from the selected option's text
 | 
			
		||||
            const selectedOption = zazStakingPeriodSelect.options[zazStakingPeriodSelect.selectedIndex];
 | 
			
		||||
            const apyMatch = selectedOption.text.match(/\((\d+\.\d+)%\)/);
 | 
			
		||||
            const apy = apyMatch ? parseFloat(apyMatch[1]) / 100 : 0.12; // Default to 12% if not found
 | 
			
		||||
            
 | 
			
		||||
            // Calculate rewards (simple interest for demonstration)
 | 
			
		||||
            const rewards = amount * apy * (termDays / 365);
 | 
			
		||||
            
 | 
			
		||||
            zazEstimatedRewardsElement.textContent = rewards.toFixed(2) + ' ZAZ';
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        zazStakeAmountInput.addEventListener('input', calculateZazStakingRewards);
 | 
			
		||||
        zazStakingPeriodSelect.addEventListener('change', calculateZazStakingRewards);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Asset Staking calculations
 | 
			
		||||
    const assetStakingSelect = document.getElementById('assetStaking');
 | 
			
		||||
    const assetStakingPeriodSelect = document.getElementById('assetStakingPeriod');
 | 
			
		||||
    const assetEstimatedRewardsElement = document.getElementById('assetEstimatedRewards');
 | 
			
		||||
 | 
			
		||||
    if (assetStakingSelect && assetStakingPeriodSelect && assetEstimatedRewardsElement) {
 | 
			
		||||
        const calculateAssetStakingRewards = () => {
 | 
			
		||||
            const selectedOption = assetStakingSelect.options[assetStakingSelect.selectedIndex];
 | 
			
		||||
            if (selectedOption.value === '') return;
 | 
			
		||||
            
 | 
			
		||||
            const assetValue = parseFloat(selectedOption.dataset.value) || 0;
 | 
			
		||||
            const termDays = parseInt(assetStakingPeriodSelect.value) || 30;
 | 
			
		||||
            
 | 
			
		||||
            // Get APY from the selected option's text
 | 
			
		||||
            const periodOption = assetStakingPeriodSelect.options[assetStakingPeriodSelect.selectedIndex];
 | 
			
		||||
            const apyMatch = periodOption.text.match(/\((\d+\.\d+)%\)/);
 | 
			
		||||
            const apy = apyMatch ? parseFloat(apyMatch[1]) / 100 : 0.035; // Default to 3.5% if not found
 | 
			
		||||
            
 | 
			
		||||
            // Calculate rewards in USD (simple interest for demonstration)
 | 
			
		||||
            const rewards = assetValue * apy * (termDays / 365);
 | 
			
		||||
            
 | 
			
		||||
            assetEstimatedRewardsElement.textContent = '$' + rewards.toFixed(2);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assetStakingSelect.addEventListener('change', calculateAssetStakingRewards);
 | 
			
		||||
        assetStakingPeriodSelect.addEventListener('change', calculateAssetStakingRewards);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =============== SWAP TAB ===============
 | 
			
		||||
    // Token swap calculations
 | 
			
		||||
    const swapFromAmountInput = document.getElementById('swapFromAmount');
 | 
			
		||||
    const swapToAmountElement = document.getElementById('swapToAmount');
 | 
			
		||||
    const fromTokenDropdown = document.getElementById('fromTokenDropdown');
 | 
			
		||||
    const toTokenDropdown = document.getElementById('toTokenDropdown');
 | 
			
		||||
    const exchangeRateElement = document.getElementById('exchangeRate');
 | 
			
		||||
    const minimumReceivedElement = document.getElementById('minimumReceived');
 | 
			
		||||
    const priceImpactElement = document.getElementById('priceImpact');
 | 
			
		||||
    const swapDirectionButton = document.getElementById('swapDirectionButton');
 | 
			
		||||
    const maxFromButton = document.getElementById('maxFromButton');
 | 
			
		||||
    const fromTokenSymbolElement = document.getElementById('fromTokenSymbol');
 | 
			
		||||
    const toTokenSymbolElement = document.getElementById('toTokenSymbol');
 | 
			
		||||
    const fromTokenImgElement = document.getElementById('fromTokenImg');
 | 
			
		||||
    const toTokenImgElement = document.getElementById('toTokenImg');
 | 
			
		||||
    const fromTokenBalanceElement = document.getElementById('fromTokenBalance');
 | 
			
		||||
    const toTokenBalanceElement = document.getElementById('toTokenBalance');
 | 
			
		||||
 | 
			
		||||
    // Mock token data
 | 
			
		||||
    const tokenData = {
 | 
			
		||||
        'TFT': { price: 0.5, balance: '10,000 TFT', usdValue: '5,000.00' },
 | 
			
		||||
        'ZAZ': { price: 0.5, balance: '5,000 ZAZ', usdValue: '2,500.00' },
 | 
			
		||||
        'USDT': { price: 1.0, balance: '2,500 USDT', usdValue: '2,500.00' }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (swapFromAmountInput && swapToAmountElement) {
 | 
			
		||||
        let fromToken = 'TFT';
 | 
			
		||||
        let toToken = 'ZAZ';
 | 
			
		||||
 | 
			
		||||
        const calculateSwap = () => {
 | 
			
		||||
            const fromAmount = parseFloat(swapFromAmountInput.value) || 0;
 | 
			
		||||
            
 | 
			
		||||
            // Calculate exchange rate
 | 
			
		||||
            const fromPrice = tokenData[fromToken].price;
 | 
			
		||||
            const toPrice = tokenData[toToken].price;
 | 
			
		||||
            const rate = fromPrice / toPrice;
 | 
			
		||||
            
 | 
			
		||||
            // Calculate to amount
 | 
			
		||||
            const toAmount = fromAmount * rate;
 | 
			
		||||
            
 | 
			
		||||
            // Update UI
 | 
			
		||||
            swapToAmountElement.value = toAmount.toFixed(2);
 | 
			
		||||
            
 | 
			
		||||
            if (exchangeRateElement) {
 | 
			
		||||
                exchangeRateElement.textContent = `1 ${fromToken} = ${rate.toFixed(4)} ${toToken}`;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (minimumReceivedElement) {
 | 
			
		||||
                // 0.5% slippage for demonstration
 | 
			
		||||
                const minReceived = toAmount * 0.995;
 | 
			
		||||
                minimumReceivedElement.textContent = `${minReceived.toFixed(2)} ${toToken}`;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (priceImpactElement) {
 | 
			
		||||
                // Mock price impact calculation
 | 
			
		||||
                const impact = fromAmount > 1000 ? '0.5%' : '< 0.1%';
 | 
			
		||||
                priceImpactElement.textContent = impact;
 | 
			
		||||
                priceImpactElement.className = fromAmount > 1000 ? 'text-warning' : 'text-success';
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Initialize from token dropdown items
 | 
			
		||||
        const fromTokenItems = document.querySelectorAll('[aria-labelledby="fromTokenDropdown"] .dropdown-item');
 | 
			
		||||
        fromTokenItems.forEach(item => {
 | 
			
		||||
            item.addEventListener('click', function(e) {
 | 
			
		||||
                e.preventDefault();
 | 
			
		||||
                fromToken = this.dataset.token;
 | 
			
		||||
                fromTokenSymbolElement.textContent = fromToken;
 | 
			
		||||
                fromTokenImgElement.src = this.dataset.img;
 | 
			
		||||
                fromTokenBalanceElement.textContent = tokenData[fromToken].balance;
 | 
			
		||||
                calculateSwap();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Initialize to token dropdown items
 | 
			
		||||
        const toTokenItems = document.querySelectorAll('[aria-labelledby="toTokenDropdown"] .dropdown-item');
 | 
			
		||||
        toTokenItems.forEach(item => {
 | 
			
		||||
            item.addEventListener('click', function(e) {
 | 
			
		||||
                e.preventDefault();
 | 
			
		||||
                toToken = this.dataset.token;
 | 
			
		||||
                toTokenSymbolElement.textContent = toToken;
 | 
			
		||||
                toTokenImgElement.src = this.dataset.img;
 | 
			
		||||
                toTokenBalanceElement.textContent = tokenData[toToken].balance;
 | 
			
		||||
                calculateSwap();
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Swap direction button
 | 
			
		||||
        if (swapDirectionButton) {
 | 
			
		||||
            swapDirectionButton.addEventListener('click', function() {
 | 
			
		||||
                // Swap tokens
 | 
			
		||||
                const tempToken = fromToken;
 | 
			
		||||
                fromToken = toToken;
 | 
			
		||||
                toToken = tempToken;
 | 
			
		||||
                
 | 
			
		||||
                // Update UI
 | 
			
		||||
                fromTokenSymbolElement.textContent = fromToken;
 | 
			
		||||
                toTokenSymbolElement.textContent = toToken;
 | 
			
		||||
                
 | 
			
		||||
                const tempImg = fromTokenImgElement.src;
 | 
			
		||||
                fromTokenImgElement.src = toTokenImgElement.src;
 | 
			
		||||
                toTokenImgElement.src = tempImg;
 | 
			
		||||
                
 | 
			
		||||
                fromTokenBalanceElement.textContent = tokenData[fromToken].balance;
 | 
			
		||||
                toTokenBalanceElement.textContent = tokenData[toToken].balance;
 | 
			
		||||
                
 | 
			
		||||
                // Swap amounts
 | 
			
		||||
                const tempAmount = swapFromAmountInput.value;
 | 
			
		||||
                swapFromAmountInput.value = swapToAmountElement.value;
 | 
			
		||||
                
 | 
			
		||||
                calculateSwap();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Max button
 | 
			
		||||
        if (maxFromButton) {
 | 
			
		||||
            maxFromButton.addEventListener('click', function() {
 | 
			
		||||
                // Set max amount based on token balance
 | 
			
		||||
                const balance = parseInt(tokenData[fromToken].balance.split(' ')[0].replace(/,/g, ''));
 | 
			
		||||
                swapFromAmountInput.value = balance;
 | 
			
		||||
                calculateSwap();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        swapFromAmountInput.addEventListener('input', calculateSwap);
 | 
			
		||||
        
 | 
			
		||||
        // Initial calculation
 | 
			
		||||
        calculateSwap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // =============== COLLATERAL TAB ===============
 | 
			
		||||
    // Collateral form calculations
 | 
			
		||||
    const collateralAssetSelect = document.getElementById('collateralAsset');
 | 
			
		||||
    const collateralAmountInput = document.getElementById('collateralAmount');
 | 
			
		||||
    const collateralValueElement = document.getElementById('collateralValue');
 | 
			
		||||
    const collateralUnitElement = document.getElementById('collateralUnit');
 | 
			
		||||
    const collateralAvailableElement = document.getElementById('collateralAvailable');
 | 
			
		||||
    const collateralAvailableUSDElement = document.getElementById('collateralAvailableUSD');
 | 
			
		||||
    const collateralPurposeSelect = document.getElementById('collateralPurpose');
 | 
			
		||||
    const loanTermGroup = document.getElementById('loanTermGroup');
 | 
			
		||||
    const loanAmountGroup = document.getElementById('loanAmountGroup');
 | 
			
		||||
    const syntheticAssetGroup = document.getElementById('syntheticAssetGroup');
 | 
			
		||||
    const syntheticAmountGroup = document.getElementById('syntheticAmountGroup');
 | 
			
		||||
    const loanAmountInput = document.getElementById('loanAmount');
 | 
			
		||||
    const maxLoanAmountElement = document.getElementById('maxLoanAmount');
 | 
			
		||||
    const syntheticAmountInput = document.getElementById('syntheticAmount');
 | 
			
		||||
    const maxSyntheticAmountElement = document.getElementById('maxSyntheticAmount');
 | 
			
		||||
    const collateralRatioElement = document.getElementById('collateralRatio');
 | 
			
		||||
    const liquidationPriceElement = document.getElementById('liquidationPrice');
 | 
			
		||||
    const liquidationUnitElement = document.getElementById('liquidationUnit');
 | 
			
		||||
 | 
			
		||||
    if (collateralAssetSelect && collateralAmountInput) {
 | 
			
		||||
        const calculateCollateralDetails = () => {
 | 
			
		||||
            if (collateralAssetSelect.selectedIndex === 0) return;
 | 
			
		||||
            
 | 
			
		||||
            const selectedOption = collateralAssetSelect.options[collateralAssetSelect.selectedIndex];
 | 
			
		||||
            const assetType = selectedOption.dataset.type;
 | 
			
		||||
            const assetValue = parseFloat(selectedOption.dataset.value) || 0;
 | 
			
		||||
            const assetAmount = parseFloat(selectedOption.dataset.amount) || 0;
 | 
			
		||||
            const assetUnit = selectedOption.dataset.unit || '';
 | 
			
		||||
            
 | 
			
		||||
            // Update UI with asset details
 | 
			
		||||
            if (collateralUnitElement) collateralUnitElement.textContent = assetUnit;
 | 
			
		||||
            if (collateralAvailableElement) collateralAvailableElement.textContent = assetAmount.toLocaleString() + ' ' + assetUnit;
 | 
			
		||||
            if (collateralAvailableUSDElement) collateralAvailableUSDElement.textContent = '$' + assetValue.toLocaleString();
 | 
			
		||||
            if (liquidationUnitElement) liquidationUnitElement.textContent = assetUnit;
 | 
			
		||||
            
 | 
			
		||||
            // Calculate collateral value
 | 
			
		||||
            const amount = parseFloat(collateralAmountInput.value) || 0;
 | 
			
		||||
            let collateralValue = 0;
 | 
			
		||||
            
 | 
			
		||||
            if (assetType === 'token') {
 | 
			
		||||
                // For tokens, calculate based on token price
 | 
			
		||||
                const tokenPrice = assetValue / assetAmount;
 | 
			
		||||
                collateralValue = amount * tokenPrice;
 | 
			
		||||
            } else {
 | 
			
		||||
                // For NFTs and other assets, use the full value if amount is 1
 | 
			
		||||
                collateralValue = amount === 1 ? assetValue : 0;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            if (collateralValueElement) collateralValueElement.value = collateralValue.toFixed(2);
 | 
			
		||||
            
 | 
			
		||||
            // Calculate max loan amount (75% of collateral value)
 | 
			
		||||
            const maxLoanAmount = collateralValue * 0.75;
 | 
			
		||||
            if (maxLoanAmountElement) maxLoanAmountElement.textContent = maxLoanAmount.toFixed(2);
 | 
			
		||||
            
 | 
			
		||||
            // Calculate max synthetic amount (50% of collateral value)
 | 
			
		||||
            const maxSyntheticAmount = collateralValue * 0.5;
 | 
			
		||||
            if (maxSyntheticAmountElement) maxSyntheticAmountElement.textContent = maxSyntheticAmount.toFixed(2);
 | 
			
		||||
            
 | 
			
		||||
            // Calculate collateral ratio and liquidation price
 | 
			
		||||
            updateCollateralRatio();
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        const updateCollateralRatio = () => {
 | 
			
		||||
            const collateralValue = parseFloat(collateralValueElement.value) || 0;
 | 
			
		||||
            const purpose = collateralPurposeSelect.value;
 | 
			
		||||
            
 | 
			
		||||
            let borrowedValue = 0;
 | 
			
		||||
            if (purpose === 'loan') {
 | 
			
		||||
                borrowedValue = parseFloat(loanAmountInput.value) || 0;
 | 
			
		||||
            } else if (purpose === 'synthetic') {
 | 
			
		||||
                borrowedValue = parseFloat(syntheticAmountInput.value) || 0;
 | 
			
		||||
            } else {
 | 
			
		||||
                // For leverage trading, assume 2x leverage
 | 
			
		||||
                borrowedValue = collateralValue;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Calculate ratio
 | 
			
		||||
            const ratio = borrowedValue > 0 ? (collateralValue / borrowedValue * 100) : 0;
 | 
			
		||||
            
 | 
			
		||||
            if (collateralRatioElement) {
 | 
			
		||||
                collateralRatioElement.value = ratio.toFixed(0) + '%';
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Calculate liquidation price
 | 
			
		||||
            if (liquidationPriceElement) {
 | 
			
		||||
                const selectedOption = collateralAssetSelect.options[collateralAssetSelect.selectedIndex];
 | 
			
		||||
                if (selectedOption.selectedIndex === 0) return;
 | 
			
		||||
                
 | 
			
		||||
                const assetType = selectedOption.dataset.type;
 | 
			
		||||
                const assetValue = parseFloat(selectedOption.dataset.value) || 0;
 | 
			
		||||
                const assetAmount = parseFloat(selectedOption.dataset.amount) || 0;
 | 
			
		||||
                const collateralAmount = parseFloat(collateralAmountInput.value) || 0;
 | 
			
		||||
                
 | 
			
		||||
                if (assetType === 'token' && collateralAmount > 0) {
 | 
			
		||||
                    const currentPrice = assetValue / assetAmount;
 | 
			
		||||
                    const liquidationThreshold = purpose === 'loan' ? 1.2 : 1.5; // 120% for loans, 150% for synthetic
 | 
			
		||||
                    const liquidationPrice = (borrowedValue / collateralAmount) * liquidationThreshold;
 | 
			
		||||
                    liquidationPriceElement.value = liquidationPrice.toFixed(4);
 | 
			
		||||
                } else {
 | 
			
		||||
                    liquidationPriceElement.value = (borrowedValue * 1.2).toFixed(2);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Handle collateral asset selection
 | 
			
		||||
        collateralAssetSelect.addEventListener('change', function() {
 | 
			
		||||
            collateralAmountInput.value = '';
 | 
			
		||||
            calculateCollateralDetails();
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        // Handle collateral amount input
 | 
			
		||||
        collateralAmountInput.addEventListener('input', calculateCollateralDetails);
 | 
			
		||||
        
 | 
			
		||||
        // Handle purpose selection
 | 
			
		||||
        collateralPurposeSelect.addEventListener('change', function() {
 | 
			
		||||
            const purpose = collateralPurposeSelect.value;
 | 
			
		||||
            
 | 
			
		||||
            // Show/hide relevant form groups
 | 
			
		||||
            if (loanTermGroup) loanTermGroup.style.display = purpose === 'loan' ? 'block' : 'none';
 | 
			
		||||
            if (loanAmountGroup) loanAmountGroup.style.display = purpose === 'loan' ? 'block' : 'none';
 | 
			
		||||
            if (syntheticAssetGroup) syntheticAssetGroup.style.display = purpose === 'synthetic' ? 'block' : 'none';
 | 
			
		||||
            if (syntheticAmountGroup) syntheticAmountGroup.style.display = purpose === 'synthetic' ? 'block' : 'none';
 | 
			
		||||
            
 | 
			
		||||
            updateCollateralRatio();
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
        // Handle loan amount input
 | 
			
		||||
        if (loanAmountInput) {
 | 
			
		||||
            loanAmountInput.addEventListener('input', updateCollateralRatio);
 | 
			
		||||
            
 | 
			
		||||
            // Max loan button
 | 
			
		||||
            const maxLoanButton = document.getElementById('maxLoanButton');
 | 
			
		||||
            if (maxLoanButton) {
 | 
			
		||||
                maxLoanButton.addEventListener('click', function() {
 | 
			
		||||
                    const maxLoan = parseFloat(maxLoanAmountElement.textContent) || 0;
 | 
			
		||||
                    loanAmountInput.value = maxLoan.toFixed(2);
 | 
			
		||||
                    updateCollateralRatio();
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Handle synthetic amount input
 | 
			
		||||
        if (syntheticAmountInput) {
 | 
			
		||||
            syntheticAmountInput.addEventListener('input', updateCollateralRatio);
 | 
			
		||||
            
 | 
			
		||||
            // Max synthetic button
 | 
			
		||||
            const maxSyntheticButton = document.getElementById('maxSyntheticButton');
 | 
			
		||||
            if (maxSyntheticButton) {
 | 
			
		||||
                maxSyntheticButton.addEventListener('click', function() {
 | 
			
		||||
                    const maxSynthetic = parseFloat(maxSyntheticAmountElement.textContent) || 0;
 | 
			
		||||
                    syntheticAmountInput.value = maxSynthetic.toFixed(2);
 | 
			
		||||
                    updateCollateralRatio();
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // Handle synthetic asset selection
 | 
			
		||||
        const syntheticAssetSelect = document.getElementById('syntheticAsset');
 | 
			
		||||
        const syntheticUnitElement = document.getElementById('syntheticUnit');
 | 
			
		||||
        const maxSyntheticUnitElement = document.getElementById('maxSyntheticUnit');
 | 
			
		||||
        
 | 
			
		||||
        if (syntheticAssetSelect && syntheticUnitElement && maxSyntheticUnitElement) {
 | 
			
		||||
            syntheticAssetSelect.addEventListener('change', function() {
 | 
			
		||||
                const asset = syntheticAssetSelect.value;
 | 
			
		||||
                syntheticUnitElement.textContent = asset;
 | 
			
		||||
                maxSyntheticUnitElement.textContent = asset;
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Initialize tab functionality if not already handled by Bootstrap
 | 
			
		||||
    const tabLinks = document.querySelectorAll('.nav-link[data-bs-toggle="tab"]');
 | 
			
		||||
    tabLinks.forEach(tabLink => {
 | 
			
		||||
        tabLink.addEventListener('click', function(e) {
 | 
			
		||||
            e.preventDefault();
 | 
			
		||||
            const targetId = this.getAttribute('href');
 | 
			
		||||
            const targetTab = document.querySelector(targetId);
 | 
			
		||||
            
 | 
			
		||||
            // Hide all tabs
 | 
			
		||||
            document.querySelectorAll('.tab-pane').forEach(tab => {
 | 
			
		||||
                tab.classList.remove('show', 'active');
 | 
			
		||||
            });
 | 
			
		||||
            
 | 
			
		||||
            // Show the target tab
 | 
			
		||||
            if (targetTab) {
 | 
			
		||||
                targetTab.classList.add('show', 'active');
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Update active state on nav links
 | 
			
		||||
            tabLinks.forEach(link => link.classList.remove('active'));
 | 
			
		||||
            this.classList.add('active');
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user