diff --git a/components/FTXFileUpload/index.tsx b/components/FTXFileUpload/index.tsx index 6001c8b..c73c61b 100644 --- a/components/FTXFileUpload/index.tsx +++ b/components/FTXFileUpload/index.tsx @@ -2,66 +2,64 @@ import BackIcon from 'components/Icons/BackIcon'; import LinkIcon from 'components/Icons/LinkIcon'; import { useEffect, useRef, useState } from 'react'; import { supabase } from 'utils/supabaseClient'; -import HCaptcha from "@hcaptcha/react-hcaptcha"; +import HCaptcha from '@hcaptcha/react-hcaptcha'; import classNames from 'classnames'; -import styles from "styles/yams.module.css" +import styles from 'styles/yams.module.css'; const FTXFileUpload = () => { const [email, setEmail] = useState(''); const [isValidEmail, setIsValidEmail] = useState(false); const [isFileUploaded, setIsFileUploaded] = useState(false); - const [captchaToken, setCaptchaToken] = useState(); + const [captchaToken, setCaptchaToken] = useState(); const [isLoading, setIsLoading] = useState(false); const [isSubmitted, setIsSubmitted] = useState(false); const [confirmationCode, setConfirmationCode] = useState(''); const [isSuccess, setIsSuccess] = useState(false); - const [file, setFile] = useState(); - const captchaRef = useRef(null); + const [file, setFile] = useState(); + const captchaRef = useRef(null); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - captchaRef.current?.execute(); - }; - - const handleFileUpload = (e: any) => { - setFile(e.target.files[0]) - setIsFileUploaded(true) - } + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + captchaRef.current?.execute(); + }; - // handling email + file submit - useEffect(() => { - const onVerified = async () => { - setIsLoading(true); - if (!isValidEmail || !isFileUploaded) { - setIsLoading(false); - return; - } - const { data, error } = await supabase.auth.signInWithOtp({ - email: email, - options: { - captchaToken - } - }); - if (error) console.log(error); - else { - const ftxFile = file - const { data, error } = await supabase - .storage - .from('FTX Files') - .upload(`${email}.pdf`, ftxFile) - if (error) { - console.log(error) - } - } - setIsLoading(false); - setIsSubmitted(true); - }; - captchaRef.current?.resetCaptcha(); - onVerified() - }, [captchaToken]) + const handleFileUpload = (e: any) => { + setFile(e.target.files[0]); + setIsFileUploaded(true); + }; + // handling email + file submit + useEffect(() => { + const onVerified = async () => { + setIsLoading(true); + if (!isValidEmail || !isFileUploaded) { + setIsLoading(false); + return; + } + const { data, error } = await supabase.auth.signInWithOtp({ + email: email, + options: { + captchaToken, + }, + }); + if (error) console.log(error); + else { + const ftxFile = file; + const { data, error } = await supabase.storage + .from('FTX Files') + .upload(`${email}.pdf`, ftxFile); + if (error) { + console.log(error); + } + } + setIsLoading(false); + setIsSubmitted(true); + }; + captchaRef.current?.resetCaptcha(); + onVerified(); + }, [captchaToken]); - // regex email verification + // regex email verification useEffect(() => { const res = email.match( /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ @@ -70,14 +68,14 @@ const FTXFileUpload = () => { else setIsValidEmail(false); }, [email]); - // cap verification code length at 6 + // cap verification code length at 6 const maxLengthCheck = (object: any) => { if (object.target.value.length > object.target.maxLength) { object.target.value = object.target.value.slice(0, object.target.maxLength); } }; - // handling verification code submit + // handling verification code submit const verificationSubmit = async (e: React.MouseEvent) => { setIsLoading(true); e.preventDefault(); @@ -94,23 +92,30 @@ const FTXFileUpload = () => { }; return ( -
+

Proof of Rug

{!isSubmitted ? (
-

+

Attach your FTX Customer Claim Form to prove you lost funds.

@@ -121,20 +126,30 @@ const FTXFileUpload = () => { type="email" onChange={(event) => setEmail(event.target.value)} value={email} - className={classNames(`w-full py-2 px-4 bg-transparent rounded-3xl mt-1 - focus:outline-0 focus:border-primary transition placeholder:text-[#0000003b]`, styles.inputIndent)} + className={classNames( + `w-full py-2 px-4 bg-transparent rounded-3xl mt-1 + focus:outline-0 focus:border-primary transition placeholder:text-[#0000003b]`, + styles.inputIndent + )} placeholder="Email" /> -
+
@@ -143,14 +158,17 @@ const FTXFileUpload = () => {
{!isSuccess ? (
-

+

In order to verify your email, enter the verification code sent to your email.

setConfirmationCode(event.target.value)} value={confirmationCode} @@ -159,11 +177,15 @@ const FTXFileUpload = () => { />
) : (
- Email verified successfully! -
+ Email verified successfully! +
)}
)} diff --git a/components/Header/index.tsx b/components/Header/index.tsx index d45cf36..60dc80a 100644 --- a/components/Header/index.tsx +++ b/components/Header/index.tsx @@ -173,7 +173,7 @@ export default function Header() { className={classNames( `${ isYams ? 'bg-slate-1000 rounded-3xl' : '!bg-slate-900 !border-slate-300 !text-white' - } whitespace-nowrap text-[0.8rem]`, + } whitespace-nowrap text-[0.8rem] hidden sm:block`, styles.blackButtonShadow )} variant="outline" diff --git a/components/LockingRoom/LinkingScreen.tsx b/components/LockingRoom/LinkingScreen.tsx index f9c490e..9a755d1 100644 --- a/components/LockingRoom/LinkingScreen.tsx +++ b/components/LockingRoom/LinkingScreen.tsx @@ -1,25 +1,14 @@ -// Libraries import React, { useEffect } from 'react'; import { Button, Progress } from '@chakra-ui/react'; import styles from 'styles/yams.module.css'; -// Components (Internal) import LinkIcon from 'components/Icons/LinkIcon'; import BackIcon from 'components/Icons/BackIcon'; import CompleteIcon from 'components/Icons/CompleteIcon'; - -// Components (External) import { toast } from 'react-toastify'; - -// Hooks (Exteneral) import { useRouter } from 'next/router'; - -// Hooks (Internal) import useLinkExchangeMutations from 'mutations/farming/useLinkExchangeMutations'; import useUserFarmingQuery from 'queries/farming/useUserFarmingQuery'; - -// Internal import { Room } from 'pages/farming/[room]'; -import { ProgressBar } from 'react-toastify/dist/components'; import { extractDexExchangeEntries, stripObjOfNonVolume, sumValues } from '../../utils/points'; import classNames from 'classnames'; import rooms from 'utils/config/rooms'; @@ -28,7 +17,7 @@ import { Timer } from 'components/Timer'; const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { /* ================================== state ================================== */ - const [status, setStatus] = React.useState('none'); // none || linking || waiting || completed + const [status, setStatus] = React.useState('linking'); // none || linking || waiting || completed const [publicKey, setPublicKey] = React.useState(''); const [secretKey, setSecretKey] = React.useState(''); const [apiPass, setApiPass] = React.useState(''); @@ -44,9 +33,9 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { try { time = JSON.parse(localStorage.getItem(`last${room.name}SubmissionTime`) || ''); } catch (error) { - console.log(error) + setCanRetry(true) + console.log(error); } - if (time) { const lastSubmissionTime = new Date(time); lastSubmissionTime.setHours(lastSubmissionTime.getHours() + 1); @@ -71,7 +60,7 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { setCanRetry(true); } } - }, [storedTime]); + }, [storedTime, status]); useEffect(() => { if (!room) { @@ -80,10 +69,9 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { const exchangeKey = room.exchange_id.toLowerCase(); - console.log(userFarmingQuery.data); - console.log(room); + if (userFarmingQuery.isLoading) { - setStatus('waiting'); + setStatus('loading'); } if (userFarmingQuery.data) { @@ -100,7 +88,7 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { Number( // Combine Binance futures and spot Number(userFarmingQuery.data.volume['binance']) + - Number(userFarmingQuery.data.volume['binancecoinm']) + Number(userFarmingQuery.data.volume['binancecoinm']) ) ); } else if (room.exchange_id == 'GMX') { @@ -108,7 +96,7 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { Number( // Combine Binance futures and spot Number(userFarmingQuery.data.volume['gmx_arbitrum']) + - Number(userFarmingQuery.data.volume['gmx_avalanche']) + Number(userFarmingQuery.data.volume['gmx_avalanche']) ) ); linkStatus = userFarmingQuery.data.volume[`gmx_status`]; @@ -130,19 +118,19 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { setVolume(Number(Number(linkVolume).toFixed(2))); } - if (linkStatus === 'processing' || linkStatus === 'queued') { + if (linkVolume >= 0) { + setStatus('completed'); + } else if (linkStatus === 'processing' || linkStatus === 'queued') { setStatus('waiting'); } else if (linkStatus === 'success') { setStatus('completed'); - } else if (linkStatus === 'failed' && linkVolume >= 0) { - setStatus('completed'); } else if (linkStatus === 'failed') { setStatus('failed'); } else { - setStatus('none'); + setStatus('linking'); } } - }, [userFarmingQuery.data]); + }, [userFarmingQuery.data, userFarmingQuery.isLoading]); /* ================================== functions ================================== */ async function handleSubmit() { setLoading(true); @@ -174,7 +162,15 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { } else { toast.error(JSON.stringify(error)); } - } else { + } + else if (!data.message.success) { + setStatus('linking'); + setLoading(false); + if (data?.message.message) { + toast.error(JSON.stringify(data.message.message).replaceAll('"', '')); + } + } + else { setStatus('waiting'); setLoading(false); userFarmingQuery.refetch(); @@ -220,23 +216,27 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { {/* Title (link) */}

- {status === 'none' ? `Link to ${room ? room.exchange_id : ''}` : ''} - {status === 'linking' ? 'Setup link' : ''} - {status === 'waiting' ? 'Processing your trading volume...' : ''} + {status === 'none' || status === 'linking' ? `Link to ${room ? room.exchange_id : ''}` : ''} + {status === 'loading' ? '' : ''} + {status === 'waiting' ? 'Processing your volume' : ''} {status === 'completed' ? 'Linked' : ''} {status === 'failed' - ? `There was an error...` // It's taking longer than usual to connect to ${room.exchange_id}, we're investigating. Your submission time was recorded. + ? `There was an error` // It's taking longer than usual to connect to ${room.exchange_id}, we're investigating. Your submission time was recorded. : ''}

+ + {status === 'loading' && ( +

Preparing the room...

+ )} + {/* description (link your api keys || Your api keys may take some time) */}

- {status === 'none' && 'Link your trading account'} - {status === 'waiting' && "We're crunching the numbers on your trading volume."} + {(status === 'none' || (room?.dex && status === 'linking')) && 'Link your trading account'} + {status === 'waiting' && "We're crunching the numbers - check back later."} {status === 'failed' && !canRetry && (
- This may be because these keys are invalid, or they have been submitted via another - account. + This may have occurred due to invalid keys, submitting the same keys via another account, or recent submissions from another account.
In order to prevent spam, you can retry in: @@ -262,7 +262,8 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { )} {/* {status === 'waiting' && ' We have recorded the time of your submission.'} */} {status === 'completed' && - `Your trading volume has been calculated and attached to your address.`} + `Your ${room.dex ? 'decentralised ' : '' + }trading volume has been calculated and attached to your address.`}

{/* Link button (hide when linking) */} {status === 'none' && ( @@ -297,7 +298,7 @@ const LinkingScreen: React.FC<{ room: Room }> = ({ room }) => { = ({ room }) => { = ({ room }) => { )} {status === 'linking' && (
- {/* Back button */} - - {/* -- */} - {/* Submit Button */} - -
- - {/* Data Points */} -
- {['Data1', 'Data2', 'Data3', 'Data4'].map((data, idx) => ( -
-

{`Heading ${idx + 1}`}

-

{data}

-
- ))} -
-
-
- ))} -
-
- ) - ) : ( - - )} - - - ); -} \ No newline at end of file diff --git a/pages/vote/[council].tsx b/pages/vote/[council].tsx index 37169a7..742fba1 100644 --- a/pages/vote/[council].tsx +++ b/pages/vote/[council].tsx @@ -47,7 +47,7 @@ export default function VoteCouncil() { return ( <> - Infinex | Governance V3 + Infinex | Governance
{activeCouncil && } diff --git a/pages/vote/index.tsx b/pages/vote/index.tsx index 88ae1b8..c18fa54 100644 --- a/pages/vote/index.tsx +++ b/pages/vote/index.tsx @@ -7,7 +7,7 @@ export default function Vote() { return ( <> - Infinex | Governance V3 + Infinex | Governance
diff --git a/public/favicon.ico b/public/favicon.ico index fa3d93c..d276911 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/queries/farming/useUserFarmingQuery.ts b/queries/farming/useUserFarmingQuery.ts index 5ba77d1..b72768c 100644 --- a/queries/farming/useUserFarmingQuery.ts +++ b/queries/farming/useUserFarmingQuery.ts @@ -59,7 +59,7 @@ function extractAndCombine(exchanges: { [key: string]: any }) { } function useUserFarmingQuery() { - console.log('calling useUserFarmingQuery'); + // console.log('calling useUserFarmingQuery'); const { walletAddress } = useConnectorContext(); return useQuery( diff --git a/utils/config/rooms.ts b/utils/config/rooms.ts index 5cc6b45..53a062f 100644 --- a/utils/config/rooms.ts +++ b/utils/config/rooms.ts @@ -1,27 +1,15 @@ const rooms = [ - { - type: 'dex', - key: 13, - name: 'Spot Dex Sauna', - description: 'Connect your address\\nEarn Voting Power', - emoji: '❀️‍πŸ”₯', - token: '', - info: "We collect volumes from over 30 spot DEX's incouding Uniswap, Sushiswap and Curve", - exchange_id: 'Spot Dex', - needsApiPass: false, - linking: false, - dex: true, - }, { type: 'cex', key: 1, name: 'Binance Forecourt', - description: 'Deposit BNB\\nEarn Voting Power', + description: 'Lock BNB\\nEarn Voting Power', emoji: 'β›²', token: 'BNB', exchange_id: 'Binance', needsApiPass: false, linking: true, + locking: true, dex: false, extra_details: 'Only BNB on the binance smart chain will be detected.', guide: @@ -31,52 +19,70 @@ const rooms = [ type: 'dex', key: 14, name: 'Spartan Grounds', - description: 'Connect your address\\nEarn Voting Power', + description: 'Connect your wallet\\nEarn Voting Power', emoji: 'βš”οΈ', token: '', exchange_id: 'SNX', needsApiPass: false, - linking: false, + linking: true, + locking: false, + dex: true, + }, + { + type: 'dex', + key: 13, + name: 'AMM Sauna', + description: 'Prove volume on Curve, Sushi and Uniswap \\nEarn Voting Power', + emoji: 'πŸ¦„', + token: '', + info: "We collect volumes from over 30 AMMs including Uniswap, Sushiswap and Curve", + exchange_id: 'Spot Dex', + needsApiPass: false, + linking: true, + locking: false, dex: true, }, { type: 'cex', key: 2, name: 'FTX Panic Room', - description: 'Deposit FTT\\nEarn Voting Power', + description: 'Lock FTT\\nEarn Voting Power', emoji: '🫣', token: 'FTT', exchange_id: 'FTX', needsApiPass: false, linking: false, + locking: true, dex: false, }, { type: 'cex', key: 3, name: 'Kucoin Scullery', - description: 'Deposit KCS\\nEarn Voting Power', + description: 'Lock KCS\\nEarn Voting Power', emoji: 'πŸ›–', token: 'KCS', exchange_id: 'Kucoin', needsApiPass: true, linking: true, + locking: true, dex: false, extra_details: 'Only KCS on Ethereum Mainnet will be detected.', guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/kucoin-guide', }, - // {type:"cex", key: 4, name: "His Excellency’s Chambers", description: "Deposit HT, Earn Voting Power", emoji: "πŸ§–β€β™‚οΈ", token: "HT", exchange_id: "Huobi", needsApiPass: false}, + // {type:"cex", key: 4, name: "His Excellency’s Chambers", description: "Lock HT, Earn Voting Power", emoji: "πŸ§–β€β™‚οΈ", token: "HT", exchange_id: "Huobi", needsApiPass: false}, { type: 'cex', key: 5, name: 'BitMex Ballroom', - description: 'Deposit BMEX\\nEarn Voting Power', + description: 'Lock BMEX\\nEarn Voting Power', emoji: 'πŸ’ƒ', token: 'BMEX', exchange_id: 'Bitmex', needsApiPass: false, linking: true, + locking: true, dex: false, guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/bitmex-guide', @@ -84,39 +90,42 @@ const rooms = [ { type: 'dex', key: 6, - name: 'Dydx Observatory', - description: 'Deposit DYDX\\nEarn Voting Power', + name: 'dYdX Observatory', + description: 'Lock dYdX\\nEarn Voting Power', emoji: 'πŸ”­', token: 'DYDX', exchange_id: 'Dydx', - info: 'We track your deposits to DYDX layer 2', + info: 'We track your deposits to dYdX layer 2', needsApiPass: false, linking: true, + locking: true, dex: true, }, { type: 'dex', key: 7, - name: 'Blueberry fields', - description: 'Deposit GMX\\nEarn Voting Power', + name: 'Blueberry Fields', + description: 'Lock GMX\\nEarn Voting Power', emoji: '🫐', token: 'GMX', info: 'We collect volumes from Arbirtum and Avalanche', exchange_id: 'GMX', needsApiPass: false, linking: true, + locking: true, dex: true, }, { type: 'cex', key: 8, name: 'Bybit Pillow Chamber', - description: 'Deposit MNT\\nEarn Voting Power', + description: 'Lock MNT\\nEarn Voting Power', emoji: 'πŸŒ–', token: 'MNT', exchange_id: 'Bybit', needsApiPass: false, linking: true, + locking: true, dex: false, extra_details: 'Only MNT on Ethereum Mainnet will be detected.', guide: @@ -126,12 +135,13 @@ const rooms = [ type: 'cex', key: 9, name: 'OKX Pitstop', - description: 'Deposit OKB\\nEarn Voting Power', + description: 'Lock OKB\\nEarn Voting Power', emoji: '🏁', token: 'OKB', exchange_id: 'OKX', needsApiPass: true, linking: true, + locking: true, dex: false, guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/okx-guide', @@ -140,12 +150,13 @@ const rooms = [ type: 'cex', key: 10, name: 'The Bitget Laundromat', - description: 'Deposit BGB\\nEarn Voting Power', + description: 'Lock BGB\\nEarn Voting Power', emoji: '🧺', token: 'BGB', exchange_id: 'Bitget', needsApiPass: true, linking: true, + locking: true, dex: false, guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/bitget-guide', @@ -154,12 +165,13 @@ const rooms = [ type: 'cex', key: 11, name: 'MEXC Nursery', - description: 'Deposit MX\\nEarn Voting Power', - emoji: 'πŸ‘©β€βš•οΈ', + description: 'Lock MX\\nEarn Voting Power', + emoji: '🀱', token: 'MX', exchange_id: 'MEXC', needsApiPass: false, linking: true, + locking: true, dex: false, guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/mexc-guide', @@ -175,6 +187,7 @@ const rooms = [ info: "Krakens API really does not like what we're doing, please be patient getting your results", needsApiPass: false, linking: false, + locking: true, dex: false, guide: 'https://docs.infinex.io/governance/elections-and-voting/governance-farming/linking-your-api-keys/kraken-guide', diff --git a/utils/numbers.ts b/utils/numbers.ts index 8a4f063..2bb2632 100644 --- a/utils/numbers.ts +++ b/utils/numbers.ts @@ -6,30 +6,33 @@ * @return The formatted percentage string or "Loading..." if undefined. */ export const formatPercent = (num: number | undefined): string => { - if (typeof num === 'undefined') { - return 'Loading...'; - } - if (num >= 0 && num < 100) { - return `${(num).toFixed(2)}%`; - } else if (num >= 100) { - return `Pending calculation..` - } else { - return `0%` - } - }; - - /** - * Format a number generally with 2 decimal places and locale-specific formatting. - * @param num - The number to be formatted. - * @param locale - The locale for formatting. Default is 'en-US'. - * @return The formatted number string or "Loading..." if undefined. - */ - export const formatNumberWithLocale = (num: number | undefined, locale: string = 'en-US'): string => { - if (typeof num === 'undefined' || typeof locale === 'undefined') { - return 'Loading...'; - } - return num.toLocaleString(locale, { - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }); - }; \ No newline at end of file + if (typeof num === 'undefined') { + return 'Loading...'; + } + if (num >= 0 && num < 100) { + return `${num.toFixed(5)}%`; + } else if (num >= 100) { + return `Pending calculation..`; + } else { + return `0%`; + } +}; + +/** + * Format a number generally with 2 decimal places and locale-specific formatting. + * @param num - The number to be formatted. + * @param locale - The locale for formatting. Default is 'en-US'. + * @return The formatted number string or "Loading..." if undefined. + */ +export const formatNumberWithLocale = ( + num: number | undefined, + locale: string = 'en-US' +): string => { + if (typeof num === 'undefined' || typeof locale === 'undefined') { + return 'Loading...'; + } + return num.toLocaleString(locale, { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }); +};