diff --git a/.example.env b/.example.env index d4724cde..a8f33fb6 100644 --- a/.example.env +++ b/.example.env @@ -42,3 +42,6 @@ NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=XXX # Add a Reservoir API key for NFT price information RESERVOIR_API_KEY=XXX + +# +NEXT_PUBLIC_FAIRSIDE_API_KEY=zrvPR6NlCgtFRljj89db \ No newline at end of file diff --git a/app/[locale]/address/[addressOrName]/coverage/page.tsx b/app/[locale]/address/[addressOrName]/coverage/page.tsx new file mode 100644 index 00000000..78663bbb --- /dev/null +++ b/app/[locale]/address/[addressOrName]/coverage/page.tsx @@ -0,0 +1,21 @@ +import CoverageDashboard from 'components/coverage/CoverageDashboard'; +import type { NextPage } from 'next'; +import { unstable_setRequestLocale } from 'next-intl/server'; + +// Re-use metadata generation from the address page +export { generateMetadata } from '../page'; + +interface Props { + params: { + locale: string; + addressOrName: string; + }; +} + +const AddressSignaturesPage: NextPage = ({ params }) => { + unstable_setRequestLocale(params.locale); + + return ; +}; + +export default AddressSignaturesPage; diff --git a/components/address/navigation/AddressNavigation.tsx b/components/address/navigation/AddressNavigation.tsx index 166e43e2..0511b7b9 100644 --- a/components/address/navigation/AddressNavigation.tsx +++ b/components/address/navigation/AddressNavigation.tsx @@ -10,12 +10,13 @@ const AddressNavigation = () => { const basePath = `/address/${addressOrName}`; const signaturesPath = `${basePath}/signatures`; - + const coveragePath = `${basePath}/coverage`; return (
); diff --git a/components/coverage/CoverageDashboard.tsx b/components/coverage/CoverageDashboard.tsx new file mode 100644 index 00000000..5a921ef4 --- /dev/null +++ b/components/coverage/CoverageDashboard.tsx @@ -0,0 +1,81 @@ +'use client'; + +import { Env, FsdSDK } from '@fairside-foundation/sdk'; +import { FAIRSIDE_API_KEY } from 'lib/constants'; +import { useAddressPageContext } from 'lib/hooks/page-context/AddressPageContext'; +import { useMounted } from 'lib/hooks/useMounted'; +import { useTranslations } from 'next-intl'; +import { useEffect, useState } from 'react'; +import CoverageDetailsCard from './CoverageDetailsCard'; +import CoverageInfo from './CoverageInfo'; +import MembershipCard from './MembershipCard'; +import WalletDetails from './WalletDetails'; + +interface Props { + isActive: boolean; + coverageAmount?: number | null; +} + +interface MembershipInfo { + statusCode: number; + hasCover: boolean; + isActive: boolean; + validFrom: string | null; + validUntil: string | null; + coverAmount: number | null; + activeClaims: string[]; +} + +const CoverageDashboard = ({ isActive = false, coverageAmount = null }: Props) => { + const isMounted = useMounted(); + const { address } = useAddressPageContext(); + const [token, setToken] = useState(null); + const t = useTranslations(); + + const { fsdAPI, fsdContract, fsdConfig } = FsdSDK({ + apiKey: FAIRSIDE_API_KEY ?? '', + env: Env.TestNet, + }); + const [membershipInfo, setMembershipInfo] = useState(null); + useEffect(() => { + async function fetchMembershipInfo() { + const results = await fsdAPI.getPublicMembershipInfo({ walletAddress: address }); + setMembershipInfo(results); + } + fetchMembershipInfo(); + }, [address, fsdAPI.getPublicMembershipInfo]); + return ( +
+ {isMounted && membershipInfo && ( +
+
+ + {membershipInfo.isActive && ( + + )} +
+ {!membershipInfo.isActive && } + {membershipInfo.isActive && ( +
+ window.open('https://test.fairside.dev/', '_blank')} + /> +
+ )} +
+ )} +
+ ); +}; + +export default CoverageDashboard; diff --git a/components/coverage/CoverageDetailsCard.tsx b/components/coverage/CoverageDetailsCard.tsx new file mode 100644 index 00000000..bc6e71f6 --- /dev/null +++ b/components/coverage/CoverageDetailsCard.tsx @@ -0,0 +1,101 @@ +import { useTranslations } from 'next-intl'; +import { twMerge } from 'tailwind-merge'; + +const formatDate = (dateString: string | null): string => { + if (!dateString) return ''; + + const date = new Date(dateString); + const month = date.toLocaleString('en-US', { month: 'short' }); + const day = date.getDate(); + const year = date.getFullYear(); + + // Add appropriate suffix to day + const suffix = ['th', 'st', 'nd', 'rd'][day % 10 > 3 ? 0 : day % 10] || 'th'; + return `${month} ${day}${suffix}, ${year}`; +}; + +const getExpiryInfo = (validUntil: string | null): { text: string; isWarning: boolean; isDanger: boolean } => { + if (!validUntil) return { text: '', isWarning: false, isDanger: false }; + + const now = new Date(); + const expiryDate = new Date(validUntil); + const daysUntilExpiry = Math.ceil((expiryDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); + + return { + text: `Expires in ${daysUntilExpiry} days!`, + isWarning: daysUntilExpiry <= 60, + isDanger: daysUntilExpiry <= 30, + }; +}; + +interface CoverageDetailsProps { + coverageAmount: number | null; + validFrom: string | null; + validUntil: string | null; + claimsCount: number | null; + onIncrease?: () => void; + className?: string; +} + +const CoverageDetailsCard = ({ + coverageAmount, + validFrom, + validUntil, + claimsCount, + onIncrease, + className, +}: CoverageDetailsProps) => { + const t = useTranslations('address.coverage'); + + const expiryInfo = getExpiryInfo(validUntil); + const expiryClass = twMerge( + 'text-sm text-gray-500 dark:text-gray-400 italic', + expiryInfo.isWarning && 'text-yellow-500 dark:text-yellow-400', + expiryInfo.isDanger && 'text-red-500 dark:text-red-400', + ); + + return ( +
+
+ {t('membership_card_title')} +
+ +
+ {t('amount')}: +
+ {coverageAmount} ETH + {onIncrease && ( + + )} +
+
+ +
+ Timeframe: +
+
+ {`${formatDate(validFrom)} - ${formatDate(validUntil)}`} +
+
{expiryInfo.text}
+
+
+ +
+ {t('claims')}: +
+ + {claimsCount === 0 ? t('not_covered') : `${claimsCount} claims`} + +
+
+
+ ); +}; + +export default CoverageDetailsCard; diff --git a/components/coverage/CoverageInfo.tsx b/components/coverage/CoverageInfo.tsx new file mode 100644 index 00000000..d92e22e5 --- /dev/null +++ b/components/coverage/CoverageInfo.tsx @@ -0,0 +1,25 @@ +import Card from 'components/common/Card'; +import { useTranslations } from 'next-intl'; + +const CoverageInfo = () => { + const t = useTranslations('address.coverage.info'); + + return ( +
+ +
+

{t('what.title')}

+

{t('what.description')}

+
+
+ +
+

{t('how.title')}

+

{t('how.description')}

+
+
+
+ ); +}; + +export default CoverageInfo; diff --git a/components/coverage/MembershipCard.tsx b/components/coverage/MembershipCard.tsx new file mode 100644 index 00000000..360dcaba --- /dev/null +++ b/components/coverage/MembershipCard.tsx @@ -0,0 +1,34 @@ +import { useTranslations } from 'next-intl'; +import { twMerge } from 'tailwind-merge'; + +interface Props { + isActive: boolean; + coverageAmount?: number | null; +} + +const MembershipCard = ({ isActive, coverageAmount = null }: Props) => { + const t = useTranslations(); + + return ( +
+
{t('address.coverage.membership_card_title')}
+
+
+ {t('address.coverage.status')}: + + {isActive ? t('address.coverage.covered') : t('address.coverage.not_covered')} + +
+ + {isActive && coverageAmount && ( +
+ {t('address.coverage.amount')}: + {coverageAmount} ETH +
+ )} +
+
+ ); +}; + +export default MembershipCard; diff --git a/components/coverage/WalletDetails.tsx b/components/coverage/WalletDetails.tsx new file mode 100644 index 00000000..68696c9b --- /dev/null +++ b/components/coverage/WalletDetails.tsx @@ -0,0 +1,160 @@ +import CopyButton from 'components/common/CopyButton'; +import { useTranslations } from 'next-intl'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; +import { twMerge } from 'tailwind-merge'; +import { useWalletClient } from 'wagmi'; + +interface WalletDetailsProps { + isAuthenticated: boolean; + className?: string; + fsdAPI?: any; + walletAddress?: string; + token?: string | null; + setToken: (token: string) => void; +} + +interface WalletEntry { + walletAddress: string; +} + +interface SignatureResponse { + message: string; + walletAddress: string; + nonce: string; +} + +const WalletDetails = ({ isAuthenticated, className, fsdAPI, walletAddress, token, setToken }: WalletDetailsProps) => { + const t = useTranslations('address.coverage'); + const [wallets, setWallets] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const { data: walletClient } = useWalletClient(); + + const handleAuthentication = async () => { + if (!fsdAPI || !walletAddress || !walletClient) { + console.log('fsdAPI', fsdAPI); + console.log('walletAddress', walletAddress); + console.log('walletClient', walletClient); + toast.error('Missing required data for authentication'); + return; + } + + try { + setIsLoading(true); + + // Step 1: Generate message to sign + const messageData = await fsdAPI.generateMessageToSign(walletAddress); + if (!messageData) { + toast.error('Failed to generate message to sign'); + return; + } + + // Step 2: Request signature from user + const signature = await walletClient.signMessage({ + message: messageData.message as `0x${string}`, + }); + + // Step 3: Verify signature with Fairside + const response = await fsdAPI.createOrLoginUser({ + walletAddress, + signature, + nonce: messageData.nonce, + referralCode: 'revoke.cash', + }); + if (!response?.token) { + toast.error('Failed to authenticate'); + return; + } + + setToken(response.token); + + // Step 4: Fetch wallets after successful authentication + const walletDataResponse = await fsdAPI.getCoveredWallets({ accessToken: response.token }); + setWallets([{ walletAddress: walletAddress ?? '' }, ...walletDataResponse.wallets]); + } catch (error) { + console.error('Authentication error:', error); + toast.error('Failed to authenticate with Fairside'); + setWallets([{ walletAddress: walletAddress ?? '' }]); + } finally { + setIsLoading(false); + } + }; + + const handleAddWallet = async () => { + try { + // This would need to be implemented based on Fairside's SDK + // Typically would open a modal or redirect to add wallet flow + window.open('https://test.fairside.dev/add-wallet', '_blank'); + } catch (error) { + console.error('Error adding wallet:', error); + toast.error('Failed to add wallet'); + } + }; + if (!isAuthenticated) { + return ( +
+
+ Covered Wallets +
+
+

+ Connect your wallet to view and manage your covered wallets +

+ +
+
+ ); + } + + return ( +
+
+
Covered Wallets{isAuthenticated && ` - ${wallets && wallets.length > 0 ? wallets.length : ''}`}
+
Max 10 wallets
+
+
+ {isLoading ? ( +
Loading wallets...
+ ) : ( + wallets && + Array.isArray(wallets) && + wallets.map((wallet) => ( +
+
+
+ {wallets.indexOf(wallet) + 1}. +
+ + {wallet.walletAddress.slice(0, 6)}...{wallet.walletAddress.slice(-4)} + + +
+ {/* + {wallet.chain} + */} +
+ )) + )} +
+ {wallets && wallets.length < 10 && ( +
+ +
+ )} +
+ ); +}; + +export default WalletDetails; diff --git a/lib/constants.ts b/lib/constants.ts index d8705f23..6537cbaf 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -31,3 +31,4 @@ export const HARPIE_API_KEY = process.env.HARPIE_API_KEY ?? process.env.NEXT_PUB export const WEBACY_API_KEY = process.env.WEBACY_API_KEY ?? process.env.NEXT_PUBLIC_WEBACY_API_KEY; export const NEFTURE_API_KEY = process.env.NEFTURE_API_KEY ?? process.env.NEXT_PUBLIC_NEFTURE_API_KEY; export const RESERVOIR_API_KEY = process.env.RESERVOIR_API_KEY ?? process.env.NEXT_PUBLIC_RESERVOIR_API_KEY; +export const FAIRSIDE_API_KEY = process.env.FAIRSIDE_API_KEY ?? process.env.NEXT_PUBLIC_FAIRSIDE_API_KEY; diff --git a/locales/en/address.json b/locales/en/address.json index 998645d5..03e2b422 100644 --- a/locales/en/address.json +++ b/locales/en/address.json @@ -70,7 +70,8 @@ "history": "History", "more": "More", "settings": "Settings", - "signatures": "Signatures" + "signatures": "Signatures", + "coverage": "Coverage" }, "permit2": { "expiration": "Expires {inTime}" @@ -98,6 +99,24 @@ "search": { "spender": "Search by Approved Spender Address" }, + "coverage": { + "membership_card_title": "Fairside Membership", + "status": "Status", + "claims": "Claims", + "amount": "Amount", + "covered": "Covered", + "not_covered": "Not Covered", + "info": { + "what": { + "title": "What is Coverage?", + "description": "Get paid if you get drained. Fairside is the first Crypto native coverage platform that allows you to purchase coverage for your wallet in the event of numerous loss events such as malicious trxns & signatures, malware, and address poisoning." + }, + "how": { + "title": "How to get Covered", + "description": "1. Input the amount you want to be covered (in ETH), and pay 1.95% of that amount. 2. Add all the wallets that are covered across the 11+ chains." + } + } + }, "signatures": { "info": { "description": "Because signatures are not stored on the blockchain, there is no way for Revoke.cash to know if you signed any signatures. So this page contains a list of known marketplaces and a list of your tokens that support offchain Permit signatures. Only if you know that you signed an offchain signature on a scam website, you need to cancel the potential signatures on this page, otherwise you are wasting transaction fees. When you cancel potential signatures for a token or marketplace, they will remain in the list but cannot be cancelled again for some time." diff --git a/package.json b/package.json index 682471f1..e828c610 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@abstract-foundation/agw-client": "^1.0.0", "@abstract-foundation/agw-react": "^1.0.0", "@dotenvx/dotenvx": "^1.14.2", + "@fairside-foundation/sdk": "^1.0.29", "@headlessui/react": "^2.1.2", "@heroicons/react": "^2.1.5", "@neondatabase/serverless": "^0.10.1", diff --git a/yarn.lock b/yarn.lock index 7b08b42e..415f05c9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,6 +52,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:1.10.1": + version: 1.10.1 + resolution: "@adraffy/ens-normalize@npm:1.10.1" + checksum: 10/4cb938c4abb88a346d50cb0ea44243ab3574330c81d4f5aaaf9dfee584b96189d0faa404de0fcbef5a1b73909ea4ebc3e63d84bd23f9949e5c8d4085207a5091 + languageName: node + linkType: hard + "@adraffy/ens-normalize@npm:^1.10.1": version: 1.11.0 resolution: "@adraffy/ens-normalize@npm:1.11.0" @@ -665,6 +672,15 @@ __metadata: languageName: node linkType: hard +"@emotion/is-prop-valid@npm:1.2.2": + version: 1.2.2 + resolution: "@emotion/is-prop-valid@npm:1.2.2" + dependencies: + "@emotion/memoize": "npm:^0.8.1" + checksum: 10/0fa3960abfbe845d40cc230ab8c9408e1f33d3c03b321980359911c7212133cdcb0344d249e9dab23342b304567eece7a10ec44b986f7230e0640ba00049dceb + languageName: node + linkType: hard + "@emotion/memoize@npm:^0.8.1": version: 0.8.1 resolution: "@emotion/memoize@npm:0.8.1" @@ -713,7 +729,7 @@ __metadata: languageName: node linkType: hard -"@emotion/unitless@npm:^0.8.1": +"@emotion/unitless@npm:0.8.1, @emotion/unitless@npm:^0.8.1": version: 0.8.1 resolution: "@emotion/unitless@npm:0.8.1" checksum: 10/918f73c46ac0b7161e3c341cc07d651ce87e31ab1695e74b12adb7da6bb98dfbff8c69cf68a4e40d9eb3d820ca055dc1267aeb3007927ce88f98b885bf729b63 @@ -953,6 +969,21 @@ __metadata: languageName: node linkType: hard +"@fairside-foundation/sdk@npm:^1.0.29": + version: 1.0.29 + resolution: "@fairside-foundation/sdk@npm:1.0.29" + dependencies: + axios: "npm:^1.6.0" + ethers: "npm:6.11.1" + styled-components: "npm:^6.1.8" + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + styled-components: ^6.1.8 + checksum: 10/300291bb47d6976417a92d383330f6bf0aae36884eb5b649cd1fc905972b068a799c931678847378b71a3181756960e9d1395910b63c0868f2fc823ca5db6109 + languageName: node + linkType: hard + "@floating-ui/core@npm:^1.6.0": version: 1.6.4 resolution: "@floating-ui/core@npm:1.6.4" @@ -1762,6 +1793,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.2.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: 10/94e02e9571a9fd42a3263362451849d2f54405cb3ce9fa7c45bc6b9b36dcd7d1d20e2e1e14cfded24937a13d82f1e60eefc4d7a14982ce0bc219a9fc0f51d1f9 + languageName: node + linkType: hard + "@noble/curves@npm:1.4.0, @noble/curves@npm:^1.4.0, @noble/curves@npm:~1.4.0": version: 1.4.0 resolution: "@noble/curves@npm:1.4.0" @@ -2789,6 +2829,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:18.15.13": + version: 18.15.13 + resolution: "@types/node@npm:18.15.13" + checksum: 10/b9bbe923573797ef7c5fd2641a6793489e25d9369c32aeadcaa5c7c175c85b42eb12d6fe173f6781ab6f42eaa1ebd9576a419eeaa2a1ec810094adb8adaa9a54 + languageName: node + linkType: hard + "@types/nprogress@npm:^0.2.3": version: 0.2.3 resolution: "@types/nprogress@npm:0.2.3" @@ -2881,6 +2928,13 @@ __metadata: languageName: node linkType: hard +"@types/stylis@npm:4.2.5": + version: 4.2.5 + resolution: "@types/stylis@npm:4.2.5" + checksum: 10/f8dde326432a7047b6684b96442f0e2ade2cfe8c29bf56217fb8cbbe4763997051fa9dc0f8dba4aeed2fddb794b4bc91feba913b780666b3adc28198ac7c63d4 + languageName: node + linkType: hard + "@types/trusted-types@npm:^2.0.2": version: 2.0.7 resolution: "@types/trusted-types@npm:2.0.7" @@ -3473,6 +3527,13 @@ __metadata: languageName: node linkType: hard +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: 10/8f745da2e8fb38e91297a8ec13c2febe3219f8383303cd4ed4660ca67190242ccfd5fdc2f0d1642fd1ea934818fb871cd4cc28d3f28e812e3dc6c3d0f1f97c24 + languageName: node + linkType: hard + "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": version: 7.1.1 resolution: "agent-base@npm:7.1.1" @@ -3744,6 +3805,17 @@ __metadata: languageName: node linkType: hard +"axios@npm:^1.6.0": + version: 1.7.9 + resolution: "axios@npm:1.7.9" + dependencies: + follow-redirects: "npm:^1.15.6" + form-data: "npm:^4.0.0" + proxy-from-env: "npm:^1.1.0" + checksum: 10/b7a5f660ea53ba9c2a745bf5ad77ad8bf4f1338e13ccc3f9f09f810267d6c638c03dac88b55dae8dc98b79c57d2d6835be651d58d2af97c174f43d289a9fd007 + languageName: node + linkType: hard + "babel-plugin-macros@npm:^3.1.0": version: 3.1.0 resolution: "babel-plugin-macros@npm:3.1.0" @@ -4006,6 +4078,13 @@ __metadata: languageName: node linkType: hard +"camelize@npm:^1.0.0": + version: 1.0.1 + resolution: "camelize@npm:1.0.1" + checksum: 10/0e147b4299ac6363c50050716aadfae42831257ec56ce54773ffd2a94a88abb2e2540c5ccc38345e8a39963105b76d86cb24477165a36b78c9958fb304513db3 + languageName: node + linkType: hard + "caniuse-lite@npm:^1.0.30001579, caniuse-lite@npm:^1.0.30001646": version: 1.0.30001660 resolution: "caniuse-lite@npm:1.0.30001660" @@ -4395,7 +4474,7 @@ __metadata: languageName: node linkType: hard -"combined-stream@npm:^1.0.6, combined-stream@npm:~1.0.6": +"combined-stream@npm:^1.0.6, combined-stream@npm:^1.0.8, combined-stream@npm:~1.0.6": version: 1.0.8 resolution: "combined-stream@npm:1.0.8" dependencies: @@ -4651,6 +4730,24 @@ __metadata: languageName: node linkType: hard +"css-color-keywords@npm:^1.0.0": + version: 1.0.0 + resolution: "css-color-keywords@npm:1.0.0" + checksum: 10/8f125e3ad477bd03c77b533044bd9e8a6f7c0da52d49bbc0bbe38327b3829d6ba04d368ca49dd9ff3b667d2fc8f1698d891c198bbf8feade1a5501bf5a296408 + languageName: node + linkType: hard + +"css-to-react-native@npm:3.2.0": + version: 3.2.0 + resolution: "css-to-react-native@npm:3.2.0" + dependencies: + camelize: "npm:^1.0.0" + css-color-keywords: "npm:^1.0.0" + postcss-value-parser: "npm:^4.0.2" + checksum: 10/62ef744254e333abc696efdc945ecf13ad6ba7b726d0a39c0405b2fcb86542aa2f3fe7b7b6770f67ae9679d98b159b4d66353107bf7d6144a445eafcf5fa250a + languageName: node + linkType: hard + "css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" @@ -4667,7 +4764,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2, csstype@npm:^3.0.7": +"csstype@npm:3.1.3, csstype@npm:^3.0.2, csstype@npm:^3.0.7": version: 3.1.3 resolution: "csstype@npm:3.1.3" checksum: 10/f593cce41ff5ade23f44e77521e3a1bcc2c64107041e1bf6c3c32adc5187d0d60983292fda326154d20b01079e24931aa5b08e4467cc488b60bb1e7f6d478ade @@ -5393,6 +5490,21 @@ __metadata: languageName: node linkType: hard +"ethers@npm:6.11.1": + version: 6.11.1 + resolution: "ethers@npm:6.11.1" + dependencies: + "@adraffy/ens-normalize": "npm:1.10.1" + "@noble/curves": "npm:1.2.0" + "@noble/hashes": "npm:1.3.2" + "@types/node": "npm:18.15.13" + aes-js: "npm:4.0.0-beta.5" + tslib: "npm:2.4.0" + ws: "npm:8.5.0" + checksum: 10/bfeba2670dbfdac3951a66ab2d5bbc18dd7e1be69da9142ad4fe3859a30891e7bb048ecbb6ab542b67df777ada1860445bb3dd83536219c0d3639fe05e74df8e + languageName: node + linkType: hard + "event-target-shim@npm:^5.0.0": version: 5.0.1 resolution: "event-target-shim@npm:5.0.1" @@ -5722,6 +5834,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.6": + version: 1.15.9 + resolution: "follow-redirects@npm:1.15.9" + peerDependenciesMeta: + debug: + optional: true + checksum: 10/e3ab42d1097e90d28b913903841e6779eb969b62a64706a3eb983e894a5db000fbd89296f45f08885a0e54cd558ef62e81be1165da9be25a6c44920da10f424c + languageName: node + linkType: hard + "for-each@npm:^0.3.3": version: 0.3.3 resolution: "for-each@npm:0.3.3" @@ -5748,6 +5870,17 @@ __metadata: languageName: node linkType: hard +"form-data@npm:^4.0.0": + version: 4.0.1 + resolution: "form-data@npm:4.0.1" + dependencies: + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: 10/6adb1cff557328bc6eb8a68da205f9ae44ab0e88d4d9237aaf91eed591ffc64f77411efb9016af7d87f23d0a038c45a788aa1c6634e51175c4efa36c2bc53774 + languageName: node + linkType: hard + "form-data@npm:~2.3.2": version: 2.3.3 resolution: "form-data@npm:2.3.3" @@ -9418,7 +9551,7 @@ __metadata: languageName: node linkType: hard -"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.2.0": +"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.0.2, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" checksum: 10/e4e4486f33b3163a606a6ed94f9c196ab49a37a7a7163abfcd469e5f113210120d70b8dd5e33d64636f41ad52316a3725655421eb9a1094f1bcab1db2f555c62 @@ -9436,6 +9569,17 @@ __metadata: languageName: node linkType: hard +"postcss@npm:8.4.38": + version: 8.4.38 + resolution: "postcss@npm:8.4.38" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.2.0" + checksum: 10/6e44a7ed835ffa9a2b096e8d3e5dfc6bcf331a25c48aeb862dd54e3aaecadf814fa22be224fd308f87d08adf2299164f88c5fd5ab1c4ef6cbd693ceb295377f4 + languageName: node + linkType: hard + "postcss@npm:^8.4.23, postcss@npm:^8.4.41": version: 8.4.45 resolution: "postcss@npm:8.4.45" @@ -9605,6 +9749,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: 10/f0bb4a87cfd18f77bc2fba23ae49c3b378fb35143af16cc478171c623eebe181678f09439707ad80081d340d1593cd54a33a0113f3ccb3f4bc9451488780ee23 + languageName: node + linkType: hard + "psl@npm:^1.1.33": version: 1.9.0 resolution: "psl@npm:1.9.0" @@ -10213,6 +10364,7 @@ __metadata: "@commitlint/config-conventional": "npm:^19.6.0" "@cypress/grep": "npm:^4.1.0" "@dotenvx/dotenvx": "npm:^1.14.2" + "@fairside-foundation/sdk": "npm:^1.0.29" "@headlessui/react": "npm:^2.1.2" "@heroicons/react": "npm:^2.1.5" "@lavamoat/allow-scripts": "npm:^3.2.0" @@ -10446,6 +10598,13 @@ __metadata: languageName: node linkType: hard +"shallowequal@npm:1.1.0": + version: 1.1.0 + resolution: "shallowequal@npm:1.1.0" + checksum: 10/f4c1de0837f106d2dbbfd5d0720a5d059d1c66b42b580965c8f06bb1db684be8783538b684092648c981294bf817869f743a066538771dbecb293df78f765e00 + languageName: node + linkType: hard + "sharp@npm:^0.33.5": version: 0.33.5 resolution: "sharp@npm:0.33.5" @@ -10963,6 +11122,26 @@ __metadata: languageName: node linkType: hard +"styled-components@npm:^6.1.8": + version: 6.1.14 + resolution: "styled-components@npm:6.1.14" + dependencies: + "@emotion/is-prop-valid": "npm:1.2.2" + "@emotion/unitless": "npm:0.8.1" + "@types/stylis": "npm:4.2.5" + css-to-react-native: "npm:3.2.0" + csstype: "npm:3.1.3" + postcss: "npm:8.4.38" + shallowequal: "npm:1.1.0" + stylis: "npm:4.3.2" + tslib: "npm:2.6.2" + peerDependencies: + react: ">= 16.8.0" + react-dom: ">= 16.8.0" + checksum: 10/de26960b8e2b8d9430e8a02a22a7fa1ae764d914064525008257fb5d469cbddb4ef9b8b5b5e4baaabd236bd77c84fdad9a8d5f0d2fd05ff39ff55d80a71ff9de + languageName: node + linkType: hard + "styled-jsx@npm:5.1.1": version: 5.1.1 resolution: "styled-jsx@npm:5.1.1" @@ -10986,6 +11165,13 @@ __metadata: languageName: node linkType: hard +"stylis@npm:4.3.2": + version: 4.3.2 + resolution: "stylis@npm:4.3.2" + checksum: 10/4d3e3cb5cbfc7abdf14e424c8631a15fd15cbf0357ffc641c319587e00c2d1036b1a71cb88b42411bc3ce10d7730ad3fb9789b034d11365e8a19d23f56486c77 + languageName: node + linkType: hard + "sucrase@npm:^3.32.0": version: 3.35.0 resolution: "sucrase@npm:3.35.0" @@ -11272,6 +11458,20 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.4.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 10/d8379e68b36caf082c1905ec25d17df8261e1d68ddc1abfd6c91158a064f6e4402039ae7c02cf4c81d12e3a2a2c7cd8ea2f57b233eb80136a2e3e7279daf2911 + languageName: node + linkType: hard + +"tslib@npm:2.6.2": + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 10/bd26c22d36736513980091a1e356378e8b662ded04204453d353a7f34a4c21ed0afc59b5f90719d4ba756e581a162ecbf93118dc9c6be5acf70aa309188166ca + languageName: node + linkType: hard + "tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": version: 2.6.3 resolution: "tslib@npm:2.6.3" @@ -12101,6 +12301,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.5.0": + version: 8.5.0 + resolution: "ws@npm:8.5.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10/f0ee700970a0bf925b1ec213ca3691e84fb8b435a91461fe3caf52f58c6cec57c99ed5890fbf6978824c932641932019aafc55d864cad38ac32577496efd5d3a + languageName: node + linkType: hard + "ws@npm:^7.3.1, ws@npm:^7.5.1": version: 7.5.10 resolution: "ws@npm:7.5.10"