From 32a0f06f09205b146ce1eeef426a081e6c0f7b47 Mon Sep 17 00:00:00 2001 From: AmAzing129 Date: Thu, 20 Jun 2024 16:48:10 +0800 Subject: [PATCH] feat(farcaster): init draft for supporting farcaster login --- packages/farcaster/.fatherrc.ts | 5 + packages/farcaster/README.md | 1 + packages/farcaster/package.json | 61 ++++ packages/farcaster/src/index.ts | 2 + .../src/provider/__tests__/utils.tsx | 19 ++ packages/farcaster/src/provider/index.tsx | 72 +++++ packages/farcaster/tsconfig.json | 4 + packages/web3/package.json | 1 + .../components/FarcasterCard.tsx | 33 +++ .../connect-modal/components/MainPanel.tsx | 2 + .../connect-modal/components/WalletList.tsx | 55 +++- .../web3/src/connect-modal/demos/basic.tsx | 2 +- packages/web3/src/connect-modal/index.tsx | 1 + packages/web3/src/connect-modal/interface.ts | 9 +- packages/web3/src/connector/connector.tsx | 10 +- packages/web3/src/farcaster/demos/login.tsx | 60 ++++ packages/web3/src/farcaster/index.zh-CN.md | 36 +++ pnpm-lock.yaml | 262 ++++++++++++++++++ 18 files changed, 629 insertions(+), 6 deletions(-) create mode 100644 packages/farcaster/.fatherrc.ts create mode 100644 packages/farcaster/README.md create mode 100644 packages/farcaster/package.json create mode 100644 packages/farcaster/src/index.ts create mode 100644 packages/farcaster/src/provider/__tests__/utils.tsx create mode 100644 packages/farcaster/src/provider/index.tsx create mode 100644 packages/farcaster/tsconfig.json create mode 100644 packages/web3/src/connect-modal/components/FarcasterCard.tsx create mode 100644 packages/web3/src/farcaster/demos/login.tsx create mode 100644 packages/web3/src/farcaster/index.zh-CN.md diff --git a/packages/farcaster/.fatherrc.ts b/packages/farcaster/.fatherrc.ts new file mode 100644 index 000000000..3305dd5a7 --- /dev/null +++ b/packages/farcaster/.fatherrc.ts @@ -0,0 +1,5 @@ +import { defineConfig } from 'father'; + +export default defineConfig({ + extends: '../../.fatherrc.base.ts', +}); diff --git a/packages/farcaster/README.md b/packages/farcaster/README.md new file mode 100644 index 000000000..464090415 --- /dev/null +++ b/packages/farcaster/README.md @@ -0,0 +1 @@ +# TODO diff --git a/packages/farcaster/package.json b/packages/farcaster/package.json new file mode 100644 index 000000000..c3e42293d --- /dev/null +++ b/packages/farcaster/package.json @@ -0,0 +1,61 @@ +{ + "name": "@ant-design/web3-farcaster", + "version": "1.0.0", + "main": "dist/lib/index.js", + "module": "dist/esm/index.js", + "typings": "dist/esm/index.d.ts", + "exports": { + "import": "./dist/esm/index.js", + "require": "./dist/lib/index.js", + "types": "./dist/esm/index.d.ts" + }, + "sideEffects": false, + "files": [ + "dist", + "CHANGELOG.md", + "README.md" + ], + "keywords": [ + "ant", + "component", + "components", + "design", + "framework", + "frontend", + "react", + "react-component", + "ui", + "web3", + "farcaster" + ], + "homepage": "https://web3.ant.design", + "bugs": { + "url": "https://github.com/ant-design/ant-design-web3/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/ant-design/ant-design-web3" + }, + "scripts": { + "dev": "father dev", + "build": "father build" + }, + "dependencies": { + "@farcaster/auth-client": "^0.1.1", + "@farcaster/auth-kit": "^0.3.1" + }, + "devDependencies": { + "father": "^4.4.4", + "typescript": "^5.4.5" + }, + "publishConfig": { + "registry": "https://registry.npmjs.org", + "access": "public" + }, + "browserslist": [ + "last 2 versions", + "Firefox ESR", + "> 1%", + "ie >= 11" + ] +} diff --git a/packages/farcaster/src/index.ts b/packages/farcaster/src/index.ts new file mode 100644 index 000000000..29d1306f9 --- /dev/null +++ b/packages/farcaster/src/index.ts @@ -0,0 +1,2 @@ +export * from './provider'; +export { QRCode } from '@farcaster/auth-kit'; diff --git a/packages/farcaster/src/provider/__tests__/utils.tsx b/packages/farcaster/src/provider/__tests__/utils.tsx new file mode 100644 index 000000000..3955fa77f --- /dev/null +++ b/packages/farcaster/src/provider/__tests__/utils.tsx @@ -0,0 +1,19 @@ +import type { FC } from 'react'; +import { render } from '@testing-library/react'; + +type RenderResult = ReturnType; +type RenderWithUtils = RenderResult & { + selector: (selector: string) => T | null; + selectors: (selector: string) => NodeListOf; +}; +type XRender = (Comp: FC, options?: Parameters[1]) => RenderWithUtils; + +export const xrender: XRender = (Comp, options) => { + const { baseElement, ...others } = render(, options); + return { + baseElement, + ...others, + selector: (selector) => baseElement.querySelector(selector), + selectors: (selector) => baseElement.querySelectorAll(selector), + }; +}; diff --git a/packages/farcaster/src/provider/index.tsx b/packages/farcaster/src/provider/index.tsx new file mode 100644 index 000000000..6f8f201d0 --- /dev/null +++ b/packages/farcaster/src/provider/index.tsx @@ -0,0 +1,72 @@ +import React, { useCallback, useEffect } from 'react'; +import type { Provider } from '@farcaster/auth-client'; +import { AuthKitProvider, useSignIn, type UseSignInArgs } from '@farcaster/auth-kit'; + +import '@farcaster/auth-kit/styles.css'; + +// declares locally in '@farcaster/auth-kit', but it is not exported +interface AuthKitConfig { + relay?: string; + domain?: string; + siweUri?: string; + rpcUrl?: string; + redirectUrl?: string; + version?: string; + provider?: Provider; +} + +interface IFarcasterContext extends Partial> { + farcasterSupported: boolean; + farcasterLogin: () => void; +} + +const FarcasterContext = React.createContext({ + farcasterSupported: false, + farcasterLogin: () => {}, +}); + +const FarcasterConfigProvider: React.FC> = ({ + children, + ...signInArgs +}) => { + const signInState = useSignIn(signInArgs); + const { isError, reconnect, signIn, channelToken, connect } = signInState; + + const farcasterLogin = useCallback(() => { + if (isError) { + reconnect(); + } + signIn(); + }, [isError, reconnect, signIn]); + + useEffect(() => { + if (!channelToken) { + connect(); + } + }, [channelToken, connect]); + + return ( + + {children} + + ); +}; + +interface Web3FarcasterProviderProps extends UseSignInArgs { + config?: AuthKitConfig; +} + +export const useFarcaster = () => { + const farcaster = React.useContext(FarcasterContext); + return farcaster; +}; + +export const FarcasterWeb3ConfigProvider: React.FC< + React.PropsWithChildren +> = ({ children, config = {}, ...signInArgs }) => { + return ( + + {children} + + ); +}; diff --git a/packages/farcaster/tsconfig.json b/packages/farcaster/tsconfig.json new file mode 100644 index 000000000..928e5b0ef --- /dev/null +++ b/packages/farcaster/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src", "global.d.ts"] +} diff --git a/packages/web3/package.json b/packages/web3/package.json index 8cd4ac361..2af2df0d3 100644 --- a/packages/web3/package.json +++ b/packages/web3/package.json @@ -46,6 +46,7 @@ "@ant-design/web3-assets": "workspace:*", "@ant-design/web3-common": "workspace:*", "@ant-design/web3-icons": "workspace:*", + "@ant-design/web3-farcaster": "workspace:*", "@ctrl/tinycolor": "^4.1.0", "@inline-svg-unique-id/react": "^1.2.3", "antd": "^5.17.3", diff --git a/packages/web3/src/connect-modal/components/FarcasterCard.tsx b/packages/web3/src/connect-modal/components/FarcasterCard.tsx new file mode 100644 index 000000000..52db663ce --- /dev/null +++ b/packages/web3/src/connect-modal/components/FarcasterCard.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { QRCode, useFarcaster } from '@ant-design/web3-farcaster'; + +import { connectModalContext } from '../context'; +import MainPanelHeader from './MainPanelHeader'; + +const FarcasterCard = () => { + const { url, error, isError } = useFarcaster(); + const { prefixCls } = React.useContext(connectModalContext); + + return ( + <> +
+ +
+ {isError ? ( + <> +
Error
+
{error?.message ?? 'Unknown error, please try again.'}
+ + ) : url ? ( + + ) : null} +
+
+
Scan with your phone's camera to continue.
+
+
+ + ); +}; + +export default FarcasterCard; diff --git a/packages/web3/src/connect-modal/components/MainPanel.tsx b/packages/web3/src/connect-modal/components/MainPanel.tsx index 8bb35cc03..00c186ecb 100644 --- a/packages/web3/src/connect-modal/components/MainPanel.tsx +++ b/packages/web3/src/connect-modal/components/MainPanel.tsx @@ -3,6 +3,7 @@ import React, { useContext } from 'react'; import { connectModalContext } from '../context'; import type { ConnectModalProps } from '../interface'; import DefaultGuidePanel from './DefaultGuidePanel'; +import FarcasterCard from './FarcasterCard'; import LinkPanel from './LinkPanel'; import QrCode from './QrCode'; import WalletCard from './WalletCard'; @@ -28,6 +29,7 @@ const MainPanel: React.FC = (props) => { {panelRoute === 'downloadQrCode' && selectedWallet ? ( ) : null} + {panelRoute === 'farcaster' ? : null} ); }; diff --git a/packages/web3/src/connect-modal/components/WalletList.tsx b/packages/web3/src/connect-modal/components/WalletList.tsx index 209894b45..c3fa1b7fd 100644 --- a/packages/web3/src/connect-modal/components/WalletList.tsx +++ b/packages/web3/src/connect-modal/components/WalletList.tsx @@ -1,5 +1,6 @@ import React, { forwardRef, useContext, useImperativeHandle, useMemo } from 'react'; import { QrcodeOutlined } from '@ant-design/icons'; +import { useFarcaster } from '@ant-design/web3-farcaster'; import { Button, List, Space, Typography } from 'antd'; import classNames from 'classnames'; @@ -69,7 +70,52 @@ const WalletList = forwardRef((props, r selectWallet, }; }); - const renderContent = (params?: { group?: string }) => { + + const { farcasterSupported, farcasterLogin } = useFarcaster(); + + const renderFarcasterContent = () => { + return farcasterSupported ? ( + ( + { + farcasterLogin(); + updatePanelRoute('farcaster', true); + }} + > +
+
图标
+ + {item.name} + +
+ +
+ )} + /> + ) : null; + }; + + const renderWalletsContent = (params?: { group?: string }) => { const { group } = params || {}; return ( @@ -123,12 +169,15 @@ const WalletList = forwardRef((props, r return (
+
+
{renderFarcasterContent()}
+
{internalGroup ? ( groupKeys.map((group) => (
{group}
- {renderContent({ + {renderWalletsContent({ group, })}
@@ -136,7 +185,7 @@ const WalletList = forwardRef((props, r )) ) : (
-
{renderContent()}
+
{renderWalletsContent()}
)}
diff --git a/packages/web3/src/connect-modal/demos/basic.tsx b/packages/web3/src/connect-modal/demos/basic.tsx index eb8208bfe..a061836db 100644 --- a/packages/web3/src/connect-modal/demos/basic.tsx +++ b/packages/web3/src/connect-modal/demos/basic.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { ConnectModal, ConnectModalProps } from '@ant-design/web3'; +import { ConnectModal, type ConnectModalProps } from '@ant-design/web3'; import { metadata_MetaMask, metadata_MobileConnect, diff --git a/packages/web3/src/connect-modal/index.tsx b/packages/web3/src/connect-modal/index.tsx index bd5ce63bd..e92c4656b 100644 --- a/packages/web3/src/connect-modal/index.tsx +++ b/packages/web3/src/connect-modal/index.tsx @@ -38,6 +38,7 @@ export const ConnectModal: React.FC & { onCancel={(e) => { onCancel?.(e); }} + destroyOnClose > , diff --git a/packages/web3/src/connect-modal/interface.ts b/packages/web3/src/connect-modal/interface.ts index d0eb02ec0..4cbc36a50 100644 --- a/packages/web3/src/connect-modal/interface.ts +++ b/packages/web3/src/connect-modal/interface.ts @@ -144,4 +144,11 @@ export type ConnectModalProps = ModalProps & connecting?: boolean; }; -export type PanelRoute = 'init' | 'guide' | 'wallet' | 'qrCode' | 'downloadQrCode' | 'link'; +export type PanelRoute = + | 'init' + | 'guide' + | 'wallet' + | 'qrCode' + | 'downloadQrCode' + | 'link' + | 'farcaster'; diff --git a/packages/web3/src/connector/connector.tsx b/packages/web3/src/connector/connector.tsx index 323b68d6b..e551e3fdf 100644 --- a/packages/web3/src/connector/connector.tsx +++ b/packages/web3/src/connector/connector.tsx @@ -1,6 +1,7 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { ConnectModal, type ConnectModalActionType } from '@ant-design/web3'; import type { Chain, ConnectOptions, ConnectorTriggerProps, Wallet } from '@ant-design/web3-common'; +import { useFarcaster } from '@ant-design/web3-farcaster'; import { message } from 'antd'; import useProvider from '../hooks/useProvider'; @@ -34,6 +35,13 @@ export const Connector: React.FC = (props) => { const actionRef = React.useRef(); const [messageApi, contextHolder] = message.useMessage(); + // close modal when login farcaster success + const { isSuccess } = useFarcaster(); + useEffect(() => { + if (!isSuccess) return; + setOpen(false); + }, [isSuccess]); + const connectWallet = async (wallet?: Wallet, options?: ConnectOptions) => { onConnect?.(); try { diff --git a/packages/web3/src/farcaster/demos/login.tsx b/packages/web3/src/farcaster/demos/login.tsx new file mode 100644 index 000000000..609656517 --- /dev/null +++ b/packages/web3/src/farcaster/demos/login.tsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { UserOutlined } from '@ant-design/icons'; +import { Connector, type ConnectorTriggerProps } from '@ant-design/web3'; +import { FarcasterWeb3ConfigProvider, useFarcaster } from '@ant-design/web3-farcaster'; +import { Avatar, Button, message, Space } from 'antd'; + +// Your custom login button +const CustomLoginBtn: React.FC = (props) => { + const { onConnectClick } = props; + return ( + + ); +}; + +const YourApp = () => { + const { data, isSuccess } = useFarcaster(); + + return ( + + {/* After a successful login, it often redirects to another page, and the login button disappears. */} + {!isSuccess ? ( + + + + ) : null} + + {/* Do something after login, e.g. display user profile */} + } + src={isSuccess ? data?.pfpUrl : undefined} + /> + {isSuccess ? data?.displayName : ''} + + + ); +}; + +const Login: React.FC = () => { + const [messageApi, contextHolder] = message.useMessage(); + + return ( + <> + {contextHolder} + messageApi.success('Welcome!')}> + + + + ); +}; + +export default Login; diff --git a/packages/web3/src/farcaster/index.zh-CN.md b/packages/web3/src/farcaster/index.zh-CN.md new file mode 100644 index 000000000..3cbaeeb5a --- /dev/null +++ b/packages/web3/src/farcaster/index.zh-CN.md @@ -0,0 +1,36 @@ +--- +nav: 组件 +subtitle: Farcaster +group: + title: 连接其他协议 + order: 3 +--- + +# Farcaster + +Ant Design Web3 官方提供了 `@ant-design/web3-farcaster`,支持 [Farcaster](https://docs.farcaster.xyz/) 生态的相关开发。 + +目前提供了开箱即用的 [Warpcast](https://warpcast.com/) 扫码登陆,即通过封装官方组件 `@farcaster/auth-kit`,在保持 `@ant-design/web3` UI 组件风格的基础上,使得开发者无需关注登陆逻辑,同时获取所有登陆相关数据。 + +## 扫码登陆 Farcaster 账户 + + + +## API + +### FarcasterWeb3ConfigProvider + +包含了所有 [useSignIn](https://docs.farcaster.xyz/auth-kit/hooks/use-sign-in) 的入参及下表参数 + +| 属性 | 描述 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| config | AuthKitConfig | [AuthKitConfig](https://docs.farcaster.xyz/auth-kit/auth-kit-provider) | `{}` | - | + +### useFarcaster + +包含了所有 [useSignIn](https://docs.farcaster.xyz/auth-kit/hooks/use-sign-in) 的返回及下表属性 + +| 属性 | 描述 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| farcasterSupported | 是否支持 farcaster 登陆方式,即被 FarcasterWeb3ConfigProvider 包裹时返回 true | `boolean` | `false` | - | +| farcasterLogin | 启动 farcaster 扫码登陆监听 | `() => void` | `() => {}` | - | diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9662233c1..3b8885ec1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -469,6 +469,22 @@ importers: specifier: ^5.4.5 version: 5.4.5 + packages/farcaster: + dependencies: + '@farcaster/auth-client': + specifier: ^0.1.1 + version: 0.1.1(ethers@6.11.1)(viem@2.15.1) + '@farcaster/auth-kit': + specifier: ^0.3.1 + version: 0.3.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)(viem@2.15.1) + devDependencies: + father: + specifier: ^4.4.4 + version: 4.4.4(@babel/core@7.24.3)(@types/node@20.14.2)(styled-components@5.3.11)(webpack@5.91.0) + typescript: + specifier: ^5.4.5 + version: 5.4.5 + packages/icons: dependencies: '@ant-design/icons': @@ -609,6 +625,9 @@ importers: '@ant-design/web3-common': specifier: workspace:* version: link:../common + '@ant-design/web3-farcaster': + specifier: workspace:* + version: link:../farcaster '@ant-design/web3-icons': specifier: workspace:* version: link:../icons @@ -5168,6 +5187,51 @@ packages: '@ethersproject/properties': 5.7.0 '@ethersproject/strings': 5.7.0 + /@farcaster/auth-client@0.1.1(ethers@6.11.1)(viem@2.15.1): + resolution: {integrity: sha512-6ZYsDKzvagsRiNLiJZfrx1P7tRKOHKSZtF9uM3Ihb+AMX0hTxrp5Y3tkSKxufPu9Sgxfc5FyzGUYw21lkqFFCA==} + peerDependencies: + ethers: 5.x || 6.x + viem: 1.x || 2.x + dependencies: + ethers: 6.11.1 + neverthrow: 6.2.2 + siwe: 2.3.2(ethers@6.11.1) + viem: 2.15.1(typescript@5.4.5) + dev: false + + /@farcaster/auth-client@0.1.1(ethers@6.13.1)(viem@2.15.1): + resolution: {integrity: sha512-6ZYsDKzvagsRiNLiJZfrx1P7tRKOHKSZtF9uM3Ihb+AMX0hTxrp5Y3tkSKxufPu9Sgxfc5FyzGUYw21lkqFFCA==} + peerDependencies: + ethers: 5.x || 6.x + viem: 1.x || 2.x + dependencies: + ethers: 6.13.1 + neverthrow: 6.2.2 + siwe: 2.3.2(ethers@6.13.1) + viem: 2.15.1(typescript@5.4.5) + dev: false + + /@farcaster/auth-kit@0.3.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)(viem@2.15.1): + resolution: {integrity: sha512-BlT5rgyIFy6/Lle4nrDOUrvz0GaHdQduStuEWc5KuU6Dub/NsKrliEJVDo1MzfJGh3DLOq1nz+7L2A00VU+UnQ==} + peerDependencies: + react: '>= 17' + react-dom: '>= 17' + dependencies: + '@farcaster/auth-client': 0.1.1(ethers@6.13.1)(viem@2.15.1) + '@vanilla-extract/css': 1.15.3 + ethers: 6.13.1 + qrcode: 1.5.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.10(@types/react@18.2.78)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - babel-plugin-macros + - bufferutil + - utf-8-validate + - viem + dev: false + /@floating-ui/core@0.6.2: resolution: {integrity: sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==} dev: false @@ -7728,6 +7792,15 @@ packages: - utf-8-validate dev: false + /@spruceid/siwe-parser@2.1.2: + resolution: {integrity: sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ==} + dependencies: + '@noble/hashes': 1.3.3 + apg-js: 4.4.0 + uri-js: 4.4.1 + valid-url: 1.0.9 + dev: false + /@stablelib/aead@1.0.1: resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} @@ -9454,6 +9527,28 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + /@vanilla-extract/css@1.15.3: + resolution: {integrity: sha512-mxoskDAxdQAspbkmQRxBvolUi1u1jnyy9WZGm+GeH8V2wwhEvndzl1QoK7w8JfA0WFevTxbev5d+i+xACZlPhA==} + dependencies: + '@emotion/hash': 0.9.1 + '@vanilla-extract/private': 1.0.5 + css-what: 6.1.0 + cssesc: 3.0.0 + csstype: 3.1.3 + dedent: 1.5.3 + deep-object-diff: 1.1.9 + deepmerge: 4.3.1 + media-query-parser: 2.0.2 + modern-ahocorasick: 1.0.1 + picocolors: 1.0.0 + transitivePeerDependencies: + - babel-plugin-macros + dev: false + + /@vanilla-extract/private@1.0.5: + resolution: {integrity: sha512-6YXeOEKYTA3UV+RC8DeAjFk+/okoNz/h88R+McnzA2zpaVqTR/Ep+vszkWYlGBcMNO7vEkqbq5nT/JMMvhi+tw==} + dev: false + /@vercel/ncc@0.33.3: resolution: {integrity: sha512-JGZ11QV+/ZcfudW2Cz2JVp54/pJNXbsuWRgSh2ZmmZdQBKXqBtIGrwI1Wyx8nlbzAiEFe7FHi4K1zX4//jxTnQ==} hasBin: true @@ -10708,6 +10803,10 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /apg-js@4.4.0: + resolution: {integrity: sha512-fefmXFknJmtgtNEXfPwZKYkMFX4Fyeyz+fNF6JWp87biGOPslJbCBVU158zvKRZfHBKnJDy8CMM40oLFGkXT8Q==} + dev: false + /appdirsjs@1.2.7: resolution: {integrity: sha512-Quji6+8kLBC3NnBeo14nPDq0+2jUs5s3/xEye+udFHumHhRk4M7aAMXp/PBJqkKYGuuyR9M/6Dq7d2AViiGmhw==} @@ -12781,6 +12880,15 @@ packages: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} + /dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: false + /deep-eql@4.1.3: resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} engines: {node: '>=6'} @@ -12796,6 +12904,10 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + /deep-object-diff@1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + dev: false + /deep-rename-keys@0.2.1: resolution: {integrity: sha512-RHd9ABw4Fvk+gYDWqwOftG849x0bYOySl/RgX0tLI9i27ZIeSO91mLZJEp7oPHOMFqHvpgu21YptmDt0FYD/0A==} engines: {node: '>=0.10.0'} @@ -12931,6 +13043,10 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + /detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -14055,6 +14171,22 @@ packages: - bufferutil - utf-8-validate + /ethers@6.13.1: + resolution: {integrity: sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A==} + engines: {node: '>=14.0.0'} + dependencies: + '@adraffy/ens-normalize': 1.10.1 + '@noble/curves': 1.2.0 + '@noble/hashes': 1.3.2 + '@types/node': 18.15.13 + aes-js: 4.0.0-beta.5 + tslib: 2.4.0 + ws: 8.17.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + /ethjs-unit@0.1.6: resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} engines: {node: '>=6.5.0', npm: '>=3'} @@ -14728,6 +14860,11 @@ packages: has-symbols: 1.0.3 hasown: 2.0.0 + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -17405,6 +17542,12 @@ packages: resolution: {integrity: sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==} dev: false + /media-query-parser@2.0.2: + resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} + dependencies: + '@babel/runtime': 7.24.5 + dev: false + /mem@5.1.1: resolution: {integrity: sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==} engines: {node: '>=8'} @@ -18135,6 +18278,10 @@ packages: pkg-types: 1.0.3 ufo: 1.3.2 + /modern-ahocorasick@1.0.1: + resolution: {integrity: sha512-yoe+JbhTClckZ67b2itRtistFKf8yPYelHLc7e5xAwtNAXxM6wJTUx2C7QeVSJFDzKT7bCIFyBVybPMKvmB9AA==} + dev: false + /motion@10.16.2: resolution: {integrity: sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==} dependencies: @@ -18263,6 +18410,10 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + /neverthrow@6.2.2: + resolution: {integrity: sha512-POR1FACqdK9jH0S2kRPzaZEvzT11wsOxLW520PQV/+vKi9dQe+hXq19EiOvYx7lSRaF5VB9lYGsPInynrnN05w==} + dev: false + /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: @@ -20770,6 +20921,41 @@ packages: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} + /react-remove-scroll-bar@2.3.6(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0) + tslib: 2.6.2 + dev: false + + /react-remove-scroll@2.5.10(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-m3zvBRANPBw3qxVVjEIPEQinkcwlFZ4qyomuWVpNJdv4c6MvHfXV0C3L9Jx5rr3HeBHKNRX+1jreB5QloDIJjA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@types/react@18.2.78)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0) + tslib: 2.6.2 + use-callback-ref: 1.3.2(@types/react@18.2.78)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.78)(react@18.2.0) + dev: false + /react-router-dom@6.3.0(react-dom@18.1.0)(react@18.1.0): resolution: {integrity: sha512-uaJj7LKytRxZNQV8+RbzJWnJ8K2nPsOOEuX7aQstlMZKQT0164C+X2w6bnkqU3sjtLvpd5ojrezAyfZ1+0sStw==} peerDependencies: @@ -20831,6 +21017,23 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.2.0 + tslib: 2.6.2 + dev: false + /react@18.1.0: resolution: {integrity: sha512-4oL8ivCz5ZEPyclFQXaNksK3adutVS8l2xzZU0cqEFrE9Sb7fC0EFK5uEk74wIreL1DERyjvsU915j1pcT2uEQ==} engines: {node: '>=0.10.0'} @@ -21748,6 +21951,30 @@ packages: sax: 1.3.0 dev: false + /siwe@2.3.2(ethers@6.11.1): + resolution: {integrity: sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==} + peerDependencies: + ethers: ^5.6.8 || ^6.0.8 + dependencies: + '@spruceid/siwe-parser': 2.1.2 + '@stablelib/random': 1.0.2 + ethers: 6.11.1 + uri-js: 4.4.1 + valid-url: 1.0.9 + dev: false + + /siwe@2.3.2(ethers@6.13.1): + resolution: {integrity: sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==} + peerDependencies: + ethers: ^5.6.8 || ^6.0.8 + dependencies: + '@spruceid/siwe-parser': 2.1.2 + '@stablelib/random': 1.0.2 + ethers: 6.13.1 + uri-js: 4.4.1 + valid-url: 1.0.9 + dev: false + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -23420,6 +23647,21 @@ packages: punycode: 1.4.1 qs: 6.11.2 + /use-callback-ref@1.3.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + tslib: 2.6.2 + dev: false + /use-debouncy@4.3.1(react@18.2.0): resolution: {integrity: sha512-K+qtK89KojRB2GbTGtmJRysSii+wVg540bYeW9YBF7jqtwoGjIpY3m71BP0NeZzOMCcbZ6ZodLw6QeN3ascTZg==} peerDependencies: @@ -23457,6 +23699,22 @@ packages: react: 18.2.0 dev: false + /use-sidecar@1.1.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.6.2 + dev: false + /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -23547,6 +23805,10 @@ packages: /v8-compile-cache@2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} + /valid-url@1.0.9: + resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} + dev: false + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: