diff --git a/frontend/src/app/maker-dashboard/page.tsx b/frontend/src/app/maker-dashboard/page.tsx index 7573f8c..f74ecb5 100644 --- a/frontend/src/app/maker-dashboard/page.tsx +++ b/frontend/src/app/maker-dashboard/page.tsx @@ -5,31 +5,17 @@ import { useAccount } from 'wagmi' import { useSearchParams } from 'next/navigation' import { useMakerDetails } from '@/lib/useContracts' import CreateOrder from '@/components/CreateOrder' -import OrdersList from '@/components/OrdersList' export default function MakerDashboard() { const { address, isConnected } = useAccount() const searchParams = useSearchParams() const { isRegistered, isForeigner, identityProof, isLoading, error } = useMakerDetails(address || '') - const [activeTab, setActiveTab] = useState<'orders' | 'create'>('orders') - const [refreshKey, setRefreshKey] = useState(0) - - // Set active tab from URL parameter (e.g., when coming from QR scanner) - useEffect(() => { - const tabParam = searchParams?.get('tab') - if (tabParam === 'create' || tabParam === 'orders') { - setActiveTab(tabParam) - } - }, [searchParams]) // Check if coming from QR scanner const isFromQRScan = searchParams?.get('upiAddress') && searchParams?.get('tab') === 'create' const handleOrderCreated = (orderId?: string) => { - // Refresh the orders list when a new order is created - setRefreshKey(prev => prev + 1) - - // Don't switch tabs - stay on create tab to show processing/completion status + // Order created successfully - could add notification here if needed } // Only check wallet connection for normal dashboard access (not from QR scan) @@ -175,45 +161,9 @@ export default function MakerDashboard() { )} - {/* Tab Navigation */} -
-
- -
-
- - {/* Tab Content */} + {/* Content */}
- {activeTab === 'orders' && ( -
- -
- )} - - {activeTab === 'create' && ( - - )} +
diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx index b7da39a..b677a0b 100644 --- a/frontend/src/app/settings/page.tsx +++ b/frontend/src/app/settings/page.tsx @@ -13,8 +13,8 @@ export default function SettingsPage() { const router = useRouter() const [formData, setFormData] = useState({ - defaultStartPrice: '90.00', - defaultEndPrice: '80.00' + defaultStartPricePercentage: '5', + defaultEndPricePercentage: '2' }) const [saved, setSaved] = useState(false) @@ -28,8 +28,8 @@ export default function SettingsPage() { // Update form data when settings change useEffect(() => { setFormData({ - defaultStartPrice: settings.defaultStartPrice, - defaultEndPrice: settings.defaultEndPrice + defaultStartPricePercentage: settings.defaultStartPricePercentage, + defaultEndPricePercentage: settings.defaultEndPricePercentage }) }, [settings]) @@ -68,57 +68,69 @@ export default function SettingsPage() {

Maker Settings

- Configure your default order parameters + Configure your default premium percentages for order pricing

- {/* Start Price (INR per USDC) */} + {/* Start Price Percentage */}
-
- {/* End Price (INR per USDC) */} + {/* End Price Percentage */}
-
{/* Price Validation */} - {formData.defaultStartPrice && formData.defaultEndPrice && - parseFloat(formData.defaultStartPrice) <= parseFloat(formData.defaultEndPrice) && ( + {formData.defaultStartPricePercentage && formData.defaultEndPricePercentage && + parseFloat(formData.defaultStartPricePercentage) <= parseFloat(formData.defaultEndPricePercentage) && (
@@ -128,7 +140,7 @@ export default function SettingsPage() {

- Warning: End price should typically be lower than start price for Dutch auctions. + Warning: Start premium should be higher than end premium for Dutch auctions.

@@ -184,13 +196,14 @@ export default function SettingsPage() {
-

About Default Prices

+

About Premium Percentages

    -
  • These default values will be automatically filled when you create new orders
  • -
  • You can always modify the prices when creating individual orders
  • +
  • These percentages will be added to the current market rate when creating orders
  • +
  • Example: If market rate is ₹85 and start premium is 5%, start price = ₹89.25
  • +
  • You can always modify the calculated prices when creating individual orders
  • Settings are stored locally in your browser and tied to your wallet address
  • -
  • For Dutch auctions, the start price should typically be higher than the end price
  • +
  • For Dutch auctions, start premium should be higher than end premium
diff --git a/frontend/src/components/CreateOrder.tsx b/frontend/src/components/CreateOrder.tsx index 24c6b6b..9e736e7 100644 --- a/frontend/src/components/CreateOrder.tsx +++ b/frontend/src/components/CreateOrder.tsx @@ -5,6 +5,7 @@ import { useAccount, useWaitForTransactionReceipt, useWatchContractEvent } from import { useSearchParams } from 'next/navigation' import { useCreateOrder, useERC20, useResolverFee, calculateApprovalAmount, COMMON_TOKENS, formatTokenAmount } from '@/lib/useContracts' import { useMakerSettings } from '@/lib/useMakerSettings' +import { useCoinPrice } from '@/lib/useCoinPrice' import { CONTRACTS } from '@/lib/contracts' @@ -17,6 +18,7 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) { const searchParams = useSearchParams() const { createOrder, saveOrderToDatabase, isLoading: isCreatingOrder, error: createOrderError, hash } = useCreateOrder() const { settings: makerSettings } = useMakerSettings() + const { price: coinPrice, loading: priceLoading, error: priceError, lastUpdated, refresh: refreshPrice } = useCoinPrice() // Get resolver fee from contract const { resolverFee } = useResolverFee() @@ -26,11 +28,29 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) { hash, }) + // Calculate start and end prices based on coin price and settings percentages + const calculatedPrices = useMemo(() => { + if (!coinPrice || !makerSettings.defaultStartPricePercentage || !makerSettings.defaultEndPricePercentage) { + return { startPrice: '', endPrice: '' } + } + + const startpercentage = parseFloat(makerSettings.defaultStartPricePercentage) / 100 + const endpercentage = parseFloat(makerSettings.defaultEndPricePercentage) / 100 + + const startPremium = parseFloat(makerSettings.defaultStartPricePercentage) / 100 + const endDiscount = parseFloat(makerSettings.defaultEndPricePercentage) / 100 + + const startPrice = (coinPrice * (1 + startPremium)).toFixed(2) + const endPrice = (coinPrice * (1 - endDiscount)).toFixed(2) + + return { startPrice, endPrice } + }, [coinPrice, makerSettings.defaultStartPricePercentage, makerSettings.defaultEndPricePercentage]) + // Form state - Initialize with URL parameters from scanned QR code const [formData, setFormData] = useState({ amount: searchParams.get('amount') || '', - startPrice: makerSettings.defaultStartPrice || '', - endPrice: makerSettings.defaultEndPrice || '', + startPrice: '', + endPrice: '', recipientUpiAddress: searchParams.get('upiAddress') || '' }) @@ -176,14 +196,16 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) { } }, [searchParams]) - // Update form data with default settings when they change + // Update form data with calculated prices when they change useEffect(() => { - setFormData(prev => ({ - ...prev, - startPrice: prev.startPrice || makerSettings.defaultStartPrice || '', - endPrice: prev.endPrice || makerSettings.defaultEndPrice || '' - })) - }, [makerSettings.defaultStartPrice, makerSettings.defaultEndPrice]) + if (calculatedPrices.startPrice && calculatedPrices.endPrice) { + setFormData(prev => ({ + ...prev, + startPrice: calculatedPrices.startPrice, + endPrice: calculatedPrices.endPrice + })) + } + }, [calculatedPrices.startPrice, calculatedPrices.endPrice]) // Handle receipt when transaction is confirmed useEffect(() => { @@ -465,17 +487,44 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
- {/* Token Info - Fixed to PYUSD only */} -
-
-
- P + {/* Current USD Coin Price Display */} +
+
+
+
+ +
+ Current USD Coin Rate
- {selectedToken.name} ({selectedToken.symbol}) + +
+
+
+ {priceLoading ? ( +
+
+
+ ) : priceError ? ( + Failed to load price + ) : ( + + ₹{coinPrice?.toFixed(2)} + + )} + per USD Coin +
+ {lastUpdated && ( + + Updated: {lastUpdated.toLocaleTimeString()} + + )}
-

- This platform exclusively supports MockUSDC for payments. All orders will be settled using MockUSDC tokens. -

{/* Amount */} @@ -513,24 +562,23 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) { - {makerSettings.defaultStartPrice && formData.startPrice === makerSettings.defaultStartPrice && ( + {makerSettings.defaultStartPricePercentage && ( - Using default + Using {makerSettings.defaultStartPricePercentage}% premium )}
- +
+ {calculatedPrices.startPrice || 'Calculating...'} +

Starting price in INR per token (Dutch auction starts high)

+ {coinPrice && makerSettings.defaultStartPricePercentage && ( +

+ Calculated: ₹{coinPrice.toFixed(2)} + {makerSettings.defaultStartPricePercentage}% premium +

+ )}
{/* End Price */} @@ -539,27 +587,23 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) { - {makerSettings.defaultEndPrice && formData.endPrice === makerSettings.defaultEndPrice && ( + {makerSettings.defaultEndPricePercentage && ( - Using default + Using {makerSettings.defaultEndPricePercentage}% discount )}
- +
+ {calculatedPrices.endPrice || 'Calculating...'} +

Ending price in INR per token (Dutch auction ends low)

-

- Note: Start price must be higher than end price for the Dutch auction mechanism -

+ {coinPrice && makerSettings.defaultEndPricePercentage && ( +

+ Calculated: ₹{coinPrice.toFixed(2)} - {makerSettings.defaultEndPricePercentage}% discount +

+ )} {/* Approval Calculation Info */} diff --git a/frontend/src/lib/useCoinPrice.ts b/frontend/src/lib/useCoinPrice.ts new file mode 100644 index 0000000..7be5b1c --- /dev/null +++ b/frontend/src/lib/useCoinPrice.ts @@ -0,0 +1,66 @@ +import { useState, useEffect } from 'react' + +interface CoinGeckoResponse { + 'usd-coin': { + inr: number + } +} + +export function useCoinPrice() { + const [price, setPrice] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + const [lastUpdated, setLastUpdated] = useState(null) + + const fetchPrice = async () => { + try { + setLoading(true) + setError(null) + + const response = await fetch( + 'https://api.coingecko.com/api/v3/simple/price?ids=usd-coin&vs_currencies=inr' + ) + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + + const data: CoinGeckoResponse = await response.json() + + if (data['usd-coin'] && data['usd-coin'].inr) { + setPrice(data['usd-coin'].inr) + setLastUpdated(new Date()) + } else { + throw new Error('Invalid API response format') + } + } catch (err) { + console.error('Error fetching USD Coin price:', err) + setError(err instanceof Error ? err.message : 'Failed to fetch price') + // Fallback to a default price if API fails + setPrice(85) // Default fallback price + } finally { + setLoading(false) + } + } + + useEffect(() => { + fetchPrice() + + // Refresh price every 30 seconds + const interval = setInterval(fetchPrice, 30000) + + return () => clearInterval(interval) + }, []) + + const refresh = () => { + fetchPrice() + } + + return { + price, + loading, + error, + lastUpdated, + refresh + } +} \ No newline at end of file diff --git a/frontend/src/lib/useMakerSettings.ts b/frontend/src/lib/useMakerSettings.ts index 23e4e31..bf732c4 100644 --- a/frontend/src/lib/useMakerSettings.ts +++ b/frontend/src/lib/useMakerSettings.ts @@ -2,13 +2,13 @@ import { useState, useEffect } from 'react' import { useAccount } from 'wagmi' export interface MakerSettings { - defaultStartPrice: string - defaultEndPrice: string + defaultStartPricePercentage: string + defaultEndPricePercentage: string } const DEFAULT_SETTINGS: MakerSettings = { - defaultStartPrice: '90.00', - defaultEndPrice: '80.00' + defaultStartPricePercentage: '5', + defaultEndPricePercentage: '2' } export function useMakerSettings() { @@ -66,8 +66,8 @@ export function useMakerSettings() { const getDefaultValues = () => { return { - defaultStartPrice: settings.defaultStartPrice || '', - defaultEndPrice: settings.defaultEndPrice || '' + defaultStartPricePercentage: settings.defaultStartPricePercentage || '', + defaultEndPricePercentage: settings.defaultEndPricePercentage || '' } }