Skip to content

Commit cc9f5ea

Browse files
committed
2 parents 7ace8cb + 9af05cf commit cc9f5ea

6 files changed

Lines changed: 345 additions & 42 deletions

File tree

backend/routes/orders.js

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const axios = require("axios");
55
const {
66
createWalletClient,
77
http,
8-
parseEther,
98
parseGwei,
109
createPublicClient,
1110
} = require("viem");
@@ -90,26 +89,6 @@ async function signalResolverOrderAccepted(orderId, resolverAddress, details) {
9089
}
9190
}
9291

93-
// Define Worldchain Sepolia chain
94-
const worldchainSepolia = {
95-
id: 4801,
96-
name: "Worldchain Sepolia",
97-
network: "worldchain-sepolia",
98-
nativeCurrency: {
99-
decimals: 18,
100-
name: "Ether",
101-
symbol: "ETH",
102-
},
103-
rpcUrls: {
104-
default: {
105-
http: ["https://testnet.evm.nodes.onflow.org"],
106-
},
107-
public: {
108-
http: ["https://testnet.evm.nodes.onflow.org"],
109-
},
110-
},
111-
};
112-
11392
// Validation middleware
11493
const validateWalletAddress = (req, res, next) => {
11594
const walletAddress =

frontend/public/sw.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/app/settings/page.tsx

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
'use client'
2+
3+
import { useState, useEffect } from 'react'
4+
import { useAccount } from 'wagmi'
5+
import { useMakerDetails } from '@/lib/useContracts'
6+
import { useMakerSettings } from '@/lib/useMakerSettings'
7+
import { useRouter } from 'next/navigation'
8+
9+
export default function SettingsPage() {
10+
const { address, isConnected } = useAccount()
11+
const { isRegistered } = useMakerDetails(address || '')
12+
const { settings, loading, updateSettings, resetSettings } = useMakerSettings()
13+
const router = useRouter()
14+
15+
const [formData, setFormData] = useState({
16+
defaultStartPrice: '90.00',
17+
defaultEndPrice: '80.00'
18+
})
19+
const [saved, setSaved] = useState(false)
20+
21+
// Redirect if not connected or not registered
22+
useEffect(() => {
23+
if (!isConnected || (isConnected && !isRegistered)) {
24+
router.push('/')
25+
}
26+
}, [isConnected, isRegistered, router])
27+
28+
// Update form data when settings change
29+
useEffect(() => {
30+
setFormData({
31+
defaultStartPrice: settings.defaultStartPrice,
32+
defaultEndPrice: settings.defaultEndPrice
33+
})
34+
}, [settings])
35+
36+
const handleInputChange = (field: string, value: string) => {
37+
setFormData(prev => ({
38+
...prev,
39+
[field]: value
40+
}))
41+
setSaved(false)
42+
}
43+
44+
const handleSave = async () => {
45+
if (!address || !isRegistered) return
46+
47+
const success = await updateSettings(formData)
48+
if (success) {
49+
setSaved(true)
50+
// Auto-hide the saved message after 3 seconds
51+
setTimeout(() => setSaved(false), 3000)
52+
}
53+
}
54+
55+
const handleReset = async () => {
56+
await resetSettings()
57+
setSaved(false)
58+
}
59+
60+
if (!isConnected || !isRegistered) {
61+
return null // Will redirect via useEffect
62+
}
63+
64+
return (
65+
<div className="min-h-screen bg-gray-50 py-8">
66+
<div className="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8">
67+
<div className="bg-white shadow-lg rounded-lg">
68+
<div className="px-6 py-4 border-b border-gray-200">
69+
<h1 className="text-2xl font-bold text-gray-900">Maker Settings</h1>
70+
<p className="text-sm text-gray-600 mt-1">
71+
Configure your default order parameters
72+
</p>
73+
</div>
74+
75+
<div className="px-6 py-6 space-y-6">
76+
{/* Start Price (INR per PYUSD) */}
77+
<div>
78+
<label htmlFor="defaultStartPrice" className="block text-sm font-medium text-gray-700 mb-2">
79+
Start Price (INR per PYUSD)
80+
</label>
81+
<input
82+
type="number"
83+
id="defaultStartPrice"
84+
step="0.01"
85+
min="0"
86+
placeholder="90.00"
87+
value={formData.defaultStartPrice}
88+
onChange={(e) => handleInputChange('defaultStartPrice', e.target.value)}
89+
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm placeholder-gray-700"
90+
/>
91+
<p className="text-xs text-blue-500 mt-1">
92+
Starting price in INR per token (Dutch auction starts high)
93+
</p>
94+
</div>
95+
96+
{/* End Price (INR per PYUSD) */}
97+
<div>
98+
<label htmlFor="defaultEndPrice" className="block text-sm font-medium text-gray-700 mb-2">
99+
End Price (INR per PYUSD)
100+
</label>
101+
<input
102+
type="number"
103+
id="defaultEndPrice"
104+
step="0.01"
105+
min="0"
106+
placeholder="80.00"
107+
value={formData.defaultEndPrice}
108+
onChange={(e) => handleInputChange('defaultEndPrice', e.target.value)}
109+
className="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm placeholder-gray-700"
110+
/>
111+
<p className="text-xs text-blue-500 mt-1">
112+
Ending price in INR per token (Dutch auction ends low)
113+
</p>
114+
<p className="text-xs text-red-500 mt-1">
115+
<strong>Note:</strong> Start price must be higher than end price for the Dutch auction mechanism
116+
</p>
117+
</div>
118+
119+
{/* Price Validation */}
120+
{formData.defaultStartPrice && formData.defaultEndPrice &&
121+
parseFloat(formData.defaultStartPrice) <= parseFloat(formData.defaultEndPrice) && (
122+
<div className="bg-yellow-50 border border-yellow-200 rounded-md p-3">
123+
<div className="flex">
124+
<div className="flex-shrink-0">
125+
<svg className="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor">
126+
<path fillRule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clipRule="evenodd" />
127+
</svg>
128+
</div>
129+
<div className="ml-3">
130+
<p className="text-sm text-yellow-800">
131+
<strong>Warning:</strong> End price should typically be lower than start price for Dutch auctions.
132+
</p>
133+
</div>
134+
</div>
135+
</div>
136+
)}
137+
138+
{/* Success Message */}
139+
{saved && (
140+
<div className="bg-green-50 border border-green-200 rounded-md p-3">
141+
<div className="flex">
142+
<div className="flex-shrink-0">
143+
<svg className="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor">
144+
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
145+
</svg>
146+
</div>
147+
<div className="ml-3">
148+
<p className="text-sm text-green-800">
149+
Settings saved successfully!
150+
</p>
151+
</div>
152+
</div>
153+
</div>
154+
)}
155+
</div>
156+
157+
{/* Action Buttons */}
158+
<div className="px-6 py-4 bg-gray-50 border-t border-gray-200 flex justify-between">
159+
<button
160+
type="button"
161+
onClick={handleReset}
162+
className="px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
163+
>
164+
Reset to Default
165+
</button>
166+
167+
<button
168+
type="button"
169+
onClick={handleSave}
170+
disabled={loading}
171+
className="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
172+
>
173+
{loading ? 'Saving...' : 'Save Settings'}
174+
</button>
175+
</div>
176+
</div>
177+
178+
{/* Additional Information */}
179+
<div className="mt-6 bg-blue-50 border border-blue-200 rounded-md p-4">
180+
<div className="flex">
181+
<div className="flex-shrink-0">
182+
<svg className="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor">
183+
<path fillRule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clipRule="evenodd" />
184+
</svg>
185+
</div>
186+
<div className="ml-3">
187+
<h3 className="text-sm font-medium text-blue-800">About Default Prices</h3>
188+
<div className="mt-2 text-sm text-blue-700">
189+
<ul className="list-disc pl-5 space-y-1">
190+
<li>These default values will be automatically filled when you create new orders</li>
191+
<li>You can always modify the prices when creating individual orders</li>
192+
<li>Settings are stored locally in your browser and tied to your wallet address</li>
193+
<li>For Dutch auctions, the start price should typically be higher than the end price</li>
194+
</ul>
195+
</div>
196+
</div>
197+
</div>
198+
</div>
199+
</div>
200+
</div>
201+
)
202+
}

frontend/src/components/CreateOrder.tsx

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, { useState, useEffect, useMemo } from 'react'
44
import { useAccount, useWaitForTransactionReceipt, useWatchContractEvent } from 'wagmi'
55
import { useSearchParams } from 'next/navigation'
66
import { useCreateOrder, useERC20, useResolverFee, calculateApprovalAmount, COMMON_TOKENS, formatTokenAmount } from '@/lib/useContracts'
7+
import { useMakerSettings } from '@/lib/useMakerSettings'
78

89
import { CONTRACTS } from '@/lib/contracts'
910

@@ -15,6 +16,7 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
1516
const { address } = useAccount()
1617
const searchParams = useSearchParams()
1718
const { createOrder, saveOrderToDatabase, isLoading: isCreatingOrder, error: createOrderError, hash } = useCreateOrder()
19+
const { settings: makerSettings } = useMakerSettings()
1820

1921
// Get resolver fee from contract
2022
const { resolverFee } = useResolverFee()
@@ -27,8 +29,8 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
2729
// Form state - Initialize with URL parameters from scanned QR code
2830
const [formData, setFormData] = useState({
2931
amount: searchParams.get('amount') || '',
30-
startPrice: '',
31-
endPrice: '',
32+
startPrice: makerSettings.defaultStartPrice || '',
33+
endPrice: makerSettings.defaultEndPrice || '',
3234
recipientUpiAddress: searchParams.get('upiAddress') || ''
3335
})
3436

@@ -173,6 +175,15 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
173175
}
174176
}, [searchParams])
175177

178+
// Update form data with default settings when they change
179+
useEffect(() => {
180+
setFormData(prev => ({
181+
...prev,
182+
startPrice: prev.startPrice || makerSettings.defaultStartPrice || '',
183+
endPrice: prev.endPrice || makerSettings.defaultEndPrice || ''
184+
}))
185+
}, [makerSettings.defaultStartPrice, makerSettings.defaultEndPrice])
186+
176187
// Handle receipt when transaction is confirmed
177188
useEffect(() => {
178189
if (isReceiptSuccess && receipt && step === 'create') {
@@ -473,9 +484,16 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
473484

474485
{/* Start Price */}
475486
<div>
476-
<label className="block text-sm font-medium text-gray-700 mb-1">
477-
Start Price (INR per {selectedToken.symbol})
478-
</label>
487+
<div className="flex items-center justify-between mb-1">
488+
<label className="block text-sm font-medium text-gray-700">
489+
Start Price (INR per {selectedToken.symbol})
490+
</label>
491+
{makerSettings.defaultStartPrice && formData.startPrice === makerSettings.defaultStartPrice && (
492+
<span className="text-xs bg-blue-100 text-blue-600 px-2 py-1 rounded">
493+
Using default
494+
</span>
495+
)}
496+
</div>
479497
<input
480498
type="number"
481499
name="startPrice"
@@ -492,9 +510,16 @@ export default function CreateOrder({ onOrderCreated }: CreateOrderProps) {
492510

493511
{/* End Price */}
494512
<div>
495-
<label className="block text-sm font-medium text-gray-700 mb-1">
496-
End Price (INR per {selectedToken.symbol})
497-
</label>
513+
<div className="flex items-center justify-between mb-1">
514+
<label className="block text-sm font-medium text-gray-700">
515+
End Price (INR per {selectedToken.symbol})
516+
</label>
517+
{makerSettings.defaultEndPrice && formData.endPrice === makerSettings.defaultEndPrice && (
518+
<span className="text-xs bg-blue-100 text-blue-600 px-2 py-1 rounded">
519+
Using default
520+
</span>
521+
)}
522+
</div>
498523
<input
499524
type="number"
500525
name="endPrice"

frontend/src/components/Navigation.tsx

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,20 @@ export default function Navigation() {
3131
</Link>
3232

3333
{isConnected && isRegistered && (
34-
<Link
35-
href="/maker-dashboard"
36-
className="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium transition-colors"
37-
>
38-
Maker Dashboard
39-
</Link>
34+
<>
35+
<Link
36+
href="/maker-dashboard"
37+
className="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium transition-colors"
38+
>
39+
Maker Dashboard
40+
</Link>
41+
<Link
42+
href="/settings"
43+
className="text-gray-600 hover:text-gray-900 px-3 py-2 rounded-md text-sm font-medium transition-colors"
44+
>
45+
Settings
46+
</Link>
47+
</>
4048
)}
4149

4250
{isConnected && !isRegistered && (
@@ -68,12 +76,20 @@ export default function Navigation() {
6876
</Link>
6977

7078
{isConnected && isRegistered && (
71-
<Link
72-
href="/maker-dashboard"
73-
className="text-gray-600 hover:text-gray-900 block px-3 py-2 rounded-md text-base font-medium"
74-
>
75-
Maker Dashboard
76-
</Link>
79+
<>
80+
<Link
81+
href="/maker-dashboard"
82+
className="text-gray-600 hover:text-gray-900 block px-3 py-2 rounded-md text-base font-medium"
83+
>
84+
Maker Dashboard
85+
</Link>
86+
<Link
87+
href="/settings"
88+
className="text-gray-600 hover:text-gray-900 block px-3 py-2 rounded-md text-base font-medium"
89+
>
90+
Settings
91+
</Link>
92+
</>
7793
)}
7894

7995
{isConnected && !isRegistered && (

0 commit comments

Comments
 (0)