diff --git a/.env.local.example b/.env.local.example index 718feb6..743b07e 100644 --- a/.env.local.example +++ b/.env.local.example @@ -19,4 +19,4 @@ WATCHTOWER_ENABLED=false APP_ID=xxx WATCHTOWER_URL=https://api.watchtower.starknet.id/service/add_message WATCHTOWER_TOKEN=xxx -LOG_EVERY_X_BLOCK=1 \ No newline at end of file +LOG_EVERY_X_BLOCK=1 diff --git a/components/verification/DiscordServerInfo.tsx b/components/verification/DiscordServerInfo.tsx index e3c3643..96b7f85 100644 --- a/components/verification/DiscordServerInfo.tsx +++ b/components/verification/DiscordServerInfo.tsx @@ -6,7 +6,7 @@ type DiscordServerInfoProps = { discordServerName: string; discordServerIcon?: string | null; network: string; - networkType: "ethereum" | "starknet"; + networkType: "ethereum" | "starknet" | "stellar"; }; const DiscordServerInfo = ({ @@ -18,11 +18,13 @@ const DiscordServerInfo = ({ const networkIcons = { ethereum: "/assets/ethereum-icon.png", starknet: "/assets/starknet-icon.png", + stellar: "/assets/stellar-icon.png", }; const networkLabels = { ethereum: "Ethereum network:", starknet: "Starknet network:", + stellar: "Stellar network:", }; return ( diff --git a/components/verification/DynamicVerificationRouter.tsx b/components/verification/DynamicVerificationRouter.tsx new file mode 100644 index 0000000..45951ce --- /dev/null +++ b/components/verification/DynamicVerificationRouter.tsx @@ -0,0 +1,73 @@ +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; +import { NetworkName } from "../../types/networks"; +import { + getChainType, + getVerifyPageForNetwork, +} from "../../utils/networkDetection"; + +type Props = { + network: NetworkName; + discordServerId: string; + discordMemberId: string; + customLink: string; +}; + +const DynamicVerificationRouter = ({ + network, + discordServerId, + discordMemberId, + customLink, +}: Props) => { + const router = useRouter(); + const [isRouting, setIsRouting] = useState(false); + + useEffect(() => { + const routeToCorrectPage = async () => { + try { + setIsRouting(true); + const chainType = getChainType(network); + + if (!chainType) { + console.error(`Unknown chain type for network: ${network}`); + return; + } + + const correctVerifyPage = getVerifyPageForNetwork(network); + const currentPath = router.asPath; + const targetPath = `/${correctVerifyPage}/${discordServerId}/${discordMemberId}/${customLink}`; + + // Only route if we're not already on the correct page + if (!currentPath.includes(`/${correctVerifyPage}/`)) { + console.log( + `Routing from current page to ${targetPath} for ${chainType} network` + ); + await router.replace(targetPath); + } + } catch (error) { + console.error("Error during dynamic routing:", error); + } finally { + setIsRouting(false); + } + }; + + if (network && discordServerId && discordMemberId && customLink) { + routeToCorrectPage(); + } + }, [network, discordServerId, discordMemberId, customLink, router]); + + if (isRouting) { + return ( +
+

+ Detecting network type and routing to the appropriate wallet + connection... +

+
+ ); + } + + return null; +}; + +export default DynamicVerificationRouter; diff --git a/components/verification/WalletInfo.tsx b/components/verification/WalletInfo.tsx index 00af3b3..2b09c3c 100644 --- a/components/verification/WalletInfo.tsx +++ b/components/verification/WalletInfo.tsx @@ -4,10 +4,11 @@ import { truncateAddress } from "../../utils/truncateAddess"; type EthereumAccount = string; type StarknetAccount = { address: string }; +type StellarAccount = string; type WalletInfoProps = { - account: EthereumAccount | StarknetAccount | null; - networkType: "ethereum" | "starknet"; + account: EthereumAccount | StarknetAccount | StellarAccount | null; + networkType: "ethereum" | "starknet" | "stellar"; balance?: string | null; onDisconnect: () => void; verifiedSignature?: boolean; @@ -42,6 +43,8 @@ const WalletInfo = ({ const getAddress = () => { if (networkType === "ethereum") { return account as EthereumAccount; + } else if (networkType === "stellar") { + return account as StellarAccount; } else { return (account as StarknetAccount).address; } @@ -51,13 +54,29 @@ const WalletInfo = ({ return ( - {networkType === "ethereum" ? "Ethereum wallet" : "Starknet wallet"}:{" "} - {isMobile ? truncateAddress(address) : address}{" "} + {networkType === "ethereum" + ? "Ethereum wallet" + : networkType === "stellar" + ? "Stellar wallet" + : "Starknet wallet"} + : {isMobile ? truncateAddress(address) : address}{" "} {!verifiedSignature && disconnect} {networkType === "ethereum" && balance && ( - <> +

Balance: {balance ? `${balance} ETH` : "Loading..."} +
+ )} + {networkType === "stellar" && balance && ( +
+
+ Balance: {balance ? `${balance} XLM` : "Loading..."} +
+ )} + {networkType === "stellar" && balance && ( + <> +
+ Balance: {balance ? `${balance} XLM` : "Loading..."} )}
diff --git a/configs/networks.json b/configs/networks.json index b3f5dfd..6330bbd 100644 --- a/configs/networks.json +++ b/configs/networks.json @@ -5,7 +5,8 @@ "url": "https://starknet.preview.apibara.org", "indexer": true, "description": "The Starknet mainnet", - "verifyPage": "verify" + "verifyPage": "verify", + "chain": "starknet" }, { "label": "Starknet Sepolia", @@ -13,7 +14,8 @@ "url": "coming-soon", "indexer": false, "description": "The Starknet testnet", - "verifyPage": "verify" + "verifyPage": "verify", + "chain": "starknet" }, { "label": "Ethereum Mainnet", @@ -24,16 +26,29 @@ "currency": "ETH", "indexer": false, "description": "The Ethereum mainnet", - "verifyPage": "verify-eth" + "verifyPage": "verify-eth", + "chain": "ethereum" }, { "label": "Stellar Mainnet", "name": "stellar-mainnet", - "url": "https://stellar.org", - "explorerUrl": "https://stellar.expert/explorer/public", + "url": "https://horizon.stellar.org", + "explorerUrl": "https://stellarchain.io", "currency": "XLM", "indexer": false, - "description": "The Stellar network", - "verifyPage": "verify-stellar" + "description": "The Stellar mainnet", + "verifyPage": "verify-stellar", + "chain": "stellar" + }, + { + "label": "Stellar Testnet", + "name": "stellar-testnet", + "url": "https://horizon-testnet.stellar.org", + "explorerUrl": "https://testnet.stellarchain.io", + "currency": "XLM", + "indexer": false, + "description": "The Stellar testnet", + "verifyPage": "verify-stellar", + "chain": "stellar" } ] diff --git a/discord/interactions/addConfigCommand.ts b/discord/interactions/addConfigCommand.ts index 030b899..86d9311 100644 --- a/discord/interactions/addConfigCommand.ts +++ b/discord/interactions/addConfigCommand.ts @@ -145,19 +145,40 @@ const handleBackToModule = async ( ) => { const currentConfig = ongoingConfigurationsCache[interaction.guildId!]; const network = currentConfig?.network; - + const modulesOptions: SelectMenuComponentOptionData[] = []; for (const starkyModuleId in starkyModules) { const starkyModule = starkyModules[starkyModuleId]; // Only show modules that support the selected network - if (network && starkyModule.networks && starkyModule.networks.includes(network)) { + if ( + network && + starkyModule.networks && + starkyModule.networks.includes(network) + ) { + // Validate label length (Discord requires 1-25 characters) + let label = starkyModule.name || starkyModuleId; + if (label.length > 25) { + label = label.substring(0, 22) + "..."; + } + if (label.length === 0) { + label = starkyModuleId.substring(0, 25); + } + modulesOptions.push({ - label: starkyModule.name, + label: label, value: starkyModuleId, }); } } + if (modulesOptions.length === 0) { + await interaction.update({ + content: `❌ No Starky modules are available for the network "${network}". Please go back and select a different network.`, + components: [addBackButton("module")], + }); + return; + } + const selectRow = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() @@ -466,13 +487,31 @@ export const handleNetworkConfigCommand = async ( const starkyModule = starkyModules[starkyModuleId]; // Only show modules that support the selected network if (starkyModule.networks && starkyModule.networks.includes(network)) { + // Validate label length (Discord requires 1-25 characters) + let label = starkyModule.name || starkyModuleId; + if (label.length > 25) { + label = label.substring(0, 22) + "..."; + } + if (label.length === 0) { + label = starkyModuleId.substring(0, 25); + } + modulesOptions.push({ - label: starkyModule.name, + label: label, value: starkyModuleId, }); } } + if (modulesOptions.length === 0) { + await interaction.followUp({ + content: `❌ No Starky modules are available for the network "${network}". Please go back and select a different network.`, + components: [addBackButton(CONFIG_STEPS.MODULE)], + ephemeral: true, + }); + return; + } + const selectRow = new ActionRowBuilder().addComponents( new StringSelectMenuBuilder() diff --git a/hooks/useStellarSignatureVerification.tsx b/hooks/useStellarSignatureVerification.tsx new file mode 100644 index 0000000..8b1e0e5 --- /dev/null +++ b/hooks/useStellarSignatureVerification.tsx @@ -0,0 +1,57 @@ +import { useCallback, useState } from "react"; +import axios from "axios"; +import WatchTowerLogger from "../watchTower"; + +const useStellarSignatureVerification = ( + network: string, + discordServerId: string, + discordMemberId: string, + customLink: string +) => { + const [verifyingSignature, setVerifyingSignature] = useState(false); + const [verifiedSignature, setVerifiedSignature] = useState(false); + const [unverifiedSignature, setUnverifiedSignature] = useState(""); + + const verifySignature = useCallback( + async (signature: string, account: string, message: string) => { + if (!account) return; + setUnverifiedSignature(""); + setVerifyingSignature(true); + try { + await axios.post("/api/verify-stellar", { + account, + signature, + discordServerId, + discordMemberId, + customLink, + network, + message, + }); + setVerifiedSignature(true); + setVerifyingSignature(false); + } catch (e: any) { + WatchTowerLogger.error( + "Stellar signature verification failed with data", + e.response?.data + ); + setVerifyingSignature(false); + setUnverifiedSignature( + `${e.response?.data?.message || "Verification failed"}.${ + e.response?.data?.error || "" + }` || "Stellar signature verification failed" + ); + } + setVerifyingSignature(false); + }, + [network, discordServerId, discordMemberId, customLink] + ); + + return { + verifyingSignature, + verifiedSignature, + unverifiedSignature, + verifySignature, + }; +}; + +export default useStellarSignatureVerification; diff --git a/package-lock.json b/package-lock.json index bb6da49..0d2d1f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@apibara/starknet": "2.0.0-beta.42", "@discordjs/rest": "^2.1.0", "@grpc/grpc-js": "^1.13.3", + "@stellar/freighter-api": "^5.0.0", "@tanstack/react-query": "^5.69.0", "@walletconnect/web3-provider": "^1.8.0", "axios": "^1.7.9", @@ -38,6 +39,7 @@ "sharp": "^0.33.5", "starknet": "^5.24.3", "starknetkit": "^1.1.3", + "stellar-sdk": "^13.3.0", "ts-parse-database-url": "^1.0.3", "typeorm": "^0.3.17", "viem": "^2.23.15", @@ -75,6 +77,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -140,6 +143,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -170,6 +174,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -258,6 +263,7 @@ "version": "7.27.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -311,6 +317,7 @@ "version": "7.28.2", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -838,7 +845,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -851,7 +858,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1062,6 +1069,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", @@ -1168,6 +1176,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "deprecated": "Use @eslint/config-array instead", + "dev": true, "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1182,6 +1191,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, "license": "Apache-2.0", "funding": { "type": "github", @@ -1193,6 +1203,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "deprecated": "Use @eslint/object-schema instead", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/@img/sharp-darwin-arm64": { @@ -2620,6 +2631,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -2633,6 +2645,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2642,6 +2655,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -5070,6 +5084,108 @@ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", "license": "MIT" }, + "node_modules/@stellar/freighter-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@stellar/freighter-api/-/freighter-api-5.0.0.tgz", + "integrity": "sha512-MydzLg+WpSzmws24uUs4mVME2LPN8xhUWkwyGEP0N1Hr519swC6I/W7K6cdVBzghBiVv7f/vvGFNT+0p1a33Vg==", + "license": "Apache-2.0", + "dependencies": { + "buffer": "6.0.3", + "semver": "7.7.1" + } + }, + "node_modules/@stellar/freighter-api/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@stellar/freighter-api/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@stellar/js-xdr": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", + "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", + "license": "Apache-2.0" + }, + "node_modules/@stellar/stellar-base": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-13.1.0.tgz", + "integrity": "sha512-90EArG+eCCEzDGj3OJNoCtwpWDwxjv+rs/RNPhvg4bulpjN/CSRj+Ys/SalRcfM4/WRC5/qAfjzmJBAuquWhkA==", + "license": "Apache-2.0", + "dependencies": { + "@stellar/js-xdr": "^3.1.2", + "base32.js": "^0.1.0", + "bignumber.js": "^9.1.2", + "buffer": "^6.0.3", + "sha.js": "^2.3.6", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "sodium-native": "^4.3.3" + } + }, + "node_modules/@stellar/stellar-base/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/@stellar/stellar-base/node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -5137,28 +5253,28 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/babel__core": { @@ -5320,14 +5436,14 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.0.17", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz", "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -5349,7 +5465,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-WFHp9YUJQ6CKshqoC37iOlHnQSmxNc795UhB26CyBBttrN9svdIrUjl/NjnNmfcwtncN0h/0PPAFWv9ovP8mLA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@types/secp256k1": { @@ -7641,6 +7757,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -7653,6 +7770,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -7662,7 +7780,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -7787,13 +7905,14 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/aria-query": { @@ -7850,6 +7969,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8318,12 +8438,95 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/bare-addon-resolve": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bare-addon-resolve/-/bare-addon-resolve-1.9.4.tgz", + "integrity": "sha512-unn6Vy/Yke6F99vg/7tcrvM2KUvIhTNniaSqDbam4AWkd4NhvDVSrQiRYVlNzUV2P7SPobkCK7JFVxrJk9btCg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-module-resolve": "^1.10.0", + "bare-semver": "^1.0.0" + }, + "peerDependencies": { + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-module-resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/bare-module-resolve/-/bare-module-resolve-1.11.1.tgz", + "integrity": "sha512-DCxeT9i8sTs3vUMA3w321OX/oXtNEu5EjObQOnTmCdNp5RXHBAvAaBDHvAi9ta0q/948QPz+co6SsGi6aQMYRg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-semver": "^1.0.0" + }, + "peerDependencies": { + "bare-url": "*" + }, + "peerDependenciesMeta": { + "bare-url": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", + "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-semver": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bare-semver/-/bare-semver-1.0.1.tgz", + "integrity": "sha512-UtggzHLiTrmFOC/ogQ+Hy7VfoKoIwrP1UFcYtTxoCUdLtsIErT8+SWtOC2DH/snT9h+xDrcBEPcwKei1mzemgg==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-url": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.2.2.tgz", + "integrity": "sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base-x": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", "license": "MIT" }, + "node_modules/base32.js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base32.js/-/base32.js-0.1.0.tgz", + "integrity": "sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -8366,6 +8569,15 @@ "url": "https://opencollective.com/bigjs" } }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -8401,6 +8613,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -8411,6 +8624,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "devOptional": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -8677,6 +8891,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -8792,6 +9007,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -9118,12 +9334,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie-es": { @@ -9231,7 +9449,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-env": { @@ -9288,7 +9506,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -9439,6 +9657,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, "license": "MIT" }, "node_modules/deepmerge": { @@ -9559,7 +9778,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -9585,6 +9804,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" @@ -9658,6 +9878,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" @@ -10119,6 +10340,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10132,6 +10354,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, "license": "MIT", "dependencies": { "@eslint/eslintrc": "^1.3.0", @@ -10544,6 +10767,7 @@ "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", @@ -10560,6 +10784,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, "license": "MIT", "dependencies": { "eslint-visitor-keys": "^2.0.0" @@ -10578,6 +10803,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=10" @@ -10587,6 +10813,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -10599,6 +10826,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", @@ -10629,6 +10857,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -10641,6 +10870,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -10653,6 +10883,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -10662,6 +10893,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -11311,6 +11543,15 @@ "node": ">=0.8.x" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", @@ -11440,6 +11681,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -11456,6 +11698,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -11474,6 +11717,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, "license": "MIT" }, "node_modules/fast-redact": { @@ -11495,6 +11739,7 @@ "version": "1.19.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -11510,10 +11755,20 @@ "bser": "2.1.1" } }, + "node_modules/feaxios": { + "version": "0.0.23", + "resolved": "https://registry.npmjs.org/feaxios/-/feaxios-0.0.23.tgz", + "integrity": "sha512-eghR0A21fvbkcQBgZuMfQhrXxJzC0GNUGC9fXhBge33D+mFDTwl0aJ35zoQQn575BhyjQitRc5N4f+L4cP708g==", + "license": "MIT", + "dependencies": { + "is-retry-allowed": "^3.0.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" @@ -11559,6 +11814,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "devOptional": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -11580,6 +11836,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -11596,6 +11853,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", @@ -11610,6 +11868,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { @@ -11718,6 +11977,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -11785,6 +12045,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -11909,6 +12170,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -11929,6 +12191,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -11951,6 +12214,7 @@ "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.20.2" @@ -11983,6 +12247,7 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", @@ -12021,6 +12286,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true, "license": "MIT" }, "node_modules/h3": { @@ -12080,6 +12346,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -12265,6 +12532,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -12293,6 +12561,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -12329,6 +12598,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -12339,6 +12609,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -12548,6 +12819,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12629,6 +12901,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "devOptional": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -12677,6 +12950,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -12723,6 +12997,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-retry-allowed": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-3.0.0.tgz", + "integrity": "sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -13631,6 +13917,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -13661,6 +13948,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { @@ -13730,6 +14018,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, "license": "MIT" }, "node_modules/json-stringify-safe": { @@ -13742,6 +14031,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -13827,6 +14117,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "license": "MIT", "dependencies": { "json-buffer": "3.0.1" @@ -14011,6 +14302,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -14303,6 +14595,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -14349,6 +14642,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, "license": "MIT" }, "node_modules/lodash.snakecase": { @@ -14509,7 +14803,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { @@ -14584,6 +14878,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -14657,6 +14952,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "devOptional": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -14721,6 +15017,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -14811,6 +15108,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, "license": "MIT" }, "node_modules/next": { @@ -15244,6 +15542,7 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -15333,6 +15632,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -15348,6 +15648,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -15384,6 +15685,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -15430,6 +15732,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15476,6 +15779,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15897,6 +16201,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -16357,6 +16662,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, "funding": [ { "type": "github", @@ -16550,6 +16856,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16614,6 +16921,20 @@ "uuid": "bin/uuid" } }, + "node_modules/require-addon": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/require-addon/-/require-addon-1.1.0.tgz", + "integrity": "sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-addon-resolve": "^1.3.0", + "bare-url": "^2.1.0" + }, + "engines": { + "bare": ">=1.10.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16676,6 +16997,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -16712,6 +17034,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -16730,6 +17053,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -16788,6 +17112,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, "funding": [ { "type": "github", @@ -17296,6 +17621,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17393,6 +17719,16 @@ } } }, + "node_modules/sodium-native": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/sodium-native/-/sodium-native-4.3.3.tgz", + "integrity": "sha512-OnxSlN3uyY8D0EsLHpmm2HOFmKddQVvEMmsakCrXUzSd8kjjbzL413t4ZNF3n0UxSwNgwTyUvkmZHTfuCeiYSw==", + "license": "MIT", + "optional": true, + "dependencies": { + "require-addon": "^1.1.0" + } + }, "node_modules/sonic-boom": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-2.8.0.tgz", @@ -17609,6 +17945,26 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "license": "MIT" }, + "node_modules/stellar-sdk": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/stellar-sdk/-/stellar-sdk-13.3.0.tgz", + "integrity": "sha512-jAA3+U7oAUueldoS4kuEhcym+DigElWq9isPxt7tjMrE7kTJ2vvY29waavUb2FSfQIWwGbuwAJTYddy2BeyJsw==", + "deprecated": "⚠️ This package has moved to @stellar/stellar-sdk! 🚚", + "license": "Apache-2.0", + "dependencies": { + "@stellar/stellar-base": "^13.1.0", + "axios": "^1.8.4", + "bignumber.js": "^9.3.0", + "eventsource": "^2.0.2", + "feaxios": "^0.0.23", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -17928,6 +18284,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17972,6 +18329,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -18020,6 +18378,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, "license": "MIT" }, "node_modules/thread-stream": { @@ -18056,6 +18415,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "devOptional": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -18070,6 +18430,12 @@ "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", "license": "MIT" }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, "node_modules/touch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", @@ -18195,7 +18561,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -18337,6 +18703,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -18359,6 +18726,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -18631,7 +18999,7 @@ "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -18751,6 +19119,12 @@ "punycode": "^2.1.0" } }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, "node_modules/url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", @@ -18815,13 +19189,14 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true, "license": "MIT" }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -19286,6 +19661,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19572,7 +19948,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -19582,6 +19958,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" diff --git a/package.json b/package.json index eaa3c1f..7ab6e11 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@apibara/starknet": "2.0.0-beta.42", "@discordjs/rest": "^2.1.0", "@grpc/grpc-js": "^1.13.3", + "@stellar/freighter-api": "^5.0.0", "@tanstack/react-query": "^5.69.0", "@walletconnect/web3-provider": "^1.8.0", "axios": "^1.7.9", @@ -41,6 +42,7 @@ "sharp": "^0.33.5", "starknet": "^5.24.3", "starknetkit": "^1.1.3", + "stellar-sdk": "^13.3.0", "ts-parse-database-url": "^1.0.3", "typeorm": "^0.3.17", "viem": "^2.23.15", diff --git a/pages/_app.tsx b/pages/_app.tsx index e526162..b458f21 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,37 +1,40 @@ import type { AppProps } from "next/app"; import Head from "next/head"; import { WalletProvider } from "../utils/ethereum/context/WalletConnect"; +import { StellarWalletProvider } from "../utils/stellar/context/StellarWalletConnect"; import "../styles/globals.scss"; function MyApp({ Component, pageProps }: AppProps) { return ( -
- - Starky - - - - - - - -
+ +
+ + Starky + + + + + + + +
+
); } diff --git a/pages/api/verify-stellar.ts b/pages/api/verify-stellar.ts new file mode 100644 index 0000000..d97df58 --- /dev/null +++ b/pages/api/verify-stellar.ts @@ -0,0 +1,83 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { verifySignature } from "../../utils/stellar/verifySignature"; +import { DiscordMemberRepository, setupDb } from "../../db"; +import { refreshDiscordMemberForAllConfigs } from "../../utils/discord/refreshRoles"; +import messageToSign from "../../utils/stellar/message"; + +type Data = { + message: string; + error?: string; +}; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + await setupDb(); + + if (req.method !== "POST") { + return res.status(405).json({ + message: "Method not allowed", + error: "POST method required", + }); + } + + const body = req.body; + if ( + !body.account || + !body.signature || + !body.discordServerId || + !body.discordMemberId || + !body.customLink || + !body.network + ) { + return res.status(400).json({ + message: "Incorrect body", + error: `Missing required fields`, + }); + } + + const discordMember = await DiscordMemberRepository.findOne({ + where: { + discordServerId: body.discordServerId, + discordMemberId: body.discordMemberId, + starknetNetwork: body.network, + }, + relations: ["discordServer"], + }); + + if (!discordMember || discordMember.customLink !== body.customLink) { + return res.status(400).json({ + message: "Incorrect body", + error: `Discord member not found or custom link is incorrect`, + }); + } + + const message = { + ...messageToSign, + domain: { + ...messageToSign.domain, + chainId: body.network, + }, + }; + + const { signatureValid, error } = await verifySignature( + body.account, + JSON.stringify(message.message), + body.signature, + body.network + ); + + if (!signatureValid) { + return res.status(400).json({ message: "Signature is invalid", error }); + } + + // Store the Stellar address in the same field for now + // In production, you might want to add a separate field for Stellar addresses + discordMember.starknetWalletAddress = body.account; + await DiscordMemberRepository.save(discordMember); + + // Refresh roles + await refreshDiscordMemberForAllConfigs(discordMember); + + return res.status(200).json({ message: "Successfully verified" }); +}; + +export default handler; diff --git a/pages/verify-stellar/[discordServerId]/[discordMemberId]/[customLink].tsx b/pages/verify-stellar/[discordServerId]/[discordMemberId]/[customLink].tsx index a191309..91be162 100644 --- a/pages/verify-stellar/[discordServerId]/[discordMemberId]/[customLink].tsx +++ b/pages/verify-stellar/[discordServerId]/[discordMemberId]/[customLink].tsx @@ -1,36 +1,251 @@ -import React from "react"; +import { useCallback, useState, useEffect } from "react"; +import { useRouter } from "next/router"; +import ReactConfetti from "react-confetti"; import Logo from "../../../../components/Logo"; +import SocialLinks from "../../../../components/SocialLinks"; +import { DiscordMemberRepository, setupDb } from "../../../../db"; +import { getDiscordServerInfo } from "../../../../discord/utils"; +import WatchTowerLogger from "../../../../watchTower"; import styles from "../../../../styles/Verify.module.scss"; +import { NetworkName } from "../../../../types/networks"; +import DiscordServerInfo from "../../../../components/verification/DiscordServerInfo"; +import WalletInfo from "../../../../components/verification/WalletInfo"; +import { + StellarWalletProvider, + useStellarWallet, +} from "../../../../utils/stellar/context/StellarWalletConnect"; +import messageToSign from "../../../../utils/stellar/message"; +import useStellarSignatureVerification from "../../../../hooks/useStellarSignatureVerification"; + +type Props = { + discordServerName: string; + discordServerIcon?: string | null; + network: NetworkName; +}; + +const getSignatureErrorMessage = ( + error: string +): { + short: string; + advanced?: string; +} => { + if (error.includes("wallet not connected")) { + return { + short: "Please connect your Freighter wallet first", + advanced: error, + }; + } + return { + short: "Signature verification failed, please try again", + advanced: error, + }; +}; + +const StellarVerifyContent = ({ + discordServerName, + discordServerIcon, + network, +}: Props) => { + const router = useRouter(); + const { discordServerId, discordMemberId, customLink } = router.query; + const { account, connect, disconnect, networkType, balance, signMessage } = + useStellarWallet(); + const [isConnecting, setIsConnecting] = useState(false); + const [windowDimension, setWindowDimension] = useState<{ + width: number; + height: number; + }>({ width: 0, height: 0 }); + + useEffect(() => { + setWindowDimension({ + width: window.innerWidth, + height: window.innerHeight, + }); + }, []); + + const { + verifyingSignature, + verifiedSignature, + unverifiedSignature, + verifySignature, + } = useStellarSignatureVerification( + network, + discordServerId as string, + discordMemberId as string, + customLink as string + ); + + const connectToStellar = useCallback(async () => { + setIsConnecting(true); + try { + await connect(network); + } catch (error: any) { + WatchTowerLogger.error("Failed to connect to Stellar wallet:", error); + } finally { + setIsConnecting(false); + } + }, [connect, network]); + + const sign = useCallback(async () => { + if (!account) return; + try { + const messageCopy = { + ...messageToSign, + domain: { + ...messageToSign.domain, + chainId: network, + }, + }; + + const signature = await signMessage(JSON.stringify(messageCopy.message)); + + // Verify the signature using Stellar-specific verification + await verifySignature( + signature, + account, + JSON.stringify(messageCopy.message) + ); + } catch (e: any) { + WatchTowerLogger.error("Signing error:", e); + } + }, [account, signMessage, verifySignature, network]); + + let stellarWalletDiv = ( +
+ {!account && ( +
+ +
+ )} + {account && !verifyingSignature && !verifiedSignature && ( + + )} + {verifyingSignature && ( + verifying your signature... + )} + {unverifiedSignature && ( +
+ {getSignatureErrorMessage(unverifiedSignature).short}{" "} + + Report on Telegram + +
+ {getSignatureErrorMessage(unverifiedSignature).advanced && ( + + advanced: {getSignatureErrorMessage(unverifiedSignature).advanced} + + )} +
+ )} +
+ ); -// Static Stellar Verification Page -const VerifyStellar: React.FC = () => { return ( -
+
-

Stellar Verification

-

- Welcome to the Stellar verification page! +

+
- This page is for verifying your Discord membership with the Stellar - network. -

-
-

About Stellar

-

- Stellar is an open-source, decentralized protocol for digital currency - to fiat money transfers, enabling cross-border transactions between - any currencies. -

- - Learn more about Stellar - -
-
- Note: Wallet connection and verification are not yet - available for Stellar. This page is for informational purposes only. + + { + disconnect(); + }} + /> + +
+ {verifiedSignature && ( +
+ {typeof window !== "undefined" && ( + + )} + + Identity: verified + +

YOU'RE ALL SET FREN

+ you shall close this tab +
+ )} + {!verifiedSignature && stellarWalletDiv}
+ {process.env.NEXT_PUBLIC_STARKY_OFFICIAL && }
); }; -export default VerifyStellar; +const VerifyStellarPage = (props: Props) => { + return ( + + + + ); +}; + +export async function getServerSideProps({ res, query }: any) { + await setupDb(); + let discordServerName = null; + let discordServerIcon = null; + const { discordServerId, discordMemberId, customLink } = query; + const discordMember = await DiscordMemberRepository.findOne({ + where: { + customLink, + discordServerId, + discordMemberId, + }, + relations: ["discordServer"], + }); + if (!discordMember || discordMember.customLink !== customLink) { + res.setHeader("location", "/"); + res.statusCode = 302; + res.end(); + return { props: {} }; + } + try { + const serverInfo = await getDiscordServerInfo(`${query.discordServerId}`); + discordServerName = serverInfo.name; + discordServerIcon = serverInfo.icon + ? `https://cdn.discordapp.com/icons/${query.discordServerId}/${ + serverInfo.icon + }${serverInfo.icon.startsWith("a_") ? ".gif" : ".png"}` + : null; + } catch (e: any) { + WatchTowerLogger.error(e.message, e); + } + return { + props: { + discordServerName, + discordServerIcon, + network: discordMember.starknetNetwork, // This might need to be updated to support Stellar networks + }, + }; +} + +export default VerifyStellarPage; diff --git a/pages/verify/[discordServerId]/[discordMemberId]/[customLink].tsx b/pages/verify/[discordServerId]/[discordMemberId]/[customLink].tsx index 214a7a8..2f9bc60 100644 --- a/pages/verify/[discordServerId]/[discordMemberId]/[customLink].tsx +++ b/pages/verify/[discordServerId]/[discordMemberId]/[customLink].tsx @@ -10,11 +10,13 @@ import SocialLinks from "../../../../components/SocialLinks"; import chainAliasByNetwork from "../../../../configs/chainAliasByNetwork.json"; import { DiscordMemberRepository, setupDb } from "../../../../db"; import { getDiscordServerInfo } from "../../../../discord/utils"; -import { StarknetNetworkName } from "../../../../types/networks"; +import { StarknetNetworkName, NetworkName } from "../../../../types/networks"; import messageToSign from "../../../../utils/starknet/message"; import WatchTowerLogger from "../../../../watchTower"; import DiscordServerInfo from "../../../../components/verification/DiscordServerInfo"; import WalletInfo from "../../../../components/verification/WalletInfo"; +import DynamicVerificationRouter from "../../../../components/verification/DynamicVerificationRouter"; +import { getChainType } from "../../../../utils/networkDetection"; import styles from "../../../../styles/Verify.module.scss"; @@ -22,6 +24,7 @@ type Props = { discordServerName: string; discordServerIcon?: string | null; starknetNetwork: StarknetNetworkName; + network: NetworkName; }; const getSignatureErrorMessage = ( @@ -60,6 +63,7 @@ const VerifyPage = ({ discordServerName, discordServerIcon, starknetNetwork, + network, }: Props) => { const router = useRouter(); const { discordServerId, discordMemberId, customLink } = router.query; @@ -232,6 +236,19 @@ const VerifyPage = ({ } }, [account, verifySignature, chainId]); + // Check if this is not a Starknet network and route to appropriate page + const chainType = getChainType(network); + if (chainType && chainType !== "starknet") { + return ( + + ); + } + let starknetWalletDiv = (
{!account && ( @@ -409,6 +426,7 @@ export async function getServerSideProps({ res, query }: any) { discordServerName, discordServerIcon, starknetNetwork: discordMember.starknetNetwork, + network: discordMember.starknetNetwork, // For backward compatibility }, }; } diff --git a/public/assets/stellar-icon1.png b/public/assets/stellar-icon1.png new file mode 100644 index 0000000..ab49d6e Binary files /dev/null and b/public/assets/stellar-icon1.png differ diff --git a/public/assets/stellar-xlm-icon.png b/public/assets/stellar-xlm-icon.png new file mode 100644 index 0000000..6e79a21 Binary files /dev/null and b/public/assets/stellar-xlm-icon.png differ diff --git a/types/freighter.d.ts b/types/freighter.d.ts new file mode 100644 index 0000000..5d914cf --- /dev/null +++ b/types/freighter.d.ts @@ -0,0 +1,12 @@ +declare global { + interface Window { + freighter?: { + isConnected: () => Promise; + getPublicKey: () => Promise; + signTransaction: (xdr: string, network?: string) => Promise; + getNetwork: () => Promise; + }; + } +} + +export {}; diff --git a/types/networks.ts b/types/networks.ts index f3e2a33..33a1454 100644 --- a/types/networks.ts +++ b/types/networks.ts @@ -1,6 +1,7 @@ export type StarknetNetworkName = "mainnet" | "goerli" | "sepolia"; +export type StellarNetworkName = "stellar-mainnet" | "stellar-testnet"; export type NetworkName = | StarknetNetworkName | "ethereum-mainnet" - | "stellar-mainnet" - | "stellar-testnet"; + | StellarNetworkName; +export type ChainType = "starknet" | "ethereum" | "stellar"; diff --git a/utils/ethereum/context/WalletConnect.tsx b/utils/ethereum/context/WalletConnect.tsx index 07ba6f2..4da2d5b 100644 --- a/utils/ethereum/context/WalletConnect.tsx +++ b/utils/ethereum/context/WalletConnect.tsx @@ -9,6 +9,7 @@ import { disconnect as starknetDisconnect, } from "starknetkit"; import { INFURA_PROJECT_ID, ETHEREUM_ENABLED } from "../ethereumEnv"; +import { ChainType } from "../../../types/networks"; type WalletContextType = { connect: (networkName: string) => Promise; @@ -16,7 +17,7 @@ type WalletContextType = { account: string | null; provider: ethers.BrowserProvider | null; chainId: number | string | null; - networkType: "ethereum" | "starknet" | null; + networkType: ChainType | null; signMessage: (message: string) => Promise; balance: string | null; }; @@ -27,9 +28,7 @@ export function WalletProvider({ children }: { children: React.ReactNode }) { const [account, setAccount] = useState(null); const [provider, setProvider] = useState(null); const [chainId, setChainId] = useState(null); - const [networkType, setNetworkType] = useState< - "ethereum" | "starknet" | null - >(null); + const [networkType, setNetworkType] = useState(null); const [wcProvider, setWcProvider] = useState(null); const [balance, setBalance] = useState(null); diff --git a/utils/networkDetection.ts b/utils/networkDetection.ts new file mode 100644 index 0000000..86cf864 --- /dev/null +++ b/utils/networkDetection.ts @@ -0,0 +1,61 @@ +import networks from "../configs/networks.json"; +import { NetworkName, ChainType } from "../types/networks"; + +export interface NetworkConfig { + label: string; + name: string; + url: string; + chain: ChainType; + verifyPage: string; + chainId?: number; + explorerUrl?: string; + currency?: string; + indexer: boolean; + description: string; +} + +export const getNetworkConfig = ( + networkName: NetworkName +): NetworkConfig | null => { + return ( + (networks.find( + (network) => network.name === networkName + ) as NetworkConfig) || null + ); +}; + +export const getChainType = (networkName: NetworkName): ChainType | null => { + const network = getNetworkConfig(networkName); + return network?.chain || null; +}; + +export const getVerifyPageForNetwork = (networkName: NetworkName): string => { + const network = getNetworkConfig(networkName); + if (!network) return "verify"; // Default fallback + + // Return the verification page based on chain type + switch (network.chain) { + case "starknet": + return "verify"; + case "ethereum": + return "verify-eth"; + case "stellar": + return "verify-stellar"; + default: + return "verify"; + } +}; + +export const getAllNetworksByChain = ( + chainType: ChainType +): NetworkConfig[] => { + return networks.filter( + (network) => (network as NetworkConfig).chain === chainType + ) as NetworkConfig[]; +}; + +export const getNetworksByChain = { + starknet: () => getAllNetworksByChain("starknet"), + ethereum: () => getAllNetworksByChain("ethereum"), + stellar: () => getAllNetworksByChain("stellar"), +}; diff --git a/utils/stellar/context/StellarWalletConnect.tsx b/utils/stellar/context/StellarWalletConnect.tsx new file mode 100644 index 0000000..8d1cbed --- /dev/null +++ b/utils/stellar/context/StellarWalletConnect.tsx @@ -0,0 +1,183 @@ +"use client"; + +import { createContext, useContext, useState } from "react"; +import { + isConnected, + getAddress, + requestAccess, + signTransaction, +} from "@stellar/freighter-api"; +import * as StellarSdk from "stellar-sdk"; +import networks from "../../../configs/networks.json"; +import { + getStellarHorizonUrl, + getStellarNetworkPassphrase, +} from "../stellarEnv"; +import WatchTowerLogger from "../../../watchTower"; + +type StellarWalletContextType = { + connect: (networkName: string) => Promise; + disconnect: () => void; + account: string | null; + networkType: "stellar-mainnet" | "stellar-testnet" | null; + signMessage: (message: string) => Promise; + balance: string | null; + server: StellarSdk.Horizon.Server | null; +}; + +const StellarWalletContext = createContext( + {} as StellarWalletContextType +); + +export function StellarWalletProvider({ + children, +}: { + children: React.ReactNode; +}) { + const [account, setAccount] = useState(null); + const [networkType, setNetworkType] = useState< + "stellar-mainnet" | "stellar-testnet" | null + >(null); + const [balance, setBalance] = useState(null); + const [server, setServer] = useState(null); + + const connect = async (networkName: string) => { + console.log("Attempting to connect to Stellar network:", networkName); + + const network = networks.find((n) => n.name === networkName); + if (!network || network.chain !== "stellar") { + console.error("Invalid network:", network); + throw new Error("Invalid Stellar network"); + } + + try { + console.log("Checking if Freighter is available..."); + + // Request access to Freighter - this handles both checking if it's installed and getting permission + console.log("Requesting Freighter access..."); + const accessResult = await requestAccess(); + console.log("Access result:", accessResult); + + if (accessResult.error) { + throw new Error(`Freighter error: ${accessResult.error}`); + } + + // Get the address (public key) + console.log("Getting address..."); + const addressResult = await getAddress(); + console.log("Address result:", addressResult); + + if (addressResult.error) { + throw new Error(`Failed to get address: ${addressResult.error}`); + } + + const publicKey = addressResult.address; + + if (!publicKey) { + throw new Error("Failed to get public key from Freighter wallet"); + } + + // Initialize Stellar server + const horizonUrl = getStellarHorizonUrl( + networkName as "stellar-mainnet" | "stellar-testnet" + ); + const stellarServer = new StellarSdk.Horizon.Server(horizonUrl); + + try { + // Get account balance + const accountInfo = await stellarServer.loadAccount(publicKey); + const nativeBalance = accountInfo.balances.find( + (balance) => balance.asset_type === "native" + ); + const xlmBalance = nativeBalance + ? parseFloat(nativeBalance.balance).toFixed(7) + : "0"; + + setBalance(xlmBalance); + } catch (error) { + WatchTowerLogger.warn("Could not load account balance:", { + error: error as Error, + }); + setBalance("0"); + } + + setAccount(publicKey); + setNetworkType(networkName as "stellar-mainnet" | "stellar-testnet"); + setServer(stellarServer); + } catch (error) { + console.error("Stellar connection error:", error); + throw error; + } + }; + + const disconnect = () => { + setAccount(null); + setNetworkType(null); + setBalance(null); + setServer(null); + }; + + const signMessage = async (message: string) => { + if (!account || !server) { + throw new Error("Wallet not connected"); + } + + try { + console.log("Signing message with Stellar account:", account); + + // Create a transaction with the message as memo for signing + const sourceAccount = await server.loadAccount(account); + + const transaction = new StellarSdk.TransactionBuilder(sourceAccount, { + fee: StellarSdk.BASE_FEE, + networkPassphrase: getStellarNetworkPassphrase(networkType!), + }) + .addMemo(StellarSdk.Memo.text(message.substring(0, 28))) // Stellar memo limit is 28 chars + .addOperation( + StellarSdk.Operation.manageData({ + name: "verify", + value: message.substring(0, 64), // Store part of message in account data + }) + ) + .setTimeout(0) + .build(); + + const xdr = transaction.toXDR(); + console.log("Transaction XDR:", xdr); + + // Sign the transaction using Freighter + const signedTxResult = await signTransaction(xdr, { + networkPassphrase: getStellarNetworkPassphrase(networkType!), + address: account, + }); + + if (signedTxResult.error) { + throw new Error(`Signing failed: ${signedTxResult.error}`); + } + + console.log("Signed transaction XDR:", signedTxResult.signedTxXdr); + return signedTxResult.signedTxXdr; + } catch (error) { + console.error("Message signing error:", error); + throw error; + } + }; + + return ( + + {children} + + ); +} + +export const useStellarWallet = () => useContext(StellarWalletContext); diff --git a/utils/stellar/message.ts b/utils/stellar/message.ts new file mode 100644 index 0000000..dba1319 --- /dev/null +++ b/utils/stellar/message.ts @@ -0,0 +1,30 @@ +const messageToSign = { + types: { + EIP712Domain: [ + { name: "name", type: "string" }, + { name: "version", type: "string" }, + { name: "chainId", type: "string" }, + { name: "verifyingContract", type: "string" }, + ], + Message: [ + { name: "contents", type: "string" }, + { name: "from", type: "string" }, + { name: "to", type: "string" }, + ], + }, + primaryType: "Message", + domain: { + name: "Starky", + version: "1", + chainId: "stellar", + verifyingContract: "starky.wtf", + }, + message: { + contents: + "Sign this message to verify that you are the owner of this account. This will not trigger a blockchain transaction or cost any gas fees.", + from: "starky.wtf", + to: "Discord server", + }, +}; + +export default messageToSign; diff --git a/utils/stellar/stellarEnv.ts b/utils/stellar/stellarEnv.ts new file mode 100644 index 0000000..a432109 --- /dev/null +++ b/utils/stellar/stellarEnv.ts @@ -0,0 +1,25 @@ +export const getStellarHorizonUrl = ( + network: "stellar-mainnet" | "stellar-testnet" +) => { + switch (network) { + case "stellar-mainnet": + return "https://horizon.stellar.org"; + case "stellar-testnet": + return "https://horizon-testnet.stellar.org"; + default: + return "https://horizon-testnet.stellar.org"; + } +}; + +export const getStellarNetworkPassphrase = ( + network: "stellar-mainnet" | "stellar-testnet" +) => { + switch (network) { + case "stellar-mainnet": + return "Public Global Stellar Network ; September 2015"; + case "stellar-testnet": + return "Test SDF Network ; September 2015"; + default: + return "Test SDF Network ; September 2015"; + } +}; diff --git a/utils/stellar/verifySignature.ts b/utils/stellar/verifySignature.ts new file mode 100644 index 0000000..8099017 --- /dev/null +++ b/utils/stellar/verifySignature.ts @@ -0,0 +1,124 @@ +import * as StellarSdk from "stellar-sdk"; +import { + getStellarHorizonUrl, + getStellarNetworkPassphrase, +} from "./stellarEnv"; + +export const verifySignature = async ( + publicKey: string, + message: string, + signedTxXdr: string, + network: string +): Promise<{ signatureValid: boolean; error?: string }> => { + try { + console.log("Verifying Stellar signature for:", publicKey); + console.log("Message:", message); + console.log("Signed XDR:", signedTxXdr); + + // Basic validation - check if public key is valid Stellar address + if (!publicKey || publicKey.length !== 56 || !publicKey.startsWith("G")) { + return { + signatureValid: false, + error: "Invalid Stellar public key format", + }; + } + + // Check if signature (XDR) is provided + if (!signedTxXdr || signedTxXdr.length === 0) { + return { + signatureValid: false, + error: "No signed transaction provided", + }; + } + + // Check if the account exists on the Stellar network + const horizonUrl = getStellarHorizonUrl( + network as "stellar-mainnet" | "stellar-testnet" + ); + const server = new StellarSdk.Horizon.Server(horizonUrl); + + try { + await server.loadAccount(publicKey); + } catch (error) { + return { + signatureValid: false, + error: "Stellar account not found on network", + }; + } + + try { + // Parse the signed transaction XDR + const networkPassphrase = getStellarNetworkPassphrase( + network as "stellar-mainnet" | "stellar-testnet" + ); + const transaction = StellarSdk.TransactionBuilder.fromXDR( + signedTxXdr, + networkPassphrase + ); + + console.log("Parsed transaction:", transaction); + + // Verify the transaction is signed by the correct account + let sourceAccount: string; + if ("source" in transaction) { + sourceAccount = transaction.source; + } else { + // For FeeBumpTransaction, use the inner transaction's source + sourceAccount = transaction.innerTransaction.source; + } + + if (sourceAccount !== publicKey) { + return { + signatureValid: false, + error: "Transaction not signed by the expected account", + }; + } + + // Check if the transaction has signatures + if (transaction.signatures.length === 0) { + return { + signatureValid: false, + error: "No signatures found in transaction", + }; + } + + // Verify signature using Stellar SDK + const keypair = StellarSdk.Keypair.fromPublicKey(publicKey); + const txHash = transaction.hash(); + + // Check if any signature is valid for this keypair + let validSignature = false; + for (const signature of transaction.signatures) { + try { + const isValid = keypair.verify(txHash, signature.signature()); + if (isValid) { + validSignature = true; + break; + } + } catch (error) { + console.log("Signature verification failed:", error); + } + } + + if (validSignature) { + return { signatureValid: true }; + } else { + return { + signatureValid: false, + error: "Invalid signature", + }; + } + } catch (error: any) { + console.error("XDR parsing error:", error); + return { + signatureValid: false, + error: `Failed to parse signed transaction: ${error.message}`, + }; + } + } catch (error: any) { + return { + signatureValid: false, + error: `Verification failed: ${error.message}`, + }; + } +};