Add more test for the daily volumes and add button to set the UIFee Factor
This commit is contained in:
@@ -222,6 +222,106 @@ export const useClaimUiFees = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// ABI for the setUiFeeFactor function
|
||||
const SET_UI_FEE_FACTOR_ABI = parseAbi([
|
||||
'function setUiFeeFactor(uint256 uiFeeFactor) external',
|
||||
])
|
||||
|
||||
// UI Fee Receiver contract address on Arbitrum (from Arbiscan)
|
||||
const UI_FEE_RECEIVER_ADDRESS = '0x602b805EedddBbD9ddff44A7dcBD46cb07849685'
|
||||
|
||||
/**
|
||||
* Custom hook to update UI fee factor on GMX ExchangeRouter contract
|
||||
*/
|
||||
export const useUpdateUiFee = () => {
|
||||
const { address, isConnected } = useAccount()
|
||||
const chainId = useChainId()
|
||||
const { switchChainAsync } = useSwitchChain()
|
||||
const { writeContractAsync } = useWriteContract()
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const [txHash, setTxHash] = useState<string | null>(null)
|
||||
|
||||
/**
|
||||
* Updates the UI fee factor by calling the ExchangeRouter contract
|
||||
* @param percentage The fee percentage (e.g., 0.1 for 0.1%)
|
||||
*/
|
||||
const updateUiFeeFactor = async (percentage: number) => {
|
||||
if (!isConnected || !address) {
|
||||
throw new Error('Wallet not connected')
|
||||
}
|
||||
|
||||
if (percentage < 0 || percentage > 100) {
|
||||
throw new Error('Fee percentage must be between 0 and 100')
|
||||
}
|
||||
|
||||
setIsLoading(true)
|
||||
setError(null)
|
||||
setTxHash(null)
|
||||
|
||||
try {
|
||||
// Switch to Arbitrum if not already on it
|
||||
if (chainId !== arbitrum.id) {
|
||||
await switchChainAsync({ chainId: arbitrum.id })
|
||||
}
|
||||
|
||||
// Convert percentage to basis points (1% = 100 basis points)
|
||||
// GMX typically uses factors with 30 decimal places (10^30 total precision)
|
||||
const basisPoints = Math.round(percentage * 100) // Convert to basis points
|
||||
const feeFactor = BigInt(basisPoints) * BigInt(10) ** BigInt(26) // Multiply by 10^26 to get the factor (10^30 - 10^4 for basis points)
|
||||
|
||||
console.log('Updating UI fee factor:')
|
||||
console.log(`Percentage: ${percentage}%`)
|
||||
console.log(`Basis points: ${basisPoints}`)
|
||||
console.log(`Fee factor: ${feeFactor.toString()}`)
|
||||
|
||||
// Call the setUiFeeFactor function on the contract
|
||||
const hash = await writeContractAsync({
|
||||
address: UI_FEE_RECEIVER_ADDRESS,
|
||||
abi: SET_UI_FEE_FACTOR_ABI,
|
||||
functionName: 'setUiFeeFactor',
|
||||
args: [feeFactor],
|
||||
})
|
||||
|
||||
setTxHash(hash)
|
||||
return hash
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred'
|
||||
setError(errorMessage)
|
||||
throw new Error(`Failed to update UI fee factor: ${errorMessage}`)
|
||||
} finally {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
updateUiFeeFactor,
|
||||
isLoading,
|
||||
error,
|
||||
txHash,
|
||||
isConnected,
|
||||
address,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to monitor UI fee update transaction status
|
||||
*/
|
||||
export const useUpdateUiFeeTransaction = (txHash: string | null) => {
|
||||
const { data, isLoading, isSuccess, isError } = useWaitForTransactionReceipt({
|
||||
hash: txHash as `0x${string}` | undefined,
|
||||
chainId: arbitrum.id,
|
||||
})
|
||||
|
||||
return {
|
||||
transactionData: data,
|
||||
isConfirming: isLoading,
|
||||
isConfirmed: isSuccess,
|
||||
isError,
|
||||
}
|
||||
}
|
||||
|
||||
// Export the allowed tickers for use in other components
|
||||
export { ALLOWED_TICKERS, type AllowedTicker }
|
||||
|
||||
|
||||
@@ -5,7 +5,13 @@ import LogIn from '../../components/mollecules/LogIn/LogIn'
|
||||
import useCookie from '../../hooks/useCookie'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {useAuthStore} from '../../app/store/accountStore'
|
||||
import {ALLOWED_TICKERS, useClaimUiFees, useClaimUiFeesTransaction} from '../../hooks/useClaimUiFees'
|
||||
import {
|
||||
ALLOWED_TICKERS,
|
||||
useClaimUiFees,
|
||||
useClaimUiFeesTransaction,
|
||||
useUpdateUiFee,
|
||||
useUpdateUiFeeTransaction
|
||||
} from '../../hooks/useClaimUiFees'
|
||||
import Toast from '../../components/mollecules/Toast/Toast'
|
||||
import useApiUrlStore from '../../app/store/apiStore'
|
||||
|
||||
@@ -85,11 +91,19 @@ export const Auth = ({ children }: any) => {
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [claimAccountAddress, setClaimAccountAddress] = useState('')
|
||||
const [showClaimSection, setShowClaimSection] = useState(false)
|
||||
|
||||
// Update UI Fee state
|
||||
const [uiFeePercentage, setUiFeePercentage] = useState('')
|
||||
const [showUpdateUiFeeSection, setShowUpdateUiFeeSection] = useState(false)
|
||||
|
||||
// Claim UI fees hook
|
||||
const { claimUiFees, isLoading: isClaimingFees, txHash, error: claimError } = useClaimUiFees()
|
||||
const { isConfirming, isConfirmed, isError: txError } = useClaimUiFeesTransaction(txHash)
|
||||
|
||||
// Update UI fee hook
|
||||
const { updateUiFeeFactor, isLoading: isUpdatingFee, txHash: updateTxHash, error: updateFeeError } = useUpdateUiFee()
|
||||
const { isConfirming: isUpdateConfirming, isConfirmed: isUpdateConfirmed, isError: updateTxError } = useUpdateUiFeeTransaction(updateTxHash)
|
||||
|
||||
useEffect(() => {
|
||||
if (ready) {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -122,6 +136,23 @@ export const Auth = ({ children }: any) => {
|
||||
toast.update('error', 'Transaction failed')
|
||||
}
|
||||
}, [txError])
|
||||
|
||||
// Handle successful UI fee update
|
||||
useEffect(() => {
|
||||
if (isUpdateConfirmed) {
|
||||
const toast = new Toast('Success')
|
||||
toast.update('success', 'UI fee factor updated successfully!')
|
||||
setUiFeePercentage('') // Clear the input
|
||||
}
|
||||
}, [isUpdateConfirmed])
|
||||
|
||||
// Handle UI fee update transaction error
|
||||
useEffect(() => {
|
||||
if (updateTxError) {
|
||||
const toast = new Toast('Error')
|
||||
toast.update('error', 'UI fee update transaction failed')
|
||||
}
|
||||
}, [updateTxError])
|
||||
|
||||
const handleClaimUiFees = async () => {
|
||||
if (!isConnected) {
|
||||
@@ -149,6 +180,33 @@ export const Auth = ({ children }: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateUiFee = async () => {
|
||||
if (!isConnected) {
|
||||
const toast = new Toast('Error')
|
||||
toast.update('error', 'Please connect your wallet first')
|
||||
return
|
||||
}
|
||||
|
||||
const percentage = parseFloat(uiFeePercentage)
|
||||
if (isNaN(percentage) || percentage < 0 || percentage > 100) {
|
||||
const toast = new Toast('Error')
|
||||
toast.update('error', 'Please enter a valid percentage between 0 and 100')
|
||||
return
|
||||
}
|
||||
|
||||
const toast = new Toast('Updating UI fee factor...')
|
||||
|
||||
try {
|
||||
toast.update('info', 'Submitting transaction to update UI fee factor...')
|
||||
await updateUiFeeFactor(percentage)
|
||||
toast.update('info', 'Transaction submitted, waiting for confirmation...')
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred'
|
||||
toast.update('error', `Failed to update UI fee factor: ${errorMessage}`)
|
||||
console.error('Error updating UI fee factor:', err)
|
||||
}
|
||||
}
|
||||
|
||||
if (!ready || isLoading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
@@ -288,6 +346,125 @@ export const Auth = ({ children }: any) => {
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Update UI Fee Section */}
|
||||
<div style={{ textAlign: 'center', marginTop: '20px' }}>
|
||||
<button
|
||||
onClick={() => setShowUpdateUiFeeSection(!showUpdateUiFeeSection)}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: showUpdateUiFeeSection ? '#6B7280' : '#8B5CF6',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: 'pointer',
|
||||
fontSize: '16px'
|
||||
}}
|
||||
>
|
||||
{showUpdateUiFeeSection ? 'Hide' : 'Update UI Fee'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{showUpdateUiFeeSection && (
|
||||
<div style={{
|
||||
padding: '20px',
|
||||
backgroundColor: '#F3F4F6',
|
||||
borderRadius: '8px',
|
||||
maxWidth: '400px',
|
||||
width: '100%',
|
||||
marginTop: '20px'
|
||||
}}>
|
||||
<h3 style={{ margin: '0 0 15px 0', fontSize: '18px', color: '#111827' }}>
|
||||
Update GMX UI Fee Factor
|
||||
</h3>
|
||||
<p style={{ margin: '0 0 10px 0', fontSize: '14px', color: '#6B7280' }}>
|
||||
Set the UI fee factor percentage for GMX trading. This will be automatically formatted for the smart contract.
|
||||
</p>
|
||||
<details style={{ marginBottom: '15px', fontSize: '12px', color: '#6B7280' }}>
|
||||
<summary style={{ cursor: 'pointer', fontWeight: '500' }}>
|
||||
How it works
|
||||
</summary>
|
||||
<div style={{
|
||||
marginTop: '8px',
|
||||
padding: '8px',
|
||||
backgroundColor: '#E5E7EB',
|
||||
borderRadius: '4px',
|
||||
lineHeight: '1.6'
|
||||
}}>
|
||||
Enter a percentage (e.g., 0.1 for 0.1%). This gets converted to basis points and formatted for the GMX contract.
|
||||
The fee factor determines the percentage of trading fees that go to the UI/interface.
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{isConnected && walletAddress && (
|
||||
<div style={{ marginBottom: '15px', fontSize: '12px', color: '#059669' }}>
|
||||
✓ Wallet connected: {walletAddress.slice(0, 6)}...{walletAddress.slice(-4)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isConnected && (
|
||||
<div style={{ marginBottom: '15px', fontSize: '12px', color: '#DC2626' }}>
|
||||
⚠ Please connect your wallet first
|
||||
</div>
|
||||
)}
|
||||
|
||||
<input
|
||||
type="number"
|
||||
placeholder="Enter fee percentage (e.g., 0.1)"
|
||||
value={uiFeePercentage}
|
||||
onChange={(e) => setUiFeePercentage(e.target.value)}
|
||||
min="0"
|
||||
max="100"
|
||||
step="0.01"
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px',
|
||||
marginBottom: '15px',
|
||||
border: '1px solid #D1D5DB',
|
||||
borderRadius: '4px',
|
||||
fontSize: '14px',
|
||||
boxSizing: 'border-box'
|
||||
}}
|
||||
/>
|
||||
|
||||
<button
|
||||
onClick={handleUpdateUiFee}
|
||||
disabled={!isConnected || isUpdatingFee || isUpdateConfirming || !uiFeePercentage.trim()}
|
||||
style={{
|
||||
width: '100%',
|
||||
padding: '10px 20px',
|
||||
backgroundColor: (!isConnected || isUpdatingFee || isUpdateConfirming || !uiFeePercentage.trim()) ? '#9CA3AF' : '#8B5CF6',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
borderRadius: '4px',
|
||||
cursor: (!isConnected || isUpdatingFee || isUpdateConfirming || !uiFeePercentage.trim()) ? 'not-allowed' : 'pointer',
|
||||
fontSize: '16px'
|
||||
}}
|
||||
>
|
||||
{isUpdatingFee ? 'Signing...' : isUpdateConfirming ? 'Confirming...' : isUpdateConfirmed ? 'Updated!' : 'Update UI Fee Factor'}
|
||||
</button>
|
||||
|
||||
{(updateFeeError) && (
|
||||
<div style={{ marginTop: '10px', fontSize: '12px', color: '#DC2626' }}>
|
||||
{updateFeeError}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{updateTxHash && (
|
||||
<div style={{ marginTop: '10px', fontSize: '12px' }}>
|
||||
<p style={{ color: '#059669', margin: '0 0 5px 0' }}>Transaction Hash:</p>
|
||||
<a
|
||||
href={`https://arbiscan.io/tx/${updateTxHash}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ color: '#8B5CF6', wordBreak: 'break-all' }}
|
||||
>
|
||||
{updateTxHash}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
} else if (!token) {
|
||||
|
||||
Reference in New Issue
Block a user