diff --git a/next.config.js b/next.config.js index cd8a7f7ac8..a2211e960d 100644 --- a/next.config.js +++ b/next.config.js @@ -21,10 +21,11 @@ const INFURA_IPFS_URLS = [ ] const SCRIPT_SRC = [ - 'https://*.juicebox.money', - 'https://static.hotjar.com', - 'https://script.hotjar.com', - 'https://cdn.usefathom.com', + 'https://juicebox.money', // Trusted host + 'https://*.juicebox.money', // Trusted subdomains + 'https://static.hotjar.com', // Hotjar analytics + 'https://script.hotjar.com', // Hotjar analytics + 'https://cdn.usefathom.com', // Fathom analytics // Not working as unsafe-eval is required for metamask // `'sha256-kZ9E6/oLrki51Yx03/BugStfFrPlm8hjaFbaokympXo='`, // hotjar `'unsafe-eval'`, // hotjar @@ -70,7 +71,9 @@ const CONNECT_SRC = [ 'https://*.supabase.co', 'https://api.ensideas.com', 'https://cloudflare-eth.com', - 'https://rpc.sepolia.org/' + 'https://rpc.sepolia.org/', + 'https://sepolia-rollup.arbitrum.io/rpc', + 'https://sepolia.optimism.io', ] const FRAME_ANCESTORS = [ @@ -125,6 +128,20 @@ const SECURITY_HEADERS = [ const nextConfig = removeImports({ experimental: { esmExternals: true, + optimizePackageImports: [ + 'juice-sdk-core', + 'juice-sdk-react', + 'ethers', + 'ethers/lib/utils', + '@ethersproject/constants', + '@ethersproject/bignumber', + '@ethersproject', + 'viem', + 'viem/chains', + 'wagmi', + '@wagmi/core', + '@heroicons/react' + ], }, staticPageGenerationTimeout: 90, webpack: config => { @@ -178,7 +195,34 @@ const nextConfig = removeImports({ ...SECURITY_HEADERS, ], }, - ]; + { + source: '/(.*)', + headers: [ + { + key: 'x-vercel-country', + value: '', // Allow this header to pass through + }, + ], + }, + { + source: '/(.*)', + headers: [ + { + key: 'X-Vercel-IP-Country-Region', + value: '', // Allow this header to pass through + }, + ], + }, + { + source: '/(.*)', + headers: [ + { + key: 'X-Vercel-IP-City', + value: '', // Allow this header to pass through + }, + ], + }, + ] }, images: { remotePatterns: [ diff --git a/package.json b/package.json index a3b93e6e65..a39af736a8 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,6 @@ "@uniswap/sdk": "3.0.3", "@uniswap/sdk-core": "3.0.1", "@uniswap/v3-sdk": "3.8.2", - "@walletconnect/web3-provider": "^1.8.0", "@web3-onboard/coinbase": "^2.4.1", "@web3-onboard/core": "^2.22.2", "@web3-onboard/gnosis": "^2.3.2", @@ -107,8 +106,8 @@ "graphql": "^16.8.1", "he": "^1.2.0", "jsonwebtoken": "^9.0.0", - "juice-sdk-core": "^11.0.0-alpha", - "juice-sdk-react": "^11.0.0-alpha", + "juice-sdk-core": "^11.5.0-alpha", + "juice-sdk-react": "^11.6.0-alpha", "juicebox-metadata-helper": "0.1.7", "less": "4.1.2", "lodash": "^4.17.21", diff --git a/scripts/abi-codegen.js b/scripts/abi-codegen.js new file mode 100644 index 0000000000..b407933f31 --- /dev/null +++ b/scripts/abi-codegen.js @@ -0,0 +1,379 @@ +/** + * A script to generate a selection of typescript files that contain the ABI and address of JB contracts. + * + * Behaviour differs slightly, depending on what contract we're importing. + * + * The idea is: instead asyncronously importing the JSON files at runtime, we bundle them into a TS file, and import that instead. + * + * There a multiple TS files generated. Again, behaviour differs slightly depending on the contract. + * + * This way: + * - we reduce the number of individual files that Next/webpack builds + * - we save on some total bundle size (the total TS files < the total JSON files) + * - src code is simpler to read and understand + * + * Code ain't great; heads up! + */ + +const fs = require('fs') + +const core = [ + 'JBDirectory', + 'JBProjects', + 'JBFundingCycleStore', + 'JBFundAccessConstraintsStore', + 'JBOperatorStore', + 'JBSplitsStore', + 'JBTokenStore', + 'JBSingleTokenPaymentTerminalStore', + 'JBSingleTokenPaymentTerminalStore3_1', + 'JBSingleTokenPaymentTerminalStore3_1_1', + 'JBETHERC20ProjectPayerDeployer', + 'JBController', + 'JBController3_1', + 'JBETHPaymentTerminal', + 'JBETHPaymentTerminal3_1', + 'JBETHPaymentTerminal3_1_1', + 'JBETHPaymentTerminal3_1_2', +] + +const coreV1 = [ + 'FundingCycles', + 'TerminalV1', + 'TerminalV1_1', + 'TerminalDirectory', + 'ModStore', + 'OperatorStore', + 'Projects', + 'TicketBooth', +] + +const juice721DelegateInterfaces = [ + 'JB721TieredGovernance', + 'IJBTiered721DelegateStore', + 'IJBTiered721Delegate', + 'IJBTiered721DelegateProjectDeployer', +] + +const V2_ADDRESS_OVERRIDES = { + JBETHERC20ProjectPayerDeployer: { + /** + * This deployment of the JBETHERC20ProjectPayerDeployer has slightly different + * internals to the one in the contracts-v2-latest package. + * + * It sets the beneficiary to tx.origin, instead of msg.sender. + * + * It was only deployed on mainnet, so we'll override it for mainnet only. + */ + addresses: { + mainnet: '0x325Ba0eFC2c750e0317561e79cFa6911e29B24CC', + }, + }, + JBOperatorStore: { + addresses: { + sepolia: '0x8f63c744c0280ef4b32af1f821c65e0fd4150ab3', + }, + }, + JBProjects: { + addresses: { + sepolia: '0x43CB8FCe4F0d61579044342A5d5A027aB7aE4D63', + }, + }, + JBDirectory: { + addresses: { + sepolia: '0x3B3Bd16cc76cd53218e00b600bFCa27aA5057794', + }, + }, + JBFundingCycleStore: { + addresses: { + sepolia: '0xCb881e166d527010B9eF11159b487f907040D7C4', + }, + }, + JBTokenStore: { + addresses: { + sepolia: '0x25fdda0eBD9e979b8c1657780045Cf87392a14E4', + }, + }, + JBSplitsStore: { + addresses: { + sepolia: '0xEdE89dB755855aF041b5f100B39db9324b5227Ac', + }, + }, + JBController: { + addresses: { + sepolia: '0x0c750ac5805AC3357b72554e3AE70840BBD09A98', + }, + }, + JBSingleTokenPaymentTerminalStore: { + addresses: { + sepolia: '0x981c8ECD009E3E84eE1fF99266BF1461a12e5c68', + }, + }, + JBETHPaymentTerminal: { + addresses: { + sepolia: '0x55FF1D8093166c1fF9664efd613D8C543b95feFc', + }, + }, +} + +const importV3Contract = (contract, network) => { + try { + const jsonData = require(`@jbx-protocol/juice-contracts-v3/deployments/${network}/${contract}.json`) + return { + address: jsonData.address, + abi: jsonData.abi, + } + } catch (e) { + return null + } +} + +const importV2Contract = (contract, network) => { + try { + // load the mainnet abi for v2. Sepolia addresses supplied in V2_ADDRESS_OVERRIDES + const jsonData = require(`@jbx-protocol/contracts-v2-latest/deployments/mainnet/${contract}.json`) + return { + address: + V2_ADDRESS_OVERRIDES[contract]?.addresses?.[network] ?? + jsonData.address, + abi: jsonData.abi, + } + } catch (e) { + return null + } +} + +const importV1Contract = (contract, network) => { + try { + const jsonData = require(`@jbx-protocol/contracts-v1/deployments/${network}/${contract}.json`) + return { + address: jsonData.address, + abi: jsonData.abi, + } + } catch (e) { + return null + } +} + +const importJuice721DelegateInterface = (interfaceName, version) => { + try { + const jsonData = require(`@jbx-protocol/juice-721-delegate-v${version}/out/${interfaceName}.sol/${interfaceName}.json`) + return { + abi: jsonData.abi, + } + } catch (e) { + return null + } +} + +const importJuice721DelegateDeployment = (version, chainId) => { + try { + const jsonData = require(`@jbx-protocol/juice-721-delegate-v${version}/broadcast/Deploy.s.sol/${chainId}/run-latest.json`) + return { + transactions: jsonData.transactions.map(t => { + return { + contractName: t.contractName, + contractAddress: t.contractAddress, + } + }), + } + } catch (e) { + return null + } +} + +const codegenJuice721DelegateInterfaces = version => { + return juice721DelegateInterfaces + .map(contract => ({ + name: contract, + contract: importJuice721DelegateInterface(contract, version), + })) + .map(({ name, contract }) => { + if (!contract) { + return null + } + + return `export const ${name} = { + address: undefined, + abi: ${JSON.stringify(contract.abi)} + } as const` + }) + .filter(Boolean) + .join('\n') +} + + +const codegenJuice721DelegateDeployment = (version) => { + // mainnnet, sepolia + return [1, 11155111] + .map(chainId => ({chainId, deployment: importJuice721DelegateDeployment(version, chainId)})) + .map((data) => { + if (!data?.deployment) { + return null + } + + return `export const chain${data.chainId} = ${JSON.stringify(data.deployment)} as const` + }) + .filter(Boolean) + .join('\n') +} + + +const codegenV1 = network => { + return coreV1 + .map(contract => ({ + name: contract, + contract: importV1Contract(contract, network), + })) + .map(({ name, contract }) => { + if (!contract) { + return null + } + + return `export const ${name} = { + address: '${contract.address}', + abi: ${JSON.stringify(contract.abi)} + } as const` + }) + .filter(Boolean) + .join('\n') +} + +const codegenV2 = network => { + return core + .map(contract => ({ + name: contract, + contract: importV2Contract(contract, network), + })) + .map(({ name, contract }) => { + if (!contract) { + return null + } + + return `export const ${name} = { + address: '${contract.address}', + abi: ${JSON.stringify(contract.abi)} + } as const` + }) + .filter(Boolean) + .join('\n') +} + +const codegenV3 = network => { + return core + .map(contract => ({ + name: contract, + contract: importV3Contract(contract, network), + })) + .map(({ name, contract }) => { + if (!contract) { + return null + } + + return `export const ${name} = { + address: '${contract.address}', + abi: ${JSON.stringify(contract.abi)} + } as const` + }) + .filter(Boolean) + .join('\n') +} + +// eslint-disable-next-line no-console +console.log('🧃 Generating Typescript files for contract deployment JSONs...') + +const mainnetV1 = codegenV1('mainnet') + +const mainnetV2 = codegenV2('mainnet') +const sepoliaV2 = codegenV2('sepolia') + +const mainnetV3 = codegenV3('mainnet') +const sepoliaV3 = codegenV3('sepolia') + +const juice721DelegateInterfacesV3 = codegenJuice721DelegateInterfaces('3') +const juice721DelegateInterfacesV3_1 = codegenJuice721DelegateInterfaces('3-1') +const juice721DelegateInterfacesV3_2 = codegenJuice721DelegateInterfaces('3-2') +const juice721DelegateInterfacesV3_3 = codegenJuice721DelegateInterfaces('3-3') +const juice721DelegateInterfacesV3_4 = codegenJuice721DelegateInterfaces('3-4') + +const juice721DelegateDeploymentV3 = codegenJuice721DelegateDeployment('3') +const juice721DelegateDeploymentV3_1 = codegenJuice721DelegateDeployment('3-1') +const juice721DelegateDeploymentV3_2 = codegenJuice721DelegateDeployment('3-2') +const juice721DelegateDeploymentV3_3 = codegenJuice721DelegateDeployment('3-3') +const juice721DelegateDeploymentV3_4 = codegenJuice721DelegateDeployment('3-4') + +fs.writeFileSync( + 'src/packages/v1/contexts/User/juice-contracts-v1-mainnet.ts', + mainnetV1, +) + +fs.writeFileSync( + 'src/packages/v2v3/utils/contractLoaders/contracts/juice-contracts-v2-mainnet.ts', + mainnetV2, +) +fs.writeFileSync( + 'src/packages/v2v3/utils/contractLoaders/contracts/juice-contracts-v2-sepolia.ts', + sepoliaV2, +) + +fs.writeFileSync( + 'src/packages/v2v3/utils/contractLoaders/contracts/juice-contracts-v3-mainnet.ts', + mainnetV3, +) +fs.writeFileSync( + 'src/packages/v2v3/utils/contractLoaders/contracts/juice-contracts-v3-sepolia.ts', + sepoliaV3, +) + +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3.ts', + juice721DelegateInterfacesV3, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3-1.ts', + juice721DelegateInterfacesV3_1, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3-2.ts', + juice721DelegateInterfacesV3_2, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3-3.ts', + juice721DelegateInterfacesV3_3, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3-4.ts', + juice721DelegateInterfacesV3_4, +) + +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/interfaceAbis/juice-721-delegate-interfaces-v3.ts', + juice721DelegateInterfacesV3, +) + +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/deployments/juice-721-delegate-deployment-v3.ts', + juice721DelegateDeploymentV3, +) + +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/deployments/juice-721-delegate-deployment-v3-1.ts', + juice721DelegateDeploymentV3_1, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/deployments/juice-721-delegate-deployment-v3-2.ts', + juice721DelegateDeploymentV3_2, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/deployments/juice-721-delegate-deployment-v3-3.ts', + juice721DelegateDeploymentV3_3, +) +fs.writeFileSync( + 'src/packages/v2v3/hooks/JB721Delegate/contracts/deployments/juice-721-delegate-deployment-v3-4.ts', + juice721DelegateDeploymentV3_4, +) + + + +// eslint-disable-next-line no-console +console.log('🧃 Done') diff --git a/src/components/Home/TopSection/TopSection.tsx b/src/components/Home/TopSection/TopSection.tsx index 0d8f8b4d2f..84bb5d6778 100644 --- a/src/components/Home/TopSection/TopSection.tsx +++ b/src/components/Home/TopSection/TopSection.tsx @@ -22,6 +22,7 @@ import { getSubgraphIdForProject } from 'utils/graph' const HEADER_TAGS: ProjectTagName[] = [ 'dao', + 'desci', 'nfts', 'fundraising', 'art', diff --git a/src/components/NftRewards/AddNftCollectionForm/AddNftCollectionForm.tsx b/src/components/NftRewards/AddNftCollectionForm/AddNftCollectionForm.tsx index 4fe7c335db..fdd41bf0d0 100644 --- a/src/components/NftRewards/AddNftCollectionForm/AddNftCollectionForm.tsx +++ b/src/components/NftRewards/AddNftCollectionForm/AddNftCollectionForm.tsx @@ -4,10 +4,12 @@ import { Form, FormInstance } from 'antd' import ExternalLink from 'components/ExternalLink' import TooltipLabel from 'components/TooltipLabel' import { JuiceInput } from 'components/inputs/JuiceTextInput' +import { NftPostPayModalConfig } from 'models/nftPostPayModal' import { NftRewardTier } from 'models/nftRewards' import { CreateCollapse } from 'packages/v2v3/components/Create/components/CreateCollapse/CreateCollapse' import { OptionalHeader } from 'packages/v2v3/components/Create/components/OptionalHeader' import { useLockPageRulesWrapper } from 'packages/v2v3/components/Create/hooks/useLockPageRulesWrapper' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { inputMustExistRule } from 'utils/antdRules' import { RewardsList } from '../RewardsList/RewardsList' import { NftAdvancedFormItems } from './NftAdvancedFormItems' @@ -28,11 +30,15 @@ export type NftRewardsFormProps = Partial<{ export const AddNftCollectionForm = ({ form, initialValues, + postPayModalData, + nftRewardsData, okButton, onFinish, }: { form: FormInstance initialValues?: NftRewardsFormProps + postPayModalData: NftPostPayModalConfig | undefined + nftRewardsData: NftRewardsData okButton: React.ReactNode onFinish?: VoidFunction }) => { @@ -53,7 +59,7 @@ export const AddNftCollectionForm = ({ >
- + {hasNfts && ( @@ -122,7 +128,9 @@ export const AddNftCollectionForm = ({ header={} hideDivider > - + state.editingV2Project.nftRewards.postPayModal, - ) return ( <>
diff --git a/src/components/NftRewards/NftPostPayModal.tsx b/src/components/NftRewards/NftPostPayModal.tsx index 314bd8a0fc..6f8ec97502 100644 --- a/src/components/NftRewards/NftPostPayModal.tsx +++ b/src/components/NftRewards/NftPostPayModal.tsx @@ -1,6 +1,6 @@ import { t } from '@lingui/macro' import Modal from 'antd/lib/modal/Modal' -import { NftPostPayModalConfig } from 'models/nftRewards' +import { NftPostPayModalConfig } from 'models/nftPostPayModal' import { withHttps } from 'utils/externalLink' export function NftPostPayModal({ diff --git a/src/components/NftRewards/RewardsList/AddEditRewardModal.tsx b/src/components/NftRewards/RewardsList/AddEditRewardModal.tsx index 48ac10911f..eb45425d6c 100644 --- a/src/components/NftRewards/RewardsList/AddEditRewardModal.tsx +++ b/src/components/NftRewards/RewardsList/AddEditRewardModal.tsx @@ -20,7 +20,7 @@ import { DEFAULT_NFT_MAX_SUPPLY } from 'packages/v2v3/constants/nftRewards' import { V2V3_CURRENCY_USD } from 'packages/v2v3/utils/currency' import { UploadRequestOption } from 'rc-upload/lib/interface' import { useCallback, useEffect, useLayoutEffect, useState } from 'react' -import { useAppSelector } from 'redux/hooks/useAppSelector' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { inputIsIntegerRule, inputIsValidUrlRule, @@ -57,6 +57,7 @@ export const NEW_NFT_ID_LOWER_LIMIT = 1000000 export const AddEditRewardModal = ({ className, editingData, + nftRewards, open, onOk, onCancel, @@ -64,6 +65,7 @@ export const AddEditRewardModal = ({ }: { className?: string editingData?: NftRewardTier | undefined + nftRewards: NftRewardsData open?: boolean onOk: (reward: NftRewardTier) => void onCancel: VoidFunction @@ -74,7 +76,6 @@ export const AddEditRewardModal = ({ const [isReservingNfts, setIsReservingNfts] = useState(false) const [advancedOptionsOpen, setAdvancedOptionsOpen] = useState(false) - const { nftRewards } = useAppSelector(state => state.editingV2Project) const nftCurrency = nftRewards?.pricing.currency useLayoutEffect(() => { diff --git a/src/components/NftRewards/RewardsList/RewardItem.tsx b/src/components/NftRewards/RewardsList/RewardItem.tsx index 02e75f0b1b..0e5a64be6c 100644 --- a/src/components/NftRewards/RewardsList/RewardItem.tsx +++ b/src/components/NftRewards/RewardsList/RewardItem.tsx @@ -8,7 +8,7 @@ import round from 'lodash/round' import { NftRewardTier } from 'models/nftRewards' import { V2V3_CURRENCY_USD } from 'packages/v2v3/utils/currency' import { ReactNode } from 'react' -import { useAppSelector } from 'redux/hooks/useAppSelector' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { isZeroAddress } from 'utils/address' import { hasLimitedSupply } from 'utils/nftRewards' import { prettyUrl } from 'utils/url' @@ -28,10 +28,12 @@ function numberUpToPrecisionFormat( export const RewardItem = ({ reward, + nftRewards, onEditClicked, onDeleteClicked, }: { reward: NftRewardTier + nftRewards: NftRewardsData onEditClicked?: () => void onDeleteClicked?: () => void }) => { @@ -47,7 +49,6 @@ export const RewardItem = ({ fileUrl, } = reward - const { nftRewards } = useAppSelector(state => state.editingV2Project) const nftCurrency = nftRewards?.pricing.currency const hasBeneficiary = Boolean(beneficiary) && !isZeroAddress(beneficiary) diff --git a/src/components/NftRewards/RewardsList/RewardsList.tsx b/src/components/NftRewards/RewardsList/RewardsList.tsx index 3054187d74..305bb0f493 100644 --- a/src/components/NftRewards/RewardsList/RewardsList.tsx +++ b/src/components/NftRewards/RewardsList/RewardsList.tsx @@ -7,6 +7,7 @@ import { FormItemInput } from 'models/formItemInput' import { NftRewardTier } from 'models/nftRewards' import { MAX_NFT_REWARD_TIERS } from 'packages/v2v3/constants/nftRewards' import { createContext, useCallback, useContext, useState } from 'react' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { sortNftsByContributionFloor } from 'utils/nftRewards' import { AddEditRewardModal } from './AddEditRewardModal' import { RewardItem } from './RewardItem' @@ -32,6 +33,7 @@ const useRewardsInstance = () => { type RewardsListProps = FormItemInput & { allowCreate?: boolean withEditWarning?: boolean + nftRewardsData: NftRewardsData } interface RewardsListChildrenExports { @@ -45,6 +47,7 @@ export const RewardsList: React.FC> & value, onChange, withEditWarning, + nftRewardsData, }: RewardsListProps) => { const rewardsHook = useRewards({ value, onChange }) const [selectedReward, setSelectedReward] = useState() @@ -78,6 +81,7 @@ export const RewardsList: React.FC> & {sortNftsByContributionFloor(rewards).map((reward, i) => (
{ setSelectedReward(reward) @@ -110,6 +114,7 @@ export const RewardsList: React.FC> & {title}
- {subtitle && ( + {subtitle || (
This project has no description.
diff --git a/src/components/ProjectPageSEO.tsx b/src/components/ProjectPageSEO.tsx new file mode 100644 index 0000000000..4dd1c54d44 --- /dev/null +++ b/src/components/ProjectPageSEO.tsx @@ -0,0 +1,52 @@ +import { SiteBaseUrl } from 'constants/url' +import { ProjectMetadata } from 'models/projectMetadata' +import { cidFromUrl, ipfsPublicGatewayUrl } from 'utils/ipfs' +import { stripHtmlTags } from 'utils/string' +import { SEO } from './common/SEO/SEO' + +const ProjectPageSEO: React.FC<{ + metadata?: ProjectMetadata + url: string +}> = ({ metadata, url }) => ( + +) + +export const V2V3ProjectSEO: React.FC<{ + metadata?: ProjectMetadata + projectId: number +}> = ({ metadata, projectId }) => ( + +) + +export const V4ProjectSEO: React.FC<{ + metadata?: ProjectMetadata + chainName: string + projectId: number +}> = ({ metadata, chainName, projectId }) => { + return ( + + ) +} diff --git a/src/components/buttons/AddTokenToMetamaskButton.tsx b/src/components/buttons/AddTokenToMetamaskButton.tsx index f6a0a7e3ef..aab89d4477 100644 --- a/src/components/buttons/AddTokenToMetamaskButton.tsx +++ b/src/components/buttons/AddTokenToMetamaskButton.tsx @@ -4,7 +4,6 @@ import { Button } from 'antd' import { providers } from 'ethers' import useSymbolOfERC20 from 'hooks/ERC20/useSymbolOfERC20' import { twMerge } from 'tailwind-merge' -import { Hash } from 'viem' declare global { interface Window { @@ -26,7 +25,7 @@ const useMetamask = () => { return ethereum as unknown as MetaMaskInpageProvider } -function useAddTokenToWalletRequest({ tokenAddress }: { tokenAddress: Hash }) { +function useAddTokenToWalletRequest({ tokenAddress }: { tokenAddress: string }) { const ethereum = useMetamask() const { data: tokenSymbol } = useSymbolOfERC20(tokenAddress) @@ -54,7 +53,7 @@ export function AddTokenToMetamaskButton({ tokenAddress, }: { className: string - tokenAddress: Hash + tokenAddress: `0x${string}` }) { const addToken = useAddTokenToWalletRequest({ tokenAddress, diff --git a/src/components/formItems/ProjectDiscountRate.tsx b/src/components/formItems/ProjectDiscountRate.tsx index 0b8d3fcb70..b04de8bb58 100644 --- a/src/components/formItems/ProjectDiscountRate.tsx +++ b/src/components/formItems/ProjectDiscountRate.tsx @@ -3,7 +3,7 @@ import { Form, Switch } from 'antd' import FormItemLabel from 'components/FormItemLabel' import FormItemWarningText from 'components/FormItemWarningText' import { DISCOUNT_RATE_EXPLANATION } from 'components/strings' -import { DEFAULT_FUNDING_CYCLE_DATA } from 'redux/slices/editingV2Project' +import { DEFAULT_FUNDING_CYCLE_DATA } from 'redux/slices/shared/v2ProjectDefaultState' import NumberSlider from '../inputs/NumberSlider' import { FormItemExt } from './formItemExt' diff --git a/src/components/formItems/ProjectReserved.tsx b/src/components/formItems/ProjectReserved.tsx index aab1b2e6eb..9193478a24 100644 --- a/src/components/formItems/ProjectReserved.tsx +++ b/src/components/formItems/ProjectReserved.tsx @@ -15,7 +15,7 @@ import { useState } from 'react' import { DEFAULT_FUNDING_CYCLE_METADATA, DEFAULT_MINT_RATE, -} from 'redux/slices/editingV2Project' +} from 'redux/slices/shared/v2ProjectDefaultState' import { formattedNum } from 'utils/format/formatNumber' import NumberSlider from '../inputs/NumberSlider' import FundingCycleDetailWarning from '../Project/FundingCycleDetailWarning' diff --git a/src/components/strings.tsx b/src/components/strings.tsx index 300f160ff3..ce3cd5aaf3 100644 --- a/src/components/strings.tsx +++ b/src/components/strings.tsx @@ -1,7 +1,6 @@ import { Trans } from '@lingui/macro' import ExternalLink from 'components/ExternalLink' import Link from 'next/link' -import { v2v3ProjectRoute } from 'packages/v2v3/utils/routes' import { helpPagePath } from 'utils/helpPagePath' export const ISSUE_ERC20_EXPLANATION = ( @@ -33,19 +32,22 @@ export const CYCLE_EXPLANATION = ( supporters.

- This choice isn't permanent — you can switch between locked and unlocked rulesets - in the future. + This choice isn't permanent — you can switch between locked and unlocked + rulesets in the future.

) export const RULESET_EXPLANATION = ( -

With unlocked ruleset cycles, you can edit your project's rules at any time.

- With locked rulesets, you can lock your project's rules for a period of time - (like 3 minutes, 2 years, or 14 days), helping you build trust with your - supporters. + With unlocked ruleset cycles, you can edit your project's rules at any + time. +

+

+ With locked rulesets, you can lock your project's rules for a period of + time (like 3 minutes, 2 years, or 14 days), helping you build trust with + your supporters.

This choice isn't permanent — you can switch between locked and unlocked @@ -61,7 +63,6 @@ export const LOCKED_PAYOUT_EXPLANATION = ( ) - export const DISTRIBUTION_LIMIT_EXPLANATION = ( The amount of ETH which can be paid out from this project during the cycle. @@ -258,8 +259,7 @@ export const FEES_EXPLANATION = ( Payouts to other Juicebox projects don't incur fees. A 2.5% fee is taken from all other payouts. This project's owner will receive{' '} - JBX in exchange for - fees paid.{' '} + JBX in exchange for fees paid.{' '} Learn more. ) diff --git a/src/constants/networks.ts b/src/constants/networks.ts index f8a52a9322..1fdb6da8b3 100644 --- a/src/constants/networks.ts +++ b/src/constants/networks.ts @@ -39,6 +39,24 @@ export const NETWORKS: Record = { rpcUrl: `https://sepolia.infura.io/v3/${infuraId}`, token: 'SepETH', }, + 421614: { + name: NetworkName.arbitrumSepolia, + label: 'Arbitrum Sepolia Testnet', + color: '#96bedc', + chainId: 421614, + token: 'ArbETH', + rpcUrl: `https://sepolia-rollup.arbitrum.io/rpc`, + blockExplorer: 'https://sepolia-explorer.arbitrum.io', + }, + 11155420: { + name: NetworkName.optimismSepolia, + label: 'Optimism Sepolia Testnet', + color: '#f01f70', + chainId: 11155420, + token: 'OpETH', + rpcUrl: `https://sepolia.optimism.io`, + blockExplorer: 'https://optimism-sepolia.blockscout.com', + }, } export const NETWORKS_BY_NAME = Object.values(NETWORKS).reduce( diff --git a/src/contexts/Transaction/EthersTxHistoryProvider.tsx b/src/contexts/Transaction/EthersTxHistoryProvider.tsx index 4c2b9a9656..48be19fee1 100644 --- a/src/contexts/Transaction/EthersTxHistoryProvider.tsx +++ b/src/contexts/Transaction/EthersTxHistoryProvider.tsx @@ -1,7 +1,6 @@ import { readProvider } from 'constants/readProvider' import { TxStatus } from 'models/transaction' import { ReactNode, useEffect } from 'react' -import { Hash } from 'viem' import { TransactionLog, TxHistoryContext } from './TxHistoryContext' import { useTransactions } from './useTransactions' @@ -47,7 +46,7 @@ const pollTransaction = async ( return { ...txLog, tx: { - hash: response.hash as Hash, + hash: response.hash as `0x${string}`, timestamp: response.timestamp, }, status: TxStatus.success, diff --git a/src/contexts/Transaction/TxHistoryContext.ts b/src/contexts/Transaction/TxHistoryContext.ts index ac93e5a0ea..8a4effeb09 100644 --- a/src/contexts/Transaction/TxHistoryContext.ts +++ b/src/contexts/Transaction/TxHistoryContext.ts @@ -1,9 +1,8 @@ import { TransactionCallbacks, TxStatus } from 'models/transaction' import { createContext } from 'react' -import { Hash } from 'viem' export type TransactionType = { - hash: Hash + hash: `0x${string}` timestamp?: number } diff --git a/src/hooks/Wallet/useWallet.ts b/src/hooks/Wallet/useWallet.ts index 08f5910a0b..e97d72250a 100644 --- a/src/hooks/Wallet/useWallet.ts +++ b/src/hooks/Wallet/useWallet.ts @@ -1,21 +1,21 @@ -import { useConnectWallet } from '@web3-onboard/react' import { useChain, - useChainUnsupported, useChangeNetworks, useDisconnect, useIsConnected, useSigner, useUserAddress, - useWalletBalance, + useWalletBalance } from './hooks' +import { useConnectWallet } from '@web3-onboard/react' + export function useWallet() { const signer = useSigner() const userAddress = useUserAddress() const isConnected = useIsConnected() const chain = useChain() - const chainUnsupported = useChainUnsupported() + const chainUnsupported = false //useChainUnsupported() const balance = useWalletBalance() const [, connect] = useConnectWallet() diff --git a/src/hooks/useSubtitle.ts b/src/hooks/useSubtitle.ts index 49af09d05e..4d38cb484d 100644 --- a/src/hooks/useSubtitle.ts +++ b/src/hooks/useSubtitle.ts @@ -1,4 +1,4 @@ -import { JBProjectMetadata } from 'juice-sdk-core' +import { ProjectMetadata } from 'models/projectMetadata' import { useMemo } from 'react' import { stripHtmlTags } from 'utils/string' @@ -6,7 +6,7 @@ export type SubtitleType = 'tagline' | 'description' export const useSubtitle = ( projectMetadata: - | Pick + | Pick | undefined, ) => { const subtitle = useMemo(() => { diff --git a/src/hooks/useTransactor.ts b/src/hooks/useTransactor.ts index 801d7e66a9..1a39b6e095 100644 --- a/src/hooks/useTransactor.ts +++ b/src/hooks/useTransactor.ts @@ -8,7 +8,6 @@ import { CV2V3 } from 'packages/v2v3/models/cv' import { useCallback, useContext } from 'react' import { featureFlagEnabled } from 'utils/featureFlags' import { emitErrorNotification } from 'utils/notifications' -import { Hash } from 'viem' import { useWallet } from './Wallet' type TxOpts = Omit @@ -138,7 +137,7 @@ export function useTransactor(): Transactor | undefined { addTransaction?.( txTitle, { - hash: result.hash as Hash, + hash: result.hash as `0x${string}`, timestamp: result.timestamp, }, { diff --git a/src/lib/apollo/subgraphUri.ts b/src/lib/apollo/subgraphUri.ts index cd94b8d3cf..84b8d40cd7 100644 --- a/src/lib/apollo/subgraphUri.ts +++ b/src/lib/apollo/subgraphUri.ts @@ -1,4 +1,3 @@ -import { JBChainId } from 'juice-sdk-react' import { isBrowser } from 'utils/isBrowser' import { sepolia } from 'viem/chains' @@ -26,20 +25,15 @@ export const subgraphUri = () => { return url.href } -export const v4SubgraphUri = (chainId: JBChainId) => { +export const v4SubgraphUri = (chainId: number) => { let uri: string | undefined - const env: { - [k in JBChainId]?: { - browserUrl?: string - serverUrl?: string - } - } = { + const env = { [sepolia.id]: { browserUrl: process.env.NEXT_PUBLIC_V4_SEPOLIA_SUBGRAPH_URL, serverUrl: process.env.V4_SEPOLIA_SUBGRAPH_URL, }, - } as const + } as Record if (isBrowser()) { uri = env?.[chainId]?.browserUrl diff --git a/src/locales/messages.pot b/src/locales/messages.pot index 9ab838e6a6..4609341b24 100644 --- a/src/locales/messages.pot +++ b/src/locales/messages.pot @@ -1226,9 +1226,6 @@ msgstr "" msgid "Issue as ERC-20" msgstr "" -msgid "Pay {primaryAmount}" -msgstr "" - msgid "Active" msgstr "" @@ -1862,6 +1859,9 @@ msgstr "" msgid "Upload" msgstr "" +msgid "DeSci" +msgstr "" + msgid "The address that should receive the tokens minted from paying this project." msgstr "" @@ -3389,6 +3389,9 @@ msgstr "" msgid "Contract permissions" msgstr "" +msgid "Project is currently only issuing NFTs" +msgstr "" + msgid "Project configurations cannot be changed to the duration of locked cycles." msgstr "" diff --git a/src/middleware.ts b/src/middleware.ts index a2ac652cb9..5cc37ad7a7 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -7,9 +7,55 @@ const HANDLE_REGEX = new RegExp(/\/@([^/]+).*/) const logger = getLogger('middleware/page') +const GEOFENCED_PROJECT_IDS: { + path: string + projectId: number + blockedCountries: string[] +}[] = [ + // { path: '/v2/p/64', projectId: 64, blockedCountries: ['AU'] }, // example +] + +// function geofenceCheck(projectId: number, request: NextRequest) { +// const url = request.nextUrl + +// const country = geolocation(request).country +// logger.info('🌎 Geofence check', { +// country, +// projectId, +// geo: geolocation(request), +// }) + +// if ( +// country && +// GEOFENCED_PROJECT_IDS.find( +// p => p.projectId === projectId, +// )?.blockedCountries.includes(country) +// ) { +// logger.info('Geofenced project', { +// originalPathname: request.nextUrl.pathname, +// newPathname: '/404', +// }) +// url.pathname = '/404' + +// return url +// } +// } + export async function middleware(request: NextRequest) { logger.info('middleware request', { pathname: request.nextUrl.pathname }) - if (!request.nextUrl.pathname.startsWith('/@')) return + if (!request.nextUrl.pathname.startsWith('/@')) { + if (!request.nextUrl.pathname.startsWith('/v2/p/')) { + return + } + + // const projectId = parseInt(request.nextUrl.pathname.split('/').reverse()[0]) + // const newUrl = geofenceCheck(projectId, request) + // if (newUrl) { + // return NextResponse.rewrite(newUrl) + // } + + // return + } // If request is for a handle id, add the search param with `isHandle`. const handle = request.nextUrl.pathname.match(HANDLE_REGEX)?.[1] @@ -44,6 +90,11 @@ export async function middleware(request: NextRequest) { return NextResponse.rewrite(url) } + // const geofenceRedirect = geofenceCheck(projectId, request) + // if (geofenceRedirect) { + // return NextResponse.rewrite(geofenceRedirect) + // } + url.pathname = `/v2/p/${projectId}${trailingPath ? `/${trailingPath}` : ''}` logger.info('Rewriting to project route', { @@ -55,5 +106,5 @@ export async function middleware(request: NextRequest) { } export const config = { - matcher: '/@(.*)', + matcher: ['/@(.*)', ...GEOFENCED_PROJECT_IDS.map(p => p.path)], } diff --git a/src/models/JB721Delegate.ts b/src/models/JB721Delegate.ts new file mode 100644 index 0000000000..4174ab8ff9 --- /dev/null +++ b/src/models/JB721Delegate.ts @@ -0,0 +1,8 @@ +export enum JB721DelegateVersion { + JB721DELEGATE_V3 = '3', + JB721DELEGATE_V3_1 = '3-1', + JB721DELEGATE_V3_2 = '3-2', + JB721DELEGATE_V3_3 = '3-3', + JB721DELEGATE_V3_4 = '3-4', + JB721DELEGATE_V4 = '4', +} diff --git a/src/models/networkName.ts b/src/models/networkName.ts index 9653ec39bb..d3e5e35266 100644 --- a/src/models/networkName.ts +++ b/src/models/networkName.ts @@ -2,4 +2,6 @@ export enum NetworkName { localhost = 'localhost', mainnet = 'mainnet', sepolia = 'sepolia', + arbitrumSepolia = 'arbitrumSepolia', + optimismSepolia = 'optimismSepolia', } diff --git a/src/models/nftPostPayModal.ts b/src/models/nftPostPayModal.ts new file mode 100644 index 0000000000..5294a78e79 --- /dev/null +++ b/src/models/nftPostPayModal.ts @@ -0,0 +1,5 @@ +export type NftPostPayModalConfig = { + ctaText: string | undefined + ctaLink: string | undefined + content: string | undefined +} diff --git a/src/models/nftRewards.ts b/src/models/nftRewards.ts index 912a815be3..aa8e39fa23 100644 --- a/src/models/nftRewards.ts +++ b/src/models/nftRewards.ts @@ -60,6 +60,24 @@ export type JB_721_TIER_PARAMS_V3_2 = Omit< useVotingUnits: boolean } +// v4TODO: add to SDK +export type JB_721_TIER_PARAMS_V4 = { + price: bigint + initialSupply: number + votingUnits: number + reserveFrequency: number + reserveBeneficiary: `0x${string}` + encodedIPFSUri: `0x${string}` + category: number + discountPercent: number + allowOwnerMint: boolean + useReserveBeneficiaryAsDefault: boolean + transfersPausable: boolean + useVotingUnits: boolean + cannotBeRemoved: boolean + cannotIncreaseDiscountPercent: boolean +} + // Tiers as they are stored on-chain. export type JB721TierV3 = JB721TierParams & { id: BigNumber @@ -114,19 +132,18 @@ export type NftCollectionMetadata = { description: string | undefined } -export type NftPostPayModalConfig = { - ctaText: string | undefined - ctaLink: string | undefined - content: string | undefined -} - export enum JB721GovernanceType { NONE, ONCHAIN, } export interface JB721PricingParams { - tiers: (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2)[] + tiers: ( + | JB721TierParams + | JB_721_TIER_PARAMS_V3_1 + | JB_721_TIER_PARAMS_V3_2 + | JB_721_TIER_PARAMS_V4 + )[] currency: CurrencyOption decimals: number prices: string // address diff --git a/src/models/project-tags.ts b/src/models/project-tags.ts index cffab6be5d..09ee7850a4 100644 --- a/src/models/project-tags.ts +++ b/src/models/project-tags.ts @@ -6,6 +6,7 @@ export const projectTagOptions = [ 'charity', 'dao', 'defi', + 'desci', 'education', 'events', 'fundraising', @@ -24,6 +25,7 @@ export const projectTagText: { charity: () => t`Charity`, dao: () => t`DAO`, defi: () => t`DeFi`, + desci: () => t`DeSci`, education: () => t`Education`, events: () => t`Events`, fundraising: () => t`Fundraising`, diff --git a/src/models/projectMetadata.ts b/src/models/projectMetadata.ts index 9df1645926..349e1596a2 100644 --- a/src/models/projectMetadata.ts +++ b/src/models/projectMetadata.ts @@ -1,4 +1,4 @@ -import { NftPostPayModalConfig } from './nftRewards' +import { NftPostPayModalConfig } from './nftPostPayModal' import { ProjectTagName, filterValidTags } from './project-tags' import { TokenRef } from './tokenRef' diff --git a/src/packages/v1/components/V1Project/modals/ReconfigureFCModal/ReconfigureFCModal.tsx b/src/packages/v1/components/V1Project/modals/ReconfigureFCModal/ReconfigureFCModal.tsx index de8818fa81..1c4e774cc9 100644 --- a/src/packages/v1/components/V1Project/modals/ReconfigureFCModal/ReconfigureFCModal.tsx +++ b/src/packages/v1/components/V1Project/modals/ReconfigureFCModal/ReconfigureFCModal.tsx @@ -41,7 +41,7 @@ import { amountSubFee } from 'packages/v1/utils/math' import { serializeV1FundingCycle } from 'packages/v1/utils/serializers' import { useCallback, useContext, useLayoutEffect, useState } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { useEditingV1FundingCycleSelector } from 'redux/hooks/useAppSelector' +import { useEditingV1FundingCycleSelector } from 'redux/hooks/v1' import { editingProjectActions } from 'redux/slices/editingProject' import { classNames } from 'utils/classNames' import { drawerWidth } from 'utils/drawerWidth' diff --git a/src/packages/v1/components/shared/forms/BudgetForm.tsx b/src/packages/v1/components/shared/forms/BudgetForm.tsx index 98ae72f9fe..8a68aa6ad8 100644 --- a/src/packages/v1/components/shared/forms/BudgetForm.tsx +++ b/src/packages/v1/components/shared/forms/BudgetForm.tsx @@ -16,7 +16,7 @@ import { } from 'packages/v1/utils/payouts' import { useContext, useLayoutEffect, useMemo, useState } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { useEditingV1FundingCycleSelector } from 'redux/hooks/useAppSelector' +import { useEditingV1FundingCycleSelector } from 'redux/hooks/v1' import { editingProjectActions } from 'redux/slices/editingProject' import { fromWad } from 'utils/format/formatNumber' import { helpPagePath } from 'utils/helpPagePath' diff --git a/src/packages/v2v3/components/Create/components/Wizard/hooks/usePage.ts b/src/packages/v2v3/components/Create/components/Wizard/hooks/usePage.ts index ca1573a61b..164f6bc00f 100644 --- a/src/packages/v2v3/components/Create/components/Wizard/hooks/usePage.ts +++ b/src/packages/v2v3/components/Create/components/Wizard/hooks/usePage.ts @@ -1,7 +1,7 @@ import { CreatePage } from 'models/createPage' import { useCallback, useContext, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { WizardContext } from '../contexts/WizardContext' export const usePage = ({ name }: { name: string }) => { @@ -41,14 +41,14 @@ export const usePage = ({ name }: { name: string }) => { const lockPageProgress = useCallback(() => { dispatch( - editingV2ProjectActions.addCreateSoftLockedPage(name as CreatePage), + creatingV2ProjectActions.addCreateSoftLockedPage(name as CreatePage), ) }, [dispatch, name]) const unlockPageProgress = useCallback(() => { // We need to make sure pages can't unsoftlock other pages :\ dispatch( - editingV2ProjectActions.removeCreateSoftLockedPage(name as CreatePage), + creatingV2ProjectActions.removeCreateSoftLockedPage(name as CreatePage), ) }, [dispatch, name]) diff --git a/src/packages/v2v3/components/Create/components/Wizard/hooks/useSteps.ts b/src/packages/v2v3/components/Create/components/Wizard/hooks/useSteps.ts index 1947d1ff9c..cf35d259a1 100644 --- a/src/packages/v2v3/components/Create/components/Wizard/hooks/useSteps.ts +++ b/src/packages/v2v3/components/Create/components/Wizard/hooks/useSteps.ts @@ -21,7 +21,7 @@ export const useSteps = () => { const { pages, currentPage, goToPage } = useContext(WizardContext) const { furthestPageReached } = useEditingCreateFurthestPageReached() const softLockedPageQueue = useAppSelector( - state => state.editingV2Project.createSoftLockPageQueue, + state => state.creatingV2Project.createSoftLockPageQueue, ) const firstIndexOfLockedPage = useMemo(() => { diff --git a/src/packages/v2v3/components/Create/components/Wizard/hooks/useWizard.ts b/src/packages/v2v3/components/Create/components/Wizard/hooks/useWizard.ts index b14c816043..fb995801e9 100644 --- a/src/packages/v2v3/components/Create/components/Wizard/hooks/useWizard.ts +++ b/src/packages/v2v3/components/Create/components/Wizard/hooks/useWizard.ts @@ -13,7 +13,7 @@ export const useWizard = ({ children }: { children?: any[] }) => { const [currentPage, setCurrentPage] = useState('') const { furthestPageReached } = useEditingCreateFurthestPageReached() const softLockedPageQueue = useAppSelector( - state => state.editingV2Project.createSoftLockPageQueue, + state => state.creatingV2Project.createSoftLockPageQueue, ) const pages: PageProps[] = useMemo(() => { diff --git a/src/packages/v2v3/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts b/src/packages/v2v3/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts index 31f668ec79..0f3760b486 100644 --- a/src/packages/v2v3/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts @@ -6,8 +6,8 @@ import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' import { DEFAULT_MUST_START_AT_OR_AFTER, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' import { deriveDurationUnit, otherUnitToSeconds, @@ -23,7 +23,7 @@ export type FundingCyclesFormProps = Partial<{ export const useFundingCyclesForm = () => { const [form] = useForm() const { fundingCycleData, fundingCyclesPageSelection, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) + useAppSelector(state => state.creatingV2Project) useDebugValue(form.getFieldsValue()) const initialValues: FundingCyclesFormProps | undefined = useMemo(() => { @@ -63,17 +63,17 @@ export const useFundingCyclesForm = () => { const launchDate = useWatch('launchDate', form) useEffect(() => { - dispatch(editingV2ProjectActions.setFundingCyclesPageSelection(selection)) + dispatch(creatingV2ProjectActions.setFundingCyclesPageSelection(selection)) // We need to handle manual case first as duration might be undefined, but // manual set. if (selection === 'manual') { - dispatch(editingV2ProjectActions.setDuration('0')) + dispatch(creatingV2ProjectActions.setDuration('0')) return } if (!selection || duration?.duration === undefined) { - dispatch(editingV2ProjectActions.setDuration('')) + dispatch(creatingV2ProjectActions.setDuration('')) return } if (selection === 'automated') { @@ -81,7 +81,7 @@ export const useFundingCyclesForm = () => { duration: duration.duration, unit: duration.unit, }) - dispatch(editingV2ProjectActions.setDuration(newDuration.toString())) + dispatch(creatingV2ProjectActions.setDuration(newDuration.toString())) return } }, [selection, duration, dispatch]) @@ -90,14 +90,14 @@ export const useFundingCyclesForm = () => { if (launchDate === undefined) return if (launchDate === null || !launchDate.unix().toString()) { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( DEFAULT_MUST_START_AT_OR_AFTER, ), ) return } dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( launchDate?.unix().toString(), ), ) diff --git a/src/packages/v2v3/components/Create/components/pages/NftRewards/NftRewardsPage.tsx b/src/packages/v2v3/components/Create/components/pages/NftRewards/NftRewardsPage.tsx index 79b9e9612c..40aaf02b0b 100644 --- a/src/packages/v2v3/components/Create/components/pages/NftRewards/NftRewardsPage.tsx +++ b/src/packages/v2v3/components/Create/components/pages/NftRewards/NftRewardsPage.tsx @@ -2,6 +2,7 @@ import { AddNftCollectionForm } from 'components/NftRewards/AddNftCollectionForm import { CREATE_FLOW } from 'constants/fathomEvents' import { trackFathomGoal } from 'lib/fathom' import { useContext } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' import { Wizard } from '../../Wizard/Wizard' import { PageContext } from '../../Wizard/contexts/PageContext' @@ -11,12 +12,22 @@ export function NftRewardsPage() { const { goToNextPage } = useContext(PageContext) const { form, initialValues } = useCreateFlowNftRewardsForm() + + const postPayModalData = useAppSelector( + state => state.creatingV2Project.nftRewards.postPayModal, + ) + const nftRewardsData = useAppSelector( + state => state.creatingV2Project.nftRewards, + ) + useSetCreateFurthestPageReached('nftRewards') return ( } onFinish={() => { goToNextPage?.() diff --git a/src/packages/v2v3/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts b/src/packages/v2v3/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts index e308334d8a..4bd4f9a295 100644 --- a/src/packages/v2v3/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts @@ -4,7 +4,7 @@ import { NftRewardTier } from 'models/nftRewards' import { useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { withHttps, withoutHttp } from 'utils/externalLink' import { defaultNftCollectionDescription, @@ -20,9 +20,9 @@ export const useCreateFlowNftRewardsForm = () => { postPayModal, governanceType, flags, - } = useAppSelector(state => state.editingV2Project.nftRewards) + } = useAppSelector(state => state.creatingV2Project.nftRewards) const { projectMetadata, fundingCycleMetadata } = useAppSelector( - state => state.editingV2Project, + state => state.creatingV2Project, ) const initialValues: NftRewardsFormProps = useMemo(() => { const collectionName = @@ -79,7 +79,7 @@ export const useCreateFlowNftRewardsForm = () => { fieldName: 'rewards', ignoreUndefined: true, // Needed to stop an infinite loop currentValue: rewardTiers, - dispatchFunction: editingV2ProjectActions.setNftRewardTiers, + dispatchFunction: creatingV2ProjectActions.setNftRewardTiers, formatter: v => { if (!v) return [] if (typeof v !== 'object') { @@ -106,7 +106,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'collectionName', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftRewardsName, + dispatchFunction: creatingV2ProjectActions.setNftRewardsName, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -117,7 +117,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'collectionSymbol', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftRewardsSymbol, + dispatchFunction: creatingV2ProjectActions.setNftRewardsSymbol, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -129,7 +129,7 @@ export const useCreateFlowNftRewardsForm = () => { fieldName: 'collectionDescription', ignoreUndefined: true, dispatchFunction: - editingV2ProjectActions.setNftRewardsCollectionDescription, + creatingV2ProjectActions.setNftRewardsCollectionDescription, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -140,7 +140,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'useDataSourceForRedeem', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setUseDataSourceForRedeem, + dispatchFunction: creatingV2ProjectActions.setUseDataSourceForRedeem, formatter: v => !!v, }) @@ -148,7 +148,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'preventOverspending', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftPreventOverspending, + dispatchFunction: creatingV2ProjectActions.setNftPreventOverspending, formatter: v => !!v, }) @@ -178,11 +178,11 @@ export const useCreateFlowNftRewardsForm = () => { postPayButtonText === undefined && postPayButtonLink === undefined ) { - dispatch(editingV2ProjectActions.setNftPostPayModalConfig(undefined)) + dispatch(creatingV2ProjectActions.setNftPostPayModalConfig(undefined)) return } dispatch( - editingV2ProjectActions.setNftPostPayModalConfig({ + creatingV2ProjectActions.setNftPostPayModalConfig({ content: postPayMessage, ctaText: postPayButtonText, ctaLink: withHttps(postPayButtonLink), diff --git a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx index 8cba9c606d..6134864242 100644 --- a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx +++ b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' import { Wizard } from '../../Wizard/Wizard' import { PageContext } from '../../Wizard/contexts/PageContext' @@ -6,11 +7,16 @@ import { CreateFlowPayoutsTable } from './components/CreateFlowPayoutsTable' import { TreasuryOptionsRadio } from './components/TreasuryOptionsRadio' export const PayoutsPage = () => { + const treasurySelection = useAppSelector( + state => state.creatingV2Project.treasurySelection, + ) + useSetCreateFurthestPageReached('payouts') const { goToNextPage } = useContext(PageContext) return ( { goToNextPage?.() }} diff --git a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx index 1cafe219a4..fb887c0db8 100644 --- a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx +++ b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx @@ -1,5 +1,6 @@ import { Form } from 'antd' import { CURRENCY_METADATA, CurrencyName } from 'constants/currency' +import { TreasurySelection } from 'models/treasurySelection' import { PayoutsTable } from 'packages/v2v3/components/shared/PayoutsTable/PayoutsTable' import { Split } from 'packages/v2v3/models/splits' import { @@ -7,9 +8,12 @@ import { getV2V3CurrencyOption, } from 'packages/v2v3/utils/currency' import { MAX_DISTRIBUTION_LIMIT } from 'packages/v2v3/utils/math' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { ReactNode } from 'react' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' import { fromWad, parseWad } from 'utils/format/formatNumber' import { usePayoutsForm } from '../hooks/usePayoutsForm' @@ -20,18 +24,22 @@ export function CreateFlowPayoutsTable({ topAccessory, okButton, addPayoutsDisabled, + createTreasurySelection, }: { onFinish?: VoidFunction okButton?: ReactNode topAccessory?: ReactNode addPayoutsDisabled?: boolean + // TODO: Hack to allow payout recipients to be shown on review but not on create page + // When zero, hides the recipients, but undefined still shows them + createTreasurySelection?: TreasurySelection }) { const [ editingDistributionLimit, , setDistributionLimitAmount, setDistributionLimitCurrency, - ] = useEditingDistributionLimit() + ] = useCreatingDistributionLimit() const { form, initialValues } = usePayoutsForm() const distributionLimit = !editingDistributionLimit @@ -72,6 +80,7 @@ export function CreateFlowPayoutsTable({ hideExplaination hideSettings addPayoutsDisabled={addPayoutsDisabled} + createTreasurySelection={createTreasurySelection} /> {/* Empty form item just to keep AntD useWatch happy */} diff --git a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx index 0389eae6df..6327320d90 100644 --- a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx +++ b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx @@ -8,9 +8,12 @@ import { useModal } from 'hooks/useModal' import { TreasurySelection } from 'models/treasurySelection' import { ConvertAmountsModal } from 'packages/v2v3/components/shared/PayoutsTable/ConvertAmountsModal' import { usePayoutsTable } from 'packages/v2v3/components/shared/PayoutsTable/hooks/usePayoutsTable' +import { V4_CURRENCY_ETH, V4_CURRENCY_USD } from 'packages/v4/utils/currency' import { useCallback, useEffect, useMemo, useState } from 'react' +import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { ReduxDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { ReduxDistributionLimit } from 'redux/hooks/v2v3/shared' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { fromWad } from 'utils/format/formatNumber' import { Icons } from '../../../Icons' import { RadioCard } from './RadioCard' @@ -23,8 +26,9 @@ const treasuryOptions = () => [ export function TreasuryOptionsRadio() { const initialTreasurySelection = useAppSelector( - state => state.editingV2Project.treasurySelection, + state => state.creatingV2Project.treasurySelection, ) + const dispatch = useAppDispatch() const [treasuryOption, setTreasuryOption] = useState( initialTreasurySelection ?? 'zero', @@ -32,6 +36,7 @@ export function TreasuryOptionsRadio() { const { distributionLimit, + currency, setDistributionLimit, payoutSplits, setCurrency, @@ -102,17 +107,19 @@ export function TreasuryOptionsRadio() { switchToZeroPayoutSelection() } + dispatch(creatingV2ProjectActions.setTreasurySelection(option)) setTreasuryOption(option) }, [ treasuryOption, payoutSplits.length, + dispatch, switchingToAmountsModal, - switchingToUnlimitedModal, setDistributionLimit, + switchingToUnlimitedModal, + switchToUnlimitedPayouts, switchingToZeroAmountsModal, switchToZeroPayoutSelection, - switchToUnlimitedPayouts, ], ) @@ -164,6 +171,7 @@ export function TreasuryOptionsRadio() { onClose={switchingToUnlimitedModal.close} /> => { - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() return determineAvailablePayoutsSelections(distributionLimit?.amount) } diff --git a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts index 8a7b6c80fe..24edcf412a 100644 --- a/src/packages/v2v3/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts @@ -1,11 +1,14 @@ import { Form } from 'antd' import { TreasurySelection } from 'models/treasurySelection' import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useDebugValue, useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingPayoutSplits } from 'redux/hooks/useEditingPayoutSplits' +import { useCreatingPayoutSplits } from 'redux/hooks/v2v3/create' type PayoutsFormProps = Partial<{ selection: TreasurySelection @@ -14,8 +17,8 @@ type PayoutsFormProps = Partial<{ export const usePayoutsForm = () => { const [form] = Form.useForm() - const { treasurySelection } = useAppSelector(state => state.editingV2Project) - const [splits, setSplits] = useEditingPayoutSplits() + const { treasurySelection } = useAppSelector(state => state.creatingV2Project) + const [splits, setSplits] = useCreatingPayoutSplits() useDebugValue(form.getFieldsValue()) const initialValues: PayoutsFormProps | undefined = useMemo(() => { diff --git a/src/packages/v2v3/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts b/src/packages/v2v3/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts index 6bdefa459e..115903809a 100644 --- a/src/packages/v2v3/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts @@ -8,8 +8,8 @@ import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' import { DEFAULT_MUST_START_AT_OR_AFTER, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' import { AmountInputValue } from '../ProjectDetailsPage' @@ -40,7 +40,7 @@ type ProjectDetailsFormProps = Partial<{ export const useProjectDetailsForm = () => { const [form] = useForm() const { projectMetadata, inputProjectOwner, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) + useAppSelector(state => state.creatingV2Project) const initialValues: ProjectDetailsFormProps = useMemo( () => ({ @@ -103,90 +103,90 @@ export const useProjectDetailsForm = () => { form, fieldName: 'projectName', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setName, + dispatchFunction: creatingV2ProjectActions.setName, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTagline', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setProjectTagline, + dispatchFunction: creatingV2ProjectActions.setProjectTagline, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectDescription', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setDescription, + dispatchFunction: creatingV2ProjectActions.setDescription, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'tags', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTags, + dispatchFunction: creatingV2ProjectActions.setTags, formatter: v => v ?? [], }) useFormDispatchWatch({ form, fieldName: 'logo', - dispatchFunction: editingV2ProjectActions.setLogoUri, + dispatchFunction: creatingV2ProjectActions.setLogoUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'coverImage', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setCoverImageUri, + dispatchFunction: creatingV2ProjectActions.setCoverImageUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectWebsite', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setInfoUri, + dispatchFunction: creatingV2ProjectActions.setInfoUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTwitter', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTwitter, + dispatchFunction: creatingV2ProjectActions.setTwitter, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectDiscord', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setDiscord, + dispatchFunction: creatingV2ProjectActions.setDiscord, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTelegram', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTelegram, + dispatchFunction: creatingV2ProjectActions.setTelegram, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'inputProjectOwner', ignoreUndefined: false, - dispatchFunction: editingV2ProjectActions.setInputProjectOwner, + dispatchFunction: creatingV2ProjectActions.setInputProjectOwner, formatter: v => v, }) useFormDispatchWatch({ form, fieldName: 'payButtonText', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPayButton, + dispatchFunction: creatingV2ProjectActions.setPayButton, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'payDisclosure', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPayDisclosure, + dispatchFunction: creatingV2ProjectActions.setPayDisclosure, formatter: v => v ?? '', }) @@ -194,21 +194,21 @@ export const useProjectDetailsForm = () => { form, fieldName: 'introVideoUrl', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setIntroVideoUrl, + dispatchFunction: creatingV2ProjectActions.setIntroVideoUrl, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'introImageUri', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setIntroImageUri, + dispatchFunction: creatingV2ProjectActions.setIntroImageUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'softTarget', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setSoftTarget, + dispatchFunction: creatingV2ProjectActions.setSoftTarget, formatter: v => v ?? { amount: '', currency: V2V3_CURRENCY_USD }, }) @@ -222,13 +222,13 @@ export const useProjectDetailsForm = () => { // check if launch date is in ms or seconds if (launchDate > 1000000000000) { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( (launchDate / 1000).toString(), ), ) } else { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter(launchDate.toString()), + creatingV2ProjectActions.setMustStartAtOrAfter(launchDate.toString()), ) } }, [dispatch, startTimestamp]) diff --git a/src/packages/v2v3/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx b/src/packages/v2v3/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx index 1a245d56ef..4dca9f6920 100644 --- a/src/packages/v2v3/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx +++ b/src/packages/v2v3/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx @@ -17,7 +17,7 @@ import { formatFundingCycleDuration } from 'packages/v2v3/components/Create/util import { ReservedTokensList } from 'packages/v2v3/components/shared/ReservedTokensList' import { MAX_DISTRIBUTION_LIMIT, MAX_MINT_RATE } from 'packages/v2v3/utils/math' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' import { inputMustExistRule } from 'utils/antdRules' import { formatAmount } from 'utils/format/formatAmount' import * as ProjectTokenForm from '../../hooks/useProjectTokenForm' @@ -37,9 +37,9 @@ const calculateMintRateAfterDiscount = ({ export const CustomTokenSettings = () => { const isMobile = useMobile() const duration = useAppSelector( - state => state.editingV2Project.fundingCycleData.duration, + state => state.creatingV2Project.fundingCycleData.duration, ) - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() const form = Form.useFormInstance() const discountRate = Form.useWatch('discountRate', form) ?? diff --git a/src/packages/v2v3/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts b/src/packages/v2v3/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts index 9e743f07aa..0537cdb63c 100644 --- a/src/packages/v2v3/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts @@ -14,13 +14,18 @@ import { redemptionRateFrom, reservedRateFrom, } from 'packages/v2v3/utils/math' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useDebugValue, useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' -import { useEditingReservedTokensSplits } from 'redux/hooks/useEditingReservedTokensSplits' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { + useCreatingDistributionLimit, + useCreatingReservedTokensSplits, +} from 'redux/hooks/v2v3/create' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' export type ProjectTokensFormProps = Partial<{ @@ -52,10 +57,10 @@ export const DefaultSettings: Required< export const useProjectTokensForm = () => { const [form] = Form.useForm() const { fundingCycleMetadata, fundingCycleData, projectTokensSelection } = - useAppSelector(state => state.editingV2Project) - const [tokenSplits] = useEditingReservedTokensSplits() + useAppSelector(state => state.creatingV2Project) + const [tokenSplits] = useCreatingReservedTokensSplits() useDebugValue(form.getFieldsValue()) - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() const redemptionRateDisabled = !distributionLimit || distributionLimit.amount.eq(MAX_DISTRIBUTION_LIMIT) @@ -117,15 +122,15 @@ export const useProjectTokensForm = () => { useEffect(() => { // We only want to update changes when selection is set if (selection === undefined) return - dispatch(editingV2ProjectActions.setProjectTokensSelection(selection)) + dispatch(creatingV2ProjectActions.setProjectTokensSelection(selection)) if (selection === 'default') { form.setFieldsValue({ ...DefaultSettings }) - dispatch(editingV2ProjectActions.setTokenSettings(DefaultSettings)) + dispatch(creatingV2ProjectActions.setTokenSettings(DefaultSettings)) return } dispatch( - editingV2ProjectActions.setTokenSettings({ + creatingV2ProjectActions.setTokenSettings({ ...DefaultSettings, ...form.getFieldsValue(), }), @@ -135,7 +140,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'initialMintRate', - dispatchFunction: editingV2ProjectActions.setWeight, + dispatchFunction: creatingV2ProjectActions.setWeight, formatter: v => { if (v === undefined || typeof v !== 'string') return issuanceRateFrom(DefaultSettings.initialMintRate) @@ -146,7 +151,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'reservedTokensPercentage', - dispatchFunction: editingV2ProjectActions.setReservedRate, + dispatchFunction: creatingV2ProjectActions.setReservedRate, formatter: v => { if (v === undefined || typeof v !== 'number') return reservedRateFrom( @@ -161,7 +166,7 @@ export const useProjectTokensForm = () => { fieldName: 'reservedTokenAllocation', ignoreUndefined: true, // Needed to stop an infinite loop currentValue: tokenSplits, // Needed to stop an infinite loop - dispatchFunction: editingV2ProjectActions.setReservedTokensSplits, + dispatchFunction: creatingV2ProjectActions.setReservedTokensSplits, formatter: v => { if (v === undefined || typeof v !== 'object') return [] return v.map(allocationToSplit) @@ -171,7 +176,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'discountRate', - dispatchFunction: editingV2ProjectActions.setDiscountRate, + dispatchFunction: creatingV2ProjectActions.setDiscountRate, formatter: v => { if (v === undefined || typeof v !== 'number') return discountRateFrom(DefaultSettings.discountRate).toHexString() @@ -182,7 +187,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'redemptionRate', - dispatchFunction: editingV2ProjectActions.setRedemptionRate, + dispatchFunction: creatingV2ProjectActions.setRedemptionRate, formatter: v => { if (v === undefined || typeof v !== 'number') return redemptionRateFrom(DefaultSettings.redemptionRate).toHexString() @@ -192,7 +197,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'redemptionRate', - dispatchFunction: editingV2ProjectActions.setBallotRedemptionRate, + dispatchFunction: creatingV2ProjectActions.setBallotRedemptionRate, formatter: v => { if (v === undefined || typeof v !== 'number') return redemptionRateFrom(DefaultSettings.redemptionRate).toHexString() @@ -203,7 +208,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'tokenMinting', - dispatchFunction: editingV2ProjectActions.setAllowMinting, + dispatchFunction: creatingV2ProjectActions.setAllowMinting, formatter: v => { if (typeof v !== 'boolean') return false return v @@ -213,7 +218,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'pauseTransfers', - dispatchFunction: editingV2ProjectActions.setPauseTransfers, + dispatchFunction: creatingV2ProjectActions.setPauseTransfers, ignoreUndefined: true, formatter: v => { if (typeof v !== 'boolean') return false diff --git a/src/packages/v2v3/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts b/src/packages/v2v3/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts index 23434ae661..92bd9755d7 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts +++ b/src/packages/v2v3/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts @@ -6,7 +6,7 @@ import { useAvailableReconfigurationStrategies } from 'packages/v2v3/components/ import { useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { isEqualAddress, isZeroAddress } from 'utils/address' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' @@ -47,7 +47,7 @@ export const useReconfigurationRulesForm = () => { fundingCycleData: { ballot }, reconfigurationRuleSelection, fundingCycleMetadata, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const initialValues: ReconfigurationRulesFormProps | undefined = useMemo(() => { const pausePayments = fundingCycleMetadata.pausePay @@ -128,15 +128,17 @@ export const useReconfigurationRulesForm = () => { address = customAddress break } - dispatch(editingV2ProjectActions.setBallot(address ?? '')) - dispatch(editingV2ProjectActions.setReconfigurationRuleSelection(selection)) + dispatch(creatingV2ProjectActions.setBallot(address ?? '')) + dispatch( + creatingV2ProjectActions.setReconfigurationRuleSelection(selection), + ) }, [customAddress, dispatch, selection, strategies]) useFormDispatchWatch({ form, fieldName: 'pausePayments', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPausePay, + dispatchFunction: creatingV2ProjectActions.setPausePay, formatter: v => !!v, }) @@ -144,7 +146,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'holdFees', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setHoldFees, + dispatchFunction: creatingV2ProjectActions.setHoldFees, formatter: v => !!v, }) @@ -152,7 +154,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowTerminalConfiguration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowSetTerminals, + dispatchFunction: creatingV2ProjectActions.setAllowSetTerminals, formatter: v => !!v, }) @@ -160,7 +162,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowControllerConfiguration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowSetController, + dispatchFunction: creatingV2ProjectActions.setAllowSetController, formatter: v => !!v, }) @@ -168,7 +170,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowTerminalMigration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowTerminalMigration, + dispatchFunction: creatingV2ProjectActions.setAllowTerminalMigration, formatter: v => !!v, }) @@ -176,14 +178,14 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowControllerMigration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowControllerMigration, + dispatchFunction: creatingV2ProjectActions.setAllowControllerMigration, formatter: v => !!v, }) useFormDispatchWatch({ form, fieldName: 'projectRequiredOFACCheck', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setRequiredOFACCheck, + dispatchFunction: creatingV2ProjectActions.setRequiredOFACCheck, formatter: v => v, }) diff --git a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx index 12b411967e..cd06e55bb2 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx +++ b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx @@ -15,7 +15,7 @@ import { useCallback, useContext, useEffect, useMemo, useState } from 'react' import { useDispatch } from 'react-redux' import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { helpPagePath } from 'utils/helpPagePath' import { CreateBadge } from '../../CreateBadge' import { CreateCollapse } from '../../CreateCollapse/CreateCollapse' @@ -65,7 +65,7 @@ export const ReviewDeployPage = () => { const { deployProject, isDeploying, deployTransactionPending } = useDeployProject() const nftRewards = useAppSelector( - state => state.editingV2Project.nftRewards.rewardTiers, + state => state.creatingV2Project.nftRewards.rewardTiers, ) const nftRewardsAreSet = useMemo( @@ -78,7 +78,7 @@ export const ReviewDeployPage = () => { const handleStartOverClicked = useCallback(() => { router.push('/create') goToPage?.('projectDetails') - dispatch(editingV2ProjectActions.resetState()) + dispatch(creatingV2ProjectActions.resetState()) }, [dispatch, goToPage, router]) const onFinish = useCallback(async () => { diff --git a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/FundingConfigurationReview/hooks/useFundingConfigurationReview.ts b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/FundingConfigurationReview/hooks/useFundingConfigurationReview.ts index 83b7f6a8e3..2ef2f54203 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/FundingConfigurationReview/hooks/useFundingConfigurationReview.ts +++ b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/FundingConfigurationReview/hooks/useFundingConfigurationReview.ts @@ -3,19 +3,24 @@ import moment from 'moment' import { useAvailablePayoutsSelections } from 'packages/v2v3/components/Create/components/pages/PayoutsPage/hooks/useAvailablePayoutsSelections' import { formatFundingCycleDuration } from 'packages/v2v3/components/Create/utils/formatFundingCycleDuration' import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useCallback, useMemo } from 'react' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' -import { useEditingPayoutSplits } from 'redux/hooks/useEditingPayoutSplits' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' +import { + useCreatingDistributionLimit, + useCreatingPayoutSplits, +} from 'redux/hooks/v2v3/create' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/creatingV2Project' import { formatFundingTarget } from 'utils/format/formatFundingTarget' export const useFundingConfigurationReview = () => { const { fundingCycleData, payoutsSelection, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) - const [distributionLimit] = useEditingDistributionLimit() - const [payoutSplits, setPayoutSplits] = useEditingPayoutSplits() + useAppSelector(state => state.creatingV2Project) + const [distributionLimit] = useCreatingDistributionLimit() + const [payoutSplits, setPayoutSplits] = useCreatingPayoutSplits() const fundingCycles = useMemo( () => (fundingCycleData.duration == '0' ? t`Manual` : t`Automated`), diff --git a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx index b7b74c3504..d5ea262bc2 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx +++ b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx @@ -31,7 +31,7 @@ export const ProjectDetailsReview = () => { softTargetCurrency, }, inputProjectOwner, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const youtubeUrl = useMemo(() => { if (!introVideoUrl) return undefined diff --git a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts index c5f4b5da21..5c6a1cf39d 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts +++ b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts @@ -1,8 +1,11 @@ import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useCallback, useMemo } from 'react' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingReservedTokensSplits } from 'redux/hooks/useEditingReservedTokensSplits' +import { useCreatingReservedTokensSplits } from 'redux/hooks/v2v3/create' import { formatEnabled, formatPaused } from 'utils/format/formatBoolean' export const useProjectTokenReview = () => { @@ -14,8 +17,8 @@ export const useProjectTokenReview = () => { redemptionRate, global, }, - } = useAppSelector(state => state.editingV2Project) - const [tokenSplits, setTokenSplits] = useEditingReservedTokensSplits() + } = useAppSelector(state => state.creatingV2Project) + const [tokenSplits, setTokenSplits] = useCreatingReservedTokensSplits() const allocationSplits = useMemo( () => tokenSplits.map(splitToAllocation), diff --git a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx index 23c08e274d..fbfa22b23a 100644 --- a/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx +++ b/src/packages/v2v3/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx @@ -4,22 +4,21 @@ import { NftRewardTier } from 'models/nftRewards' import { useCallback, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { formatEnabled } from 'utils/format/formatBoolean' import { v4 } from 'uuid' import { ReviewDescription } from '../ReviewDescription' export const RewardsReview = () => { - const { - nftRewards: { rewardTiers, flags }, - fundingCycleMetadata, - } = useAppSelector(state => state.editingV2Project) + const { nftRewards: nftRewardsData, fundingCycleMetadata } = useAppSelector( + state => state.creatingV2Project, + ) const dispatch = useAppDispatch() const rewards: NftRewardTier[] = useMemo(() => { return ( - rewardTiers?.map(t => ({ + nftRewardsData.rewardTiers?.map(t => ({ id: parseInt(v4()), name: t.name, contributionFloor: t.contributionFloor, @@ -33,12 +32,12 @@ export const RewardsReview = () => { votingWeight: t.votingWeight, })) ?? [] ) - }, [rewardTiers]) + }, [nftRewardsData.rewardTiers]) const setRewards = useCallback( (rewards: NftRewardTier[]) => { dispatch( - editingV2ProjectActions.setNftRewardTiers( + creatingV2ProjectActions.setNftRewardTiers( rewards.map(reward => ({ contributionFloor: reward.contributionFloor, maxSupply: reward.maxSupply, @@ -63,12 +62,16 @@ export const RewardsReview = () => { }, [fundingCycleMetadata.useDataSourceForRedeem]) const preventOverspending = useMemo(() => { - return formatEnabled(flags.preventOverspending) - }, [flags.preventOverspending]) + return formatEnabled(nftRewardsData.flags.preventOverspending) + }, [nftRewardsData.flags.preventOverspending]) return (

- +
{ reconfigurationRuleSelection, fundingCycleMetadata, projectMetadata, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const pausePayments = useMemo(() => { return formatPaused(fundingCycleMetadata.pausePay) diff --git a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts index 75ab2342d8..2b0fd1a462 100644 --- a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts +++ b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts @@ -2,13 +2,13 @@ import { TransactionCallbacks } from 'models/transaction' import { useLaunchProjectWithNftsTx } from 'packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx' import { DEFAULT_JB_721_DELEGATE_VERSION } from 'packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate' import { useCallback, useMemo } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' -import { DEFAULT_NFT_FLAGS } from 'redux/slices/editingV2Project' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' +import { DEFAULT_NFT_FLAGS } from 'redux/slices/creatingV2Project' import { NFT_FUNDING_CYCLE_METADATA_OVERRIDES } from 'utils/nftFundingCycleMetadataOverrides' import { buildJB721TierParams } from 'utils/nftRewards' @@ -28,10 +28,10 @@ export const useDeployNftProject = () => { reservedTokensGroupedSplits, inputProjectOwner, mustStartAtOrAfter, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() const collectionName = useMemo( () => diff --git a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts index 5d38d3d9d3..5dc9700221 100644 --- a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts +++ b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts @@ -6,7 +6,7 @@ import { useAppSelector } from 'redux/hooks/useAppSelector' * @returns Whether the project to be deployed is an NFT project. */ export const useIsNftProject = (): boolean => { - const { nftRewards } = useAppSelector(state => state.editingV2Project) + const { nftRewards } = useAppSelector(state => state.creatingV2Project) return useMemo( () => diff --git a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts index 5b4193e286..2f795a20d1 100644 --- a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts +++ b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts @@ -14,7 +14,7 @@ export const useUploadNftRewards = () => { const { nftRewards, projectMetadata: { name: projectName, logoUri, infoUri }, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) return useCallback(async () => { if (!nftRewards?.rewardTiers || !nftRewards?.collectionMetadata) return diff --git a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts index a3dc8d3be4..dc7cdfb971 100644 --- a/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts +++ b/src/packages/v2v3/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts @@ -1,12 +1,12 @@ import { TransactionCallbacks } from 'models/transaction' import { useLaunchProjectTx } from 'packages/v2v3/hooks/transactor/useLaunchProjectTx' import { useCallback } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' /** * Hook that returns a function that deploys a project. @@ -22,10 +22,10 @@ export const useDeployStandardProject = () => { reservedTokensGroupedSplits, inputProjectOwner, mustStartAtOrAfter, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() const deployStandardProjectCallback = useCallback( async ({ diff --git a/src/packages/v2v3/components/Create/hooks/DeployProject/useDeployProject.ts b/src/packages/v2v3/components/Create/hooks/DeployProject/useDeployProject.ts index fa363ac619..7dfb5ccee4 100644 --- a/src/packages/v2v3/components/Create/hooks/DeployProject/useDeployProject.ts +++ b/src/packages/v2v3/components/Create/hooks/DeployProject/useDeployProject.ts @@ -4,13 +4,13 @@ import { uploadProjectMetadata } from 'lib/api/ipfs' import { TransactionCallbacks } from 'models/transaction' import { useCallback, useState } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { emitErrorNotification } from 'utils/notifications' import { useDeployNftProject } from './hooks/NFT/useDeployNftProject' import { useIsNftProject } from './hooks/NFT/useIsNftProject' @@ -94,10 +94,10 @@ export const useDeployProject = () => { const { projectMetadata, nftRewards: { postPayModal }, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() const dispatch = useAppDispatch() @@ -138,7 +138,7 @@ export const useDeployProject = () => { } // Reset the project state - dispatch(editingV2ProjectActions.resetState()) + dispatch(creatingV2ProjectActions.resetState()) onProjectDeployed?.(projectId) }, onError: error => { diff --git a/src/packages/v2v3/components/Create/hooks/useLoadInitialStateFromQuery.ts b/src/packages/v2v3/components/Create/hooks/useLoadInitialStateFromQuery.ts index a2d3097086..ecd122f276 100644 --- a/src/packages/v2v3/components/Create/hooks/useLoadInitialStateFromQuery.ts +++ b/src/packages/v2v3/components/Create/hooks/useLoadInitialStateFromQuery.ts @@ -11,10 +11,10 @@ import { useEffect, useState } from 'react' import { useDispatch } from 'react-redux' import { DEFAULT_REDUX_STATE, - INITIAL_REDUX_STATE, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' -import { CreateState, ProjectState } from 'redux/slices/editingV2Project/types' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' +import { INITIAL_REDUX_STATE } from 'redux/slices/shared/v2ProjectInitialReduxState' +import { CreateState, ProjectState } from 'redux/slices/shared/v2ProjectTypes' import { isEqualAddress } from 'utils/address' import { parseWad } from 'utils/format/formatNumber' import { DefaultSettings as DefaultTokenSettings } from '../components/pages/ProjectToken/hooks/useProjectTokenForm' @@ -140,7 +140,7 @@ export function useLoadingInitialStateFromQuery() { parseCreateFlowStateFromInitialState(parsedInitialState) dispatch( - editingV2ProjectActions.setState({ + creatingV2ProjectActions.setState({ ...INITIAL_REDUX_STATE, ...createFlowState, ...parsedInitialState, diff --git a/src/packages/v2v3/components/Create/utils/projectTokenSettingsToReduxFormat.ts b/src/packages/v2v3/components/Create/utils/projectTokenSettingsToReduxFormat.ts index de6f55ff2d..fa7d98954e 100644 --- a/src/packages/v2v3/components/Create/utils/projectTokenSettingsToReduxFormat.ts +++ b/src/packages/v2v3/components/Create/utils/projectTokenSettingsToReduxFormat.ts @@ -5,7 +5,7 @@ import { reservedRateFrom, } from 'packages/v2v3/utils/math' import { allocationToSplit } from 'packages/v2v3/utils/splitToAllocation' -import { EMPTY_RESERVED_TOKENS_GROUPED_SPLITS } from 'redux/slices/editingV2Project' +import { EMPTY_RESERVED_TOKENS_GROUPED_SPLITS } from 'redux/slices/creatingV2Project' import { ProjectTokensFormProps } from '../components/pages/ProjectToken/hooks/useProjectTokenForm' export const projectTokenSettingsToReduxFormat = ( diff --git a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/CyclesPayoutsPanel/components/__snapshots__/CurrentUpcomingSubPanel.test.tsx.snap b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/CyclesPayoutsPanel/components/__snapshots__/CurrentUpcomingSubPanel.test.tsx.snap index 6c268782d8..1d0966d067 100644 --- a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/CyclesPayoutsPanel/components/__snapshots__/CurrentUpcomingSubPanel.test.tsx.snap +++ b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/CyclesPayoutsPanel/components/__snapshots__/CurrentUpcomingSubPanel.test.tsx.snap @@ -135,6 +135,27 @@ exports[`CurrentUpcomingSubPanel renders "upcoming" 1`] = `
+
+ + Starts in +
@@ -375,6 +396,27 @@ exports[`CurrentUpcomingSubPanel renders a skeleton when loading "upcoming" 1`]
+
+ + Starts in +
diff --git a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/PayRedeemCard/PayRedeemCard.tsx b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/PayRedeemCard/PayRedeemCard.tsx index c89ea7576b..0ecf599e71 100644 --- a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/PayRedeemCard/PayRedeemCard.tsx +++ b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/PayRedeemCard/PayRedeemCard.tsx @@ -861,23 +861,25 @@ const NftReward: React.FC<{ }, [price]) return ( -
-
+
+
-
+
setProjectPageTab('nft_rewards')} > NFT diff --git a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/SuccessPayView/components/SuccessTokensItem.tsx b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/SuccessPayView/components/SuccessTokensItem.tsx index 4c5b987bb8..d638cfcc38 100644 --- a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/SuccessPayView/components/SuccessTokensItem.tsx +++ b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/SuccessPayView/components/SuccessTokensItem.tsx @@ -21,7 +21,7 @@ export const SuccessTokensItem = () => { Project tokens - Token + Token
{projectPayReceipt.tokensReceived} diff --git a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/TokensPanel/TokensPanel.tsx b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/TokensPanel/TokensPanel.tsx index 8f773394b1..be16c3bdd0 100644 --- a/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/TokensPanel/TokensPanel.tsx +++ b/src/packages/v2v3/components/V2V3Project/ProjectDashboard/components/TokensPanel/TokensPanel.tsx @@ -12,7 +12,6 @@ import { V2V3ClaimTokensModal } from 'packages/v2v3/components/V2V3Project/V2V3M import { V2V3MintModal } from 'packages/v2v3/components/V2V3Project/V2V3ManageTokensSection/AccountBalanceDescription/V2V3MintModal' import { useCallback, useState } from 'react' import { reloadWindow } from 'utils/windowUtils' -import { Hash } from 'viem' import { TokenHoldersModal } from '../TokenHoldersModal/TokenHoldersModal' import { MigrateTokensButton } from './components/MigrateTokensButton' import { RedeemTokensButton } from './components/RedeemTokensButton' @@ -191,7 +190,7 @@ const ProjectTokenCard = () => { {projectTokenAddress && projectHasErc20Token && ( )} {canCreateErc20Token && ( diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useEditingFundingCycleConfig.ts b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useEditingFundingCycleConfig.ts index 35b19119a5..5e367d14c4 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useEditingFundingCycleConfig.ts +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useEditingFundingCycleConfig.ts @@ -7,13 +7,13 @@ import { ETHPayoutGroupedSplits, ReservedTokensGroupedSplits, } from 'packages/v2v3/models/splits' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, useEditingV2V3FundAccessConstraintsSelector, useEditingV2V3FundingCycleDataSelector, useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' +} from 'redux/hooks/v2v3/edit' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' export interface EditingFundingCycleConfig { editingPayoutGroupedSplits: ETHPayoutGroupedSplits diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useInitialEditingData.ts b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useInitialEditingData.ts index d2a9075db0..af2e688ea8 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useInitialEditingData.ts +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useInitialEditingData.ts @@ -25,7 +25,7 @@ import { DEFAULT_MUST_START_AT_OR_AFTER, editingV2ProjectActions, } from 'redux/slices/editingV2Project' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import useDeepCompareEffect from 'use-deep-compare-effect' import { fromWad } from 'utils/format/formatNumber' diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/EditCycleFormFields.ts b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/EditCycleFormFields.ts index 3d7940503d..92327b64fb 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/EditCycleFormFields.ts +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/EditCycleFormFields.ts @@ -1,7 +1,7 @@ import { DurationOption } from 'components/inputs/DurationInput' import { CurrencyName } from 'constants/currency' import { Split } from 'packages/v2v3/models/splits' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' type DetailsSectionFields = { duration: number diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/hooks/usePrepareSaveEditCycleData.tsx b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/hooks/usePrepareSaveEditCycleData.tsx index 4153ce30b5..e2fc94eb6e 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/hooks/usePrepareSaveEditCycleData.tsx +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditCyclePage/hooks/usePrepareSaveEditCycleData.tsx @@ -20,7 +20,7 @@ import { import { BaseV3FundingCycleMetadataGlobal } from 'packages/v3/models/fundingCycle' import { useContext } from 'react' import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { isZeroAddress } from 'utils/address' import { parseWad } from 'utils/format/formatNumber' import { otherUnitToSeconds } from 'utils/format/formatTime' diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx index 29d144f9cd..3c7915e439 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx @@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro' import { Button } from 'antd' import { AddNftCollectionForm } from 'components/NftRewards/AddNftCollectionForm/AddNftCollectionForm' import TransactionModal from 'components/modals/TransactionModal' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { TransactionSuccessModal } from '../../../TransactionSuccessModal' import { useLaunchNftsForm } from './hooks/useLaunchNftsForm' @@ -14,10 +15,20 @@ export function LaunchNftsPage() { successModalOpen, setSuccessModalOpen, } = useLaunchNftsForm() + + const postPayModalData = useAppSelector( + state => state.creatingV2Project.nftRewards.postPayModal, + ) + const nftRewardsData = useAppSelector( + state => state.creatingV2Project.nftRewards, + ) + return ( <> state.editingV2Project.nftRewards.postPayModal, + ) + const editProjectDetailsTx = useEditProjectDetailsTx() const onProjectFormSaved = useCallback(async () => { @@ -82,7 +87,10 @@ export function EditNftsPostPaySection() { return (
- + diff --git a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx index 5871a499f9..00aa83ea6e 100644 --- a/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx +++ b/src/packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx @@ -7,12 +7,16 @@ import { RewardsList } from 'components/NftRewards/RewardsList/RewardsList' import { useUpdateCurrentCollection } from 'packages/v2v3/components/V2V3Project/V2V3ProjectSettings/pages/EditNftsPage/hooks/useUpdateCurrentCollection' import { useHasNftRewards } from 'packages/v2v3/hooks/JB721Delegate/useHasNftRewards' import { useCallback, useState } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { useEditingFundingCycleConfig } from '../../../hooks/useEditingFundingCycleConfig' import { useReconfigureFundingCycle } from '../../../hooks/useReconfigureFundingCycle' import { TransactionSuccessModal } from '../../../TransactionSuccessModal' import { useEditingNfts } from '../hooks/useEditingNfts' export function EditNftsSection() { + const nftRewardsData = useAppSelector( + state => state.editingV2Project.nftRewards, + ) const [submitLoading, setSubmitLoading] = useState(false) const [successModalOpen, setSuccessModalOpen] = useState(false) @@ -64,6 +68,7 @@ export function EditNftsSection() {
void onCancel: VoidFunction splits: Split[] + currency: V2V3CurrencyOption | undefined }) => { - const [distributionLimit] = useEditingDistributionLimit() const [newDistributionLimit, setNewDistributionLimit] = useState('') const [currency, setCurrency] = useState( - distributionLimit?.currency ?? V2V3_CURRENCY_ETH, + c ?? V2V3_CURRENCY_ETH, ) const totalPayoutsPercent = useMemo( diff --git a/src/packages/v2v3/components/shared/PayoutsTable/PayoutTableSettings.tsx b/src/packages/v2v3/components/shared/PayoutsTable/PayoutTableSettings.tsx index 91f21f5d1d..5571cb575d 100644 --- a/src/packages/v2v3/components/shared/PayoutsTable/PayoutTableSettings.tsx +++ b/src/packages/v2v3/components/shared/PayoutsTable/PayoutTableSettings.tsx @@ -4,8 +4,12 @@ import { SwitchToUnlimitedModal } from 'components/PayoutsTable/SwitchToUnlimite import { PopupMenu, PopupMenuItem } from 'components/ui/PopupMenu' import { handleConfirmationDeletion } from 'hooks/emitConfirmationDeletionModal' import { ConvertAmountsModal } from 'packages/v2v3/components/shared/PayoutsTable/ConvertAmountsModal' +import { + V2V3_CURRENCY_ETH, + V2V3_CURRENCY_USD, +} from 'packages/v2v3/utils/currency' import { useState } from 'react' -import { ReduxDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { ReduxDistributionLimit } from 'redux/hooks/v2v3/shared' import { fromWad } from 'utils/format/formatNumber' import { usePayoutsTable } from './hooks/usePayoutsTable' @@ -20,6 +24,7 @@ export function PayoutTableSettings() { const { payoutSplits, + currency, distributionLimitIsInfinite, handleDeleteAllPayoutSplits, setDistributionLimit, @@ -103,6 +108,7 @@ export function PayoutTableSettings() { onOk={handleSwitchToLimitedPayouts} onCancel={() => setSwitchToLimitedModalOpen(false)} splits={payoutSplits} + currency={currency === 'ETH' ? V2V3_CURRENCY_ETH : V2V3_CURRENCY_USD} /> ) diff --git a/src/packages/v2v3/components/shared/PayoutsTable/PayoutsTableBody.tsx b/src/packages/v2v3/components/shared/PayoutsTable/PayoutsTableBody.tsx index 367c92ad48..2e6037aa14 100644 --- a/src/packages/v2v3/components/shared/PayoutsTable/PayoutsTableBody.tsx +++ b/src/packages/v2v3/components/shared/PayoutsTable/PayoutsTableBody.tsx @@ -16,7 +16,8 @@ const Row = PayoutsTableRow const Cell = PayoutsTableCell export function PayoutsTableBody() { - const { topAccessory, hideHeader } = usePayoutsTableContext() + const { topAccessory, hideHeader, createTreasurySelection } = + usePayoutsTableContext() const { payoutSplits, currency, @@ -28,6 +29,11 @@ export function PayoutsTableBody() { const hasDistributionLimit = distributionLimit && distributionLimit > 0 + if (createTreasurySelection === 'zero') { + // TODO: This feels like a hack, this should not be coupled here. + return <>{topAccessory} + } + return ( <> {topAccessory} @@ -59,9 +65,11 @@ export function PayoutsTableBody() { Address or ID - {hasDistributionLimit ? - - : Percent} + {hasDistributionLimit ? ( + + ) : ( + Percent + )} ) : null} {payoutSplits.map((payoutSplit, index) => ( diff --git a/src/packages/v2v3/components/shared/PayoutsTable/context/PayoutsTableContext.tsx b/src/packages/v2v3/components/shared/PayoutsTable/context/PayoutsTableContext.tsx index 3ee6000eba..5453075780 100644 --- a/src/packages/v2v3/components/shared/PayoutsTable/context/PayoutsTableContext.tsx +++ b/src/packages/v2v3/components/shared/PayoutsTable/context/PayoutsTableContext.tsx @@ -1,4 +1,5 @@ import { CurrencyName } from 'constants/currency' +import { TreasurySelection } from 'models/treasurySelection' import { Split } from 'packages/v2v3/models/splits' import { ReactNode, createContext, useContext } from 'react' @@ -9,12 +10,15 @@ export interface PayoutsTableContextProps { setCurrency?: (currency: CurrencyName) => void distributionLimit: number | undefined setDistributionLimit?: (distributionLimit: number | undefined) => void + hideExplaination?: boolean hideHeader?: boolean showAvatars?: boolean topAccessory?: ReactNode hideSettings?: boolean addPayoutsDisabled?: boolean + // TODO: Hack to allow the create payouts table to hide data if set to none. + createTreasurySelection?: TreasurySelection } export const PayoutsTableContext = createContext< diff --git a/src/packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext.ts b/src/packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext.ts index 5af4ca0bba..60784a8216 100644 --- a/src/packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext.ts +++ b/src/packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext.ts @@ -1,5 +1,5 @@ import { Contract } from 'ethers' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { createContext } from 'react' interface JB721DelegateContracts { diff --git a/src/packages/v2v3/contexts/NftRewards/NftRewardsContext.ts b/src/packages/v2v3/contexts/NftRewards/NftRewardsContext.ts index 8bfd7394fc..a7d72df221 100644 --- a/src/packages/v2v3/contexts/NftRewards/NftRewardsContext.ts +++ b/src/packages/v2v3/contexts/NftRewards/NftRewardsContext.ts @@ -4,8 +4,8 @@ import { DEFAULT_NFT_FLAGS, DEFAULT_NFT_PRICING, EMPTY_NFT_COLLECTION_METADATA, -} from 'redux/slices/editingV2Project' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' +} from 'redux/slices/shared/v2ProjectDefaultState' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' type NftRewardsContextType = { nftRewards: NftRewardsData diff --git a/src/packages/v2v3/contexts/NftRewards/NftRewardsProvider.tsx b/src/packages/v2v3/contexts/NftRewards/NftRewardsProvider.tsx index b4a4443a76..9a45761c0d 100644 --- a/src/packages/v2v3/contexts/NftRewards/NftRewardsProvider.tsx +++ b/src/packages/v2v3/contexts/NftRewards/NftRewardsProvider.tsx @@ -12,7 +12,7 @@ import { DEFAULT_NFT_FLAGS, DEFAULT_NFT_PRICING, EMPTY_NFT_COLLECTION_METADATA, -} from 'redux/slices/editingV2Project' +} from 'redux/slices/shared/v2ProjectDefaultState' import { CIDsOfNftRewardTiersResponse } from 'utils/nftRewards' import { JB721DelegateContractsContext } from './JB721DelegateContracts/JB721DelegateContractsContext' diff --git a/src/packages/v2v3/contexts/Project/V2V3ProjectContext.ts b/src/packages/v2v3/contexts/Project/V2V3ProjectContext.ts index 146897f735..37a2cfb171 100644 --- a/src/packages/v2v3/contexts/Project/V2V3ProjectContext.ts +++ b/src/packages/v2v3/contexts/Project/V2V3ProjectContext.ts @@ -19,7 +19,7 @@ interface V2V3ProjectLoadingStates { export type V2V3ProjectContextType = { handle: string | undefined createdAt: number | undefined - tokenAddress: string | undefined + tokenAddress: `0x${string}` | undefined tokenSymbol: string | undefined tokenName: string | undefined terminals: string[] | undefined // array of terminal addresses, 0xABC... diff --git a/src/packages/v2v3/contexts/Project/useV2V3ProjectState.ts b/src/packages/v2v3/contexts/Project/useV2V3ProjectState.ts index 70a19c2e17..1f0e52f06a 100644 --- a/src/packages/v2v3/contexts/Project/useV2V3ProjectState.ts +++ b/src/packages/v2v3/contexts/Project/useV2V3ProjectState.ts @@ -238,7 +238,7 @@ export function useV2V3ProjectState({ projectId }: { projectId: number }) { balanceInDistributionLimitCurrency, // token data - tokenAddress, + tokenAddress: tokenAddress as `0x${string}`, tokenSymbol, tokenName, totalTokenSupply, diff --git a/src/packages/v2v3/contexts/V2V3ProjectOFACProvider.tsx b/src/packages/v2v3/contexts/V2V3ProjectOFACProvider.tsx index 8d3ea1b460..70bfb6ac3d 100644 --- a/src/packages/v2v3/contexts/V2V3ProjectOFACProvider.tsx +++ b/src/packages/v2v3/contexts/V2V3ProjectOFACProvider.tsx @@ -6,7 +6,7 @@ import { ReactNode, createContext } from 'react' interface ProjectOFACContextType { isLoading?: boolean - isAddressListedInOFAC?: boolean + isAddressListedInOFAC?: boolean | null } export const ProjectOFACContext = createContext({ @@ -28,7 +28,7 @@ export default function V2V3ProjectOFACProvider({ queryKey: ['isAddressListedInOFAC', userAddress], queryFn: async () => { if (!enabled) { - return + return null } try { diff --git a/src/packages/v2v3/hooks/JB721Delegate/JB721DelegateVersion/useJB721DelegateVersion.ts b/src/packages/v2v3/hooks/JB721Delegate/JB721DelegateVersion/useJB721DelegateVersion.ts index 4a3b25ce62..19be67c98f 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/JB721DelegateVersion/useJB721DelegateVersion.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/JB721DelegateVersion/useJB721DelegateVersion.ts @@ -1,6 +1,6 @@ import { useQuery } from '@tanstack/react-query' import axios from 'axios' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { isZeroAddress } from 'utils/address' export function useJB721DelegateVersion({ diff --git a/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionMetadataUri.ts b/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionMetadataUri.ts index 75aa64f5d6..1fc3766540 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionMetadataUri.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftCollectionMetadataUri.ts @@ -1,6 +1,6 @@ +import { JB721DelegateVersion } from 'models/JB721Delegate' import { JB721DelegateContractsContext } from 'packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext' import useV2ContractReader from 'packages/v2v3/hooks/contractReader/useV2ContractReader' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { useContext } from 'react' export function useNftCollectionMetadataUri( diff --git a/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftTiers.ts b/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftTiers.ts index 8698d08f38..649e608bb3 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftTiers.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contractReader/useNftTiers.ts @@ -1,8 +1,9 @@ import { JB721TierV3, JB_721_TIER_V3_2 } from 'models/nftRewards' + +import { JB721DelegateVersion } from 'models/JB721Delegate' import { MAX_NFT_REWARD_TIERS } from 'packages/v2v3/constants/nftRewards' import { JB721DelegateContractsContext } from 'packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext' import useV2ContractReader from 'packages/v2v3/hooks/contractReader/useV2ContractReader' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { useContext } from 'react' function buildArgs( diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi.ts index b8fe9e5f3d..f73e174fa3 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi.ts @@ -1,6 +1,6 @@ import { ContractInterface } from 'ethers' import { ContractJson } from 'models/contracts' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { useEffect, useState } from 'react' type JB721DelegateContractName = diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateContractAddress.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateContractAddress.ts index d883ebe226..ac44e42a3d 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateContractAddress.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateContractAddress.ts @@ -1,7 +1,7 @@ import { readNetwork } from 'constants/networks' import { ForgeDeploy, addressFor } from 'forge-run-parser' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { NetworkName } from 'models/networkName' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { useEffect, useState } from 'react' /** diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegate.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegate.ts index 2542213e49..2b690fc91b 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegate.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegate.ts @@ -1,6 +1,6 @@ import { Contract } from 'ethers' import { useLoadContractFromAddress } from 'hooks/useLoadContractFromAddress' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { useJB721DelegateAbi } from './useJB721DelegateAbi' export function useJB721TieredDelegate({ diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegateStore.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegateStore.ts index 46f2cc9261..0b6b9b260a 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegateStore.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJB721TieredDelegateStore.ts @@ -1,6 +1,6 @@ import { Contract } from 'ethers' import { useLoadContractFromAddress } from 'hooks/useLoadContractFromAddress' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { useJB721DelegateAbi } from './useJB721DelegateAbi' export function useJB721TieredDelegateStore({ diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJBTiered721DelegateProjectDeployer.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJBTiered721DelegateProjectDeployer.ts index 00998b448a..a888dfe62f 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useJBTiered721DelegateProjectDeployer.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useJBTiered721DelegateProjectDeployer.ts @@ -1,7 +1,7 @@ import { Contract } from 'ethers' import { useLoadContractFromAddress } from 'hooks/useLoadContractFromAddress' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { useJB721DelegateAbi } from 'packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { useJB721DelegateContractAddress } from './useJB721DelegateContractAddress' export function useJBTiered721DelegateProjectDeployer({ diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useProjectJB721DelegateVersion.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useProjectJB721DelegateVersion.ts index 28bdf37e79..94e178aee6 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useProjectJB721DelegateVersion.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useProjectJB721DelegateVersion.ts @@ -1,9 +1,9 @@ -import { V2V3ProjectContractsContext } from 'packages/v2v3/contexts/ProjectContracts/V2V3ProjectContractsContext' import { DEFAULT_JB_721_DELEGATE_VERSION } from 'packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { - JB721DelegateVersion, V2V3ContractName, } from 'packages/v2v3/models/contracts' +import { V2V3ProjectContractsContext } from 'packages/v2v3/contexts/ProjectContracts/V2V3ProjectContractsContext' import { useContext } from 'react' /** diff --git a/src/packages/v2v3/hooks/JB721Delegate/contracts/useStoreofJB721TieredDelegate.ts b/src/packages/v2v3/hooks/JB721Delegate/contracts/useStoreofJB721TieredDelegate.ts index dc0392b183..d123a2ece8 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/contracts/useStoreofJB721TieredDelegate.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/contracts/useStoreofJB721TieredDelegate.ts @@ -1,6 +1,6 @@ import { Contract } from 'ethers' import { useContractReadValue } from 'hooks/ContractReader' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { useJB721TieredDelegateStore } from './useJB721TieredDelegateStore' export function useStoreOfJB721TieredDelegate({ diff --git a/src/packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts b/src/packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts index facc3450c3..56d59ea47a 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts @@ -1,11 +1,4 @@ -import { t } from '@lingui/macro' -import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' -import { DEFAULT_MEMO } from 'constants/transactionDefaults' -import { TransactionContext } from 'contexts/Transaction/TransactionContext' -import { getAddress } from 'ethers/lib/utils' -import { useWallet } from 'hooks/Wallet' -import { TransactorInstance } from 'hooks/useTransactor' -import omit from 'lodash/omit' +import { GroupedSplits, SplitGroup } from 'packages/v2v3/models/splits' import { JB721GovernanceType, JB721TierParams, @@ -13,30 +6,37 @@ import { JBTiered721Flags, JB_721_TIER_PARAMS_V3_1, JB_721_TIER_PARAMS_V3_2, + JB_721_TIER_PARAMS_V4, JB_DEPLOY_TIERED_721_DELEGATE_DATA_V3_1, } from 'models/nftRewards' -import { V2V3ContractsContext } from 'packages/v2v3/contexts/Contracts/V2V3ContractsContext' -import { useJBPrices } from 'packages/v2v3/hooks/JBPrices' -import { DEFAULT_JB_721_DELEGATE_VERSION } from 'packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate' -import { useDefaultJBController } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBController' -import { useDefaultJBETHPaymentTerminal } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBETHPaymentTerminal' -import { LaunchV2V3ProjectData } from 'packages/v2v3/hooks/transactor/useLaunchProjectTx' -import { useV2ProjectTitle } from 'packages/v2v3/hooks/useProjectTitle' -import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' import { JBPayDataSourceFundingCycleMetadata, V2V3FundAccessConstraint, V2V3FundingCycleData, } from 'packages/v2v3/models/fundingCycle' -import { GroupedSplits, SplitGroup } from 'packages/v2v3/models/splits' -import { - isValidMustStartAtOrAfter -} from 'packages/v2v3/utils/fundingCycle' -import { useContext } from 'react' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' + +import { DEFAULT_JB_721_DELEGATE_VERSION } from 'packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate' +import { DEFAULT_MEMO } from 'constants/transactionDefaults' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' +import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' +import { LaunchV2V3ProjectData } from 'packages/v2v3/hooks/transactor/useLaunchProjectTx' +import { TransactionContext } from 'contexts/Transaction/TransactionContext' +import { TransactorInstance } from 'hooks/useTransactor' +import { V2V3ContractsContext } from 'packages/v2v3/contexts/Contracts/V2V3ContractsContext' +import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' import { buildDeployTiered721DelegateData } from 'utils/nftRewards' +import { getAddress } from 'ethers/lib/utils' +import { isValidMustStartAtOrAfter } from 'packages/v2v3/utils/fundingCycle' +import omit from 'lodash/omit' +import { t } from '@lingui/macro' +import { useContext } from 'react' +import { useDefaultJBController } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBController' +import { useDefaultJBETHPaymentTerminal } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBETHPaymentTerminal' import { useJB721DelegateContractAddress } from '../contracts/useJB721DelegateContractAddress' +import { useJBPrices } from 'packages/v2v3/hooks/JBPrices' import { useJBTiered721DelegateProjectDeployer } from '../contracts/useJBTiered721DelegateProjectDeployer' +import { useV2ProjectTitle } from 'packages/v2v3/hooks/useProjectTitle' +import { useWallet } from 'hooks/Wallet' interface DeployTiered721DelegateData { collectionUri: string @@ -44,7 +44,7 @@ interface DeployTiered721DelegateData { collectionSymbol: string currency: V2V3CurrencyOption governanceType: JB721GovernanceType - tiers: (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2)[] + tiers: (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2 | JB_721_TIER_PARAMS_V4)[] flags: JBTiered721Flags } diff --git a/src/packages/v2v3/hooks/JB721Delegate/transactor/useReconfigureV2V3FundingCycleWithNftsTx.ts b/src/packages/v2v3/hooks/JB721Delegate/transactor/useReconfigureV2V3FundingCycleWithNftsTx.ts index de53a7fbdd..78a3762644 100644 --- a/src/packages/v2v3/hooks/JB721Delegate/transactor/useReconfigureV2V3FundingCycleWithNftsTx.ts +++ b/src/packages/v2v3/hooks/JB721Delegate/transactor/useReconfigureV2V3FundingCycleWithNftsTx.ts @@ -1,36 +1,37 @@ +import { + JBDeployTiered721DelegateData, + JB_DEPLOY_TIERED_721_DELEGATE_DATA_V3_1, +} from 'models/nftRewards' +import { + JBPayDataSourceFundingCycleMetadata, + V2V3FundAccessConstraint, + V2V3FundingCycleData, +} from 'packages/v2v3/models/fundingCycle' +import { GroupedSplits, SplitGroup } from 'packages/v2v3/models/splits' +import { + buildDeployTiered721DelegateData, + buildJB721TierParams, + defaultNftCollectionName, +} from 'utils/nftRewards' + import { t } from '@lingui/macro' import { ProjectMetadataContext } from 'contexts/ProjectMetadataContext' import { TransactionContext } from 'contexts/Transaction/TransactionContext' import { getAddress } from 'ethers/lib/utils' import { TransactorInstance } from 'hooks/useTransactor' import omit from 'lodash/omit' -import { - JBDeployTiered721DelegateData, - JB_DEPLOY_TIERED_721_DELEGATE_DATA_V3_1, -} from 'models/nftRewards' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { V2V3ContractsContext } from 'packages/v2v3/contexts/Contracts/V2V3ContractsContext' import { V2V3ProjectContext } from 'packages/v2v3/contexts/Project/V2V3ProjectContext' import { V2V3ProjectContractsContext } from 'packages/v2v3/contexts/ProjectContracts/V2V3ProjectContractsContext' import { useJBPrices } from 'packages/v2v3/hooks/JBPrices' import { ReconfigureFundingCycleTxParams } from 'packages/v2v3/hooks/transactor/useReconfigureV2V3FundingCycleTx' import { useV2ProjectTitle } from 'packages/v2v3/hooks/useProjectTitle' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' -import { - JBPayDataSourceFundingCycleMetadata, - V2V3FundAccessConstraint, - V2V3FundingCycleData, -} from 'packages/v2v3/models/fundingCycle' -import { GroupedSplits, SplitGroup } from 'packages/v2v3/models/splits' import { V2V3_CURRENCY_ETH } from 'packages/v2v3/utils/currency' import { isValidMustStartAtOrAfter } from 'packages/v2v3/utils/fundingCycle' import { useContext } from 'react' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' -import { NftRewardsData } from 'redux/slices/editingV2Project/types' -import { - buildDeployTiered721DelegateData, - buildJB721TierParams, - defaultNftCollectionName, -} from 'utils/nftRewards' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' import { useJB721DelegateContractAddress } from '../contracts/useJB721DelegateContractAddress' import { useJBTiered721DelegateProjectDeployer } from '../contracts/useJBTiered721DelegateProjectDeployer' import { useProjectControllerJB721DelegateVersion } from '../contracts/useProjectJB721DelegateVersion' diff --git a/src/packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate.ts b/src/packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate.ts index e64f8661cd..432d0b72bd 100644 --- a/src/packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate.ts +++ b/src/packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate.ts @@ -1,4 +1,4 @@ -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' +import { JB721DelegateVersion } from 'models/JB721Delegate' /** * The version of the JB721Delegate contracts (NFT Rewards) that should be used to launch projects, funding cycles, etc. diff --git a/src/packages/v2v3/hooks/transactor/useLaunchProjectTx.ts b/src/packages/v2v3/hooks/transactor/useLaunchProjectTx.ts index 092e850a70..d41bb30766 100644 --- a/src/packages/v2v3/hooks/transactor/useLaunchProjectTx.ts +++ b/src/packages/v2v3/hooks/transactor/useLaunchProjectTx.ts @@ -13,11 +13,9 @@ import { V2V3FundingCycleMetadata, } from 'packages/v2v3/models/fundingCycle' import { GroupedSplits, SplitGroup } from 'packages/v2v3/models/splits' -import { - isValidMustStartAtOrAfter -} from 'packages/v2v3/utils/fundingCycle' +import { isValidMustStartAtOrAfter } from 'packages/v2v3/utils/fundingCycle' import { useContext } from 'react' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' import { useV2ProjectTitle } from '../useProjectTitle' export interface LaunchV2V3ProjectData { diff --git a/src/packages/v2v3/hooks/transactor/useReconfigureNftCollectionMetadata.ts b/src/packages/v2v3/hooks/transactor/useReconfigureNftCollectionMetadata.ts index f4bb514c10..b5c9c4d00f 100644 --- a/src/packages/v2v3/hooks/transactor/useReconfigureNftCollectionMetadata.ts +++ b/src/packages/v2v3/hooks/transactor/useReconfigureNftCollectionMetadata.ts @@ -1,14 +1,16 @@ import * as constants from '@ethersproject/constants' + +import { cidFromUrl, encodeIpfsUri, ipfsUri } from 'utils/ipfs' + import { t } from '@lingui/macro' import { ProjectMetadataContext } from 'contexts/ProjectMetadataContext' import { TransactionContext } from 'contexts/Transaction/TransactionContext' import { useDefaultTokenUriResolver } from 'hooks/DefaultTokenUriResolver/contracts/useDefaultTokenUriResolver' import { TransactorInstance } from 'hooks/useTransactor' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { NftCollectionMetadata } from 'models/nftRewards' import { JB721DelegateContractsContext } from 'packages/v2v3/contexts/NftRewards/JB721DelegateContracts/JB721DelegateContractsContext' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { useContext } from 'react' -import { cidFromUrl, encodeIpfsUri, ipfsUri } from 'utils/ipfs' import { pinNftCollectionMetadata } from 'utils/nftRewards' import { useV2ProjectTitle } from '../useProjectTitle' diff --git a/src/packages/v2v3/hooks/transactor/useReconfigureV2V3FundingCycleTx.ts b/src/packages/v2v3/hooks/transactor/useReconfigureV2V3FundingCycleTx.ts index ca4b0c94ac..68b0e7d0fb 100644 --- a/src/packages/v2v3/hooks/transactor/useReconfigureV2V3FundingCycleTx.ts +++ b/src/packages/v2v3/hooks/transactor/useReconfigureV2V3FundingCycleTx.ts @@ -6,7 +6,7 @@ import { TransactorInstance } from 'hooks/useTransactor' import { V2V3ProjectContractsContext } from 'packages/v2v3/contexts/ProjectContracts/V2V3ProjectContractsContext' import { isValidMustStartAtOrAfter } from 'packages/v2v3/utils/fundingCycle' import { useContext } from 'react' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' import { useV2ProjectTitle } from '../useProjectTitle' import { LaunchV2V3ProjectData } from './useLaunchProjectTx' diff --git a/src/packages/v2v3/models/contracts.ts b/src/packages/v2v3/models/contracts.ts index 1412219a24..48de68ee25 100644 --- a/src/packages/v2v3/models/contracts.ts +++ b/src/packages/v2v3/models/contracts.ts @@ -74,11 +74,3 @@ export const SUPPORTED_CONTROLLERS = [ V2V3ContractName.JBController3_1, ] as const export type ControllerVersion = (typeof SUPPORTED_CONTROLLERS)[number] - -export enum JB721DelegateVersion { - JB721DELEGATE_V3 = '3', - JB721DELEGATE_V3_1 = '3-1', - JB721DELEGATE_V3_2 = '3-2', - JB721DELEGATE_V3_3 = '3-3', - JB721DELEGATE_V3_4 = '3-4', -} diff --git a/src/packages/v2v3/utils/csv.ts b/src/packages/v2v3/utils/csv.ts index 761bbb1237..b8d650bb55 100644 --- a/src/packages/v2v3/utils/csv.ts +++ b/src/packages/v2v3/utils/csv.ts @@ -1,4 +1,4 @@ -import { getAddress } from 'viem' +import { getAddress } from 'ethers/lib/utils' import { Split } from '../models/splits' import { splitPercentFrom } from './math' diff --git a/src/packages/v4/components/Create/Create.tsx b/src/packages/v4/components/Create/Create.tsx index e4bd960031..12d0fe009e 100644 --- a/src/packages/v4/components/Create/Create.tsx +++ b/src/packages/v4/components/Create/Create.tsx @@ -10,7 +10,9 @@ import Loading from 'components/Loading' import { readNetwork } from 'constants/networks' import { NetworkName } from 'models/networkName' import { useRouter } from 'next/router' +import { CreateBadge } from './components/CreateBadge' import { FundingCyclesPage } from './components/pages/FundingCycles/FundingCyclesPage' +import { NftRewardsPage } from './components/pages/NftRewards/NftRewardsPage' import { PayoutsPage } from './components/pages/PayoutsPage/PayoutsPage' import { ProjectDetailsPage } from './components/pages/ProjectDetails/ProjectDetailsPage' import { ProjectTokenPage } from './components/pages/ProjectToken/ProjectTokenPage' @@ -86,7 +88,7 @@ export function Create() { > - {/* @@ -99,7 +101,7 @@ export function Create() { } > - */} + Edit Deadline} diff --git a/src/packages/v4/components/Create/components/Wizard/hooks/usePage.ts b/src/packages/v4/components/Create/components/Wizard/hooks/usePage.ts index ca1573a61b..164f6bc00f 100644 --- a/src/packages/v4/components/Create/components/Wizard/hooks/usePage.ts +++ b/src/packages/v4/components/Create/components/Wizard/hooks/usePage.ts @@ -1,7 +1,7 @@ import { CreatePage } from 'models/createPage' import { useCallback, useContext, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { WizardContext } from '../contexts/WizardContext' export const usePage = ({ name }: { name: string }) => { @@ -41,14 +41,14 @@ export const usePage = ({ name }: { name: string }) => { const lockPageProgress = useCallback(() => { dispatch( - editingV2ProjectActions.addCreateSoftLockedPage(name as CreatePage), + creatingV2ProjectActions.addCreateSoftLockedPage(name as CreatePage), ) }, [dispatch, name]) const unlockPageProgress = useCallback(() => { // We need to make sure pages can't unsoftlock other pages :\ dispatch( - editingV2ProjectActions.removeCreateSoftLockedPage(name as CreatePage), + creatingV2ProjectActions.removeCreateSoftLockedPage(name as CreatePage), ) }, [dispatch, name]) diff --git a/src/packages/v4/components/Create/components/Wizard/hooks/useSteps.ts b/src/packages/v4/components/Create/components/Wizard/hooks/useSteps.ts index 2c58a52f47..a777e09d0b 100644 --- a/src/packages/v4/components/Create/components/Wizard/hooks/useSteps.ts +++ b/src/packages/v4/components/Create/components/Wizard/hooks/useSteps.ts @@ -1,6 +1,7 @@ +import { useCallback, useContext, useMemo } from 'react' + import { t } from '@lingui/macro' import { CreatePage } from 'models/createPage' -import { useCallback, useContext, useMemo } from 'react' import { useAppSelector } from 'redux/hooks/useAppSelector' import { useEditingCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' import { WizardContext } from '../contexts/WizardContext' @@ -11,7 +12,7 @@ const stepNames = (): Record => { fundingCycles: t`Rulesets`, payouts: t`Payouts`, projectToken: t`Token`, - // nftRewards: t`NFTs`, + nftRewards: t`NFTs`, reconfigurationRules: t`Deadline`, reviewDeploy: t`Deploy`, } @@ -21,7 +22,7 @@ export const useSteps = () => { const { pages, currentPage, goToPage } = useContext(WizardContext) const { furthestPageReached } = useEditingCreateFurthestPageReached() const softLockedPageQueue = useAppSelector( - state => state.editingV2Project.createSoftLockPageQueue, + state => state.creatingV2Project.createSoftLockPageQueue, ) const firstIndexOfLockedPage = useMemo(() => { diff --git a/src/packages/v4/components/Create/components/Wizard/hooks/useWizard.ts b/src/packages/v4/components/Create/components/Wizard/hooks/useWizard.ts index b14c816043..fb995801e9 100644 --- a/src/packages/v4/components/Create/components/Wizard/hooks/useWizard.ts +++ b/src/packages/v4/components/Create/components/Wizard/hooks/useWizard.ts @@ -13,7 +13,7 @@ export const useWizard = ({ children }: { children?: any[] }) => { const [currentPage, setCurrentPage] = useState('') const { furthestPageReached } = useEditingCreateFurthestPageReached() const softLockedPageQueue = useAppSelector( - state => state.editingV2Project.createSoftLockPageQueue, + state => state.creatingV2Project.createSoftLockPageQueue, ) const pages: PageProps[] = useMemo(() => { diff --git a/src/packages/v4/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts b/src/packages/v4/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts index 50593d7694..bbebd8ff6d 100644 --- a/src/packages/v4/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts +++ b/src/packages/v4/components/Create/components/pages/FundingCycles/hooks/useFundingCyclesForm.ts @@ -6,8 +6,8 @@ import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' import { DEFAULT_MUST_START_AT_OR_AFTER, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' import { deriveDurationUnit, otherUnitToSeconds, @@ -23,7 +23,7 @@ export type FundingCyclesFormProps = Partial<{ export const useFundingCyclesForm = () => { const [form] = useForm() const { fundingCycleData, fundingCyclesPageSelection, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) + useAppSelector(state => state.creatingV2Project) useDebugValue(form.getFieldsValue()) const initialValues: FundingCyclesFormProps | undefined = useMemo(() => { @@ -63,17 +63,17 @@ export const useFundingCyclesForm = () => { const launchDate = useWatch('launchDate', form) useEffect(() => { - dispatch(editingV2ProjectActions.setFundingCyclesPageSelection(selection)) + dispatch(creatingV2ProjectActions.setFundingCyclesPageSelection(selection)) // We need to handle manual case first as duration might be undefined, but // manual set. if (selection === 'manual') { - dispatch(editingV2ProjectActions.setDuration('0')) + dispatch(creatingV2ProjectActions.setDuration('0')) return } if (!selection || duration?.duration === undefined) { - dispatch(editingV2ProjectActions.setDuration('')) + dispatch(creatingV2ProjectActions.setDuration('')) return } if (selection === 'automated') { @@ -81,7 +81,7 @@ export const useFundingCyclesForm = () => { duration: duration.duration, unit: duration.unit, }) - dispatch(editingV2ProjectActions.setDuration(newDuration.toString())) + dispatch(creatingV2ProjectActions.setDuration(newDuration.toString())) return } }, [selection, duration, dispatch]) @@ -90,14 +90,14 @@ export const useFundingCyclesForm = () => { if (launchDate === undefined) return if (launchDate === null || !launchDate.unix().toString()) { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( DEFAULT_MUST_START_AT_OR_AFTER, ), ) return } dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( launchDate?.unix().toString(), ), ) diff --git a/src/packages/v4/components/Create/components/pages/NftRewards/NftRewardsPage.tsx b/src/packages/v4/components/Create/components/pages/NftRewards/NftRewardsPage.tsx index 79b9e9612c..40aaf02b0b 100644 --- a/src/packages/v4/components/Create/components/pages/NftRewards/NftRewardsPage.tsx +++ b/src/packages/v4/components/Create/components/pages/NftRewards/NftRewardsPage.tsx @@ -2,6 +2,7 @@ import { AddNftCollectionForm } from 'components/NftRewards/AddNftCollectionForm import { CREATE_FLOW } from 'constants/fathomEvents' import { trackFathomGoal } from 'lib/fathom' import { useContext } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' import { Wizard } from '../../Wizard/Wizard' import { PageContext } from '../../Wizard/contexts/PageContext' @@ -11,12 +12,22 @@ export function NftRewardsPage() { const { goToNextPage } = useContext(PageContext) const { form, initialValues } = useCreateFlowNftRewardsForm() + + const postPayModalData = useAppSelector( + state => state.creatingV2Project.nftRewards.postPayModal, + ) + const nftRewardsData = useAppSelector( + state => state.creatingV2Project.nftRewards, + ) + useSetCreateFurthestPageReached('nftRewards') return ( } onFinish={() => { goToNextPage?.() diff --git a/src/packages/v4/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts b/src/packages/v4/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts index e308334d8a..4bd4f9a295 100644 --- a/src/packages/v4/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts +++ b/src/packages/v4/components/Create/components/pages/NftRewards/hooks/useCreateFlowNftRewardsForm.ts @@ -4,7 +4,7 @@ import { NftRewardTier } from 'models/nftRewards' import { useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { withHttps, withoutHttp } from 'utils/externalLink' import { defaultNftCollectionDescription, @@ -20,9 +20,9 @@ export const useCreateFlowNftRewardsForm = () => { postPayModal, governanceType, flags, - } = useAppSelector(state => state.editingV2Project.nftRewards) + } = useAppSelector(state => state.creatingV2Project.nftRewards) const { projectMetadata, fundingCycleMetadata } = useAppSelector( - state => state.editingV2Project, + state => state.creatingV2Project, ) const initialValues: NftRewardsFormProps = useMemo(() => { const collectionName = @@ -79,7 +79,7 @@ export const useCreateFlowNftRewardsForm = () => { fieldName: 'rewards', ignoreUndefined: true, // Needed to stop an infinite loop currentValue: rewardTiers, - dispatchFunction: editingV2ProjectActions.setNftRewardTiers, + dispatchFunction: creatingV2ProjectActions.setNftRewardTiers, formatter: v => { if (!v) return [] if (typeof v !== 'object') { @@ -106,7 +106,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'collectionName', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftRewardsName, + dispatchFunction: creatingV2ProjectActions.setNftRewardsName, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -117,7 +117,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'collectionSymbol', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftRewardsSymbol, + dispatchFunction: creatingV2ProjectActions.setNftRewardsSymbol, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -129,7 +129,7 @@ export const useCreateFlowNftRewardsForm = () => { fieldName: 'collectionDescription', ignoreUndefined: true, dispatchFunction: - editingV2ProjectActions.setNftRewardsCollectionDescription, + creatingV2ProjectActions.setNftRewardsCollectionDescription, formatter: v => { if (!v || typeof v !== 'string') return '' return v @@ -140,7 +140,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'useDataSourceForRedeem', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setUseDataSourceForRedeem, + dispatchFunction: creatingV2ProjectActions.setUseDataSourceForRedeem, formatter: v => !!v, }) @@ -148,7 +148,7 @@ export const useCreateFlowNftRewardsForm = () => { form, fieldName: 'preventOverspending', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setNftPreventOverspending, + dispatchFunction: creatingV2ProjectActions.setNftPreventOverspending, formatter: v => !!v, }) @@ -178,11 +178,11 @@ export const useCreateFlowNftRewardsForm = () => { postPayButtonText === undefined && postPayButtonLink === undefined ) { - dispatch(editingV2ProjectActions.setNftPostPayModalConfig(undefined)) + dispatch(creatingV2ProjectActions.setNftPostPayModalConfig(undefined)) return } dispatch( - editingV2ProjectActions.setNftPostPayModalConfig({ + creatingV2ProjectActions.setNftPostPayModalConfig({ content: postPayMessage, ctaText: postPayButtonText, ctaLink: withHttps(postPayButtonLink), diff --git a/src/packages/v4/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx b/src/packages/v4/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx index 8cba9c606d..c2e2563baf 100644 --- a/src/packages/v4/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx +++ b/src/packages/v4/components/Create/components/pages/PayoutsPage/PayoutsPage.tsx @@ -1,4 +1,5 @@ import { useContext } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' import { Wizard } from '../../Wizard/Wizard' import { PageContext } from '../../Wizard/contexts/PageContext' @@ -6,11 +7,15 @@ import { CreateFlowPayoutsTable } from './components/CreateFlowPayoutsTable' import { TreasuryOptionsRadio } from './components/TreasuryOptionsRadio' export const PayoutsPage = () => { + const treasurySelection = useAppSelector( + state => state.creatingV2Project.treasurySelection, + ) useSetCreateFurthestPageReached('payouts') const { goToNextPage } = useContext(PageContext) return ( { goToNextPage?.() }} diff --git a/src/packages/v4/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx b/src/packages/v4/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx index 8dc36c16ce..204b0260ef 100644 --- a/src/packages/v4/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx +++ b/src/packages/v4/components/Create/components/pages/PayoutsPage/components/CreateFlowPayoutsTable.tsx @@ -1,6 +1,7 @@ import { Form } from 'antd' import { CURRENCY_METADATA, CurrencyName } from 'constants/currency' import { BigNumber } from 'ethers' +import { TreasurySelection } from 'models/treasurySelection' import { PayoutsTable } from 'packages/v2v3/components/shared/PayoutsTable/PayoutsTable' import { Split } from 'packages/v2v3/models/splits' import { @@ -13,7 +14,7 @@ import { } from 'packages/v2v3/utils/splitToAllocation' import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' import { ReactNode } from 'react' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' import { fromWad, parseWad } from 'utils/format/formatNumber' import { usePayoutsForm } from '../hooks/usePayoutsForm' @@ -24,25 +25,29 @@ export function CreateFlowPayoutsTable({ topAccessory, okButton, addPayoutsDisabled, + createTreasurySelection, }: { onFinish?: VoidFunction okButton?: ReactNode topAccessory?: ReactNode addPayoutsDisabled?: boolean + // TODO: Hack to allow payout recipients to be shown on review but not on create page + // When zero, hides the recipients, but undefined still shows them + createTreasurySelection?: TreasurySelection }) { const [ - editingDistributionLimit, + creatingDistributionLimit, , setDistributionLimitAmount, setDistributionLimitCurrency, - ] = useEditingDistributionLimit() + ] = useCreatingDistributionLimit() const { form, initialValues } = usePayoutsForm() - const distributionLimit = !editingDistributionLimit + const distributionLimit = !creatingDistributionLimit ? 0 - : editingDistributionLimit.amount.eq(MAX_PAYOUT_LIMIT) + : creatingDistributionLimit.amount.eq(MAX_PAYOUT_LIMIT) ? undefined - : parseFloat(fromWad(editingDistributionLimit?.amount)) + : parseFloat(fromWad(creatingDistributionLimit?.amount)) const splits: Split[] = form.getFieldValue('payoutsList')?.map(allocationToSplit) ?? [] @@ -68,7 +73,7 @@ export function CreateFlowPayoutsTable({ payoutSplits={splits} setPayoutSplits={setSplits} currency={ - V2V3CurrencyName(editingDistributionLimit?.currency) ?? + V2V3CurrencyName(creatingDistributionLimit?.currency) ?? DEFAULT_CURRENCY_NAME } setCurrency={setCurrency} @@ -78,6 +83,7 @@ export function CreateFlowPayoutsTable({ hideExplaination hideSettings addPayoutsDisabled={addPayoutsDisabled} + createTreasurySelection={createTreasurySelection} /> {/* Empty form item just to keep AntD useWatch happy */} diff --git a/src/packages/v4/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx b/src/packages/v4/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx index b595c6d095..d4c2fffb25 100644 --- a/src/packages/v4/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx +++ b/src/packages/v4/components/Create/components/pages/PayoutsPage/components/TreasuryOptionsRadio.tsx @@ -8,9 +8,12 @@ import { useModal } from 'hooks/useModal' import { TreasurySelection } from 'models/treasurySelection' import { ConvertAmountsModal } from 'packages/v2v3/components/shared/PayoutsTable/ConvertAmountsModal' import { usePayoutsTable } from 'packages/v2v3/components/shared/PayoutsTable/hooks/usePayoutsTable' +import { V4_CURRENCY_ETH, V4_CURRENCY_USD } from 'packages/v4/utils/currency' import { useCallback, useEffect, useMemo, useState } from 'react' +import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { ReduxDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { ReduxDistributionLimit } from 'redux/hooks/v2v3/shared' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { fromWad } from 'utils/format/formatNumber' import { Icons } from '../../../Icons' import { RadioCard } from './RadioCard' @@ -23,8 +26,9 @@ const treasuryOptions = () => [ export function TreasuryOptionsRadio() { const initialTreasurySelection = useAppSelector( - state => state.editingV2Project.treasurySelection, + state => state.creatingV2Project.treasurySelection, ) + const dispatch = useAppDispatch() const [treasuryOption, setTreasuryOption] = useState( initialTreasurySelection ?? 'zero', @@ -32,6 +36,7 @@ export function TreasuryOptionsRadio() { const { distributionLimit, + currency, setDistributionLimit, payoutSplits, setCurrency, @@ -60,14 +65,14 @@ export function TreasuryOptionsRadio() { setTreasuryOption('amount') switchingToAmountsModal.close() }, - [setDistributionLimit, switchingToAmountsModal, setCurrency], + [setDistributionLimit, setCurrency, switchingToAmountsModal], ) const switchToUnlimitedPayouts = useCallback(() => { setDistributionLimit(undefined) setTreasuryOption('unlimited') switchingToUnlimitedModal.close() - }, [switchingToUnlimitedModal, setDistributionLimit]) + }, [setDistributionLimit, switchingToUnlimitedModal]) const switchToZeroPayoutSelection = useCallback(() => { setPayoutSplits([]) @@ -102,17 +107,19 @@ export function TreasuryOptionsRadio() { switchToZeroPayoutSelection() } + dispatch(creatingV2ProjectActions.setTreasurySelection(option)) setTreasuryOption(option) }, [ treasuryOption, payoutSplits.length, + dispatch, switchingToAmountsModal, - switchingToUnlimitedModal, setDistributionLimit, + switchingToUnlimitedModal, + switchToUnlimitedPayouts, switchingToZeroAmountsModal, switchToZeroPayoutSelection, - switchToUnlimitedPayouts, ], ) @@ -168,6 +175,7 @@ export function TreasuryOptionsRadio() { onOk={switchToAmountsPayoutSelection} onCancel={switchingToAmountsModal.close} splits={payoutSplits} + currency={currency === 'ETH' ? V4_CURRENCY_ETH : V4_CURRENCY_USD} /> ) diff --git a/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/useAvailablePayoutsSelections.ts b/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/useAvailablePayoutsSelections.ts index 993611ee99..1e2cc22d03 100644 --- a/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/useAvailablePayoutsSelections.ts +++ b/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/useAvailablePayoutsSelections.ts @@ -1,8 +1,8 @@ import { PayoutsSelection } from 'models/payoutsSelection' import { determineAvailablePayoutsSelections } from 'packages/v2v3/components/Create/utils/determineAvailablePayoutsSelections' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' export const useAvailablePayoutsSelections = (): Set => { - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() return determineAvailablePayoutsSelections(distributionLimit?.amount) } diff --git a/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts b/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts index 8a7b6c80fe..24edcf412a 100644 --- a/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts +++ b/src/packages/v4/components/Create/components/pages/PayoutsPage/hooks/usePayoutsForm.ts @@ -1,11 +1,14 @@ import { Form } from 'antd' import { TreasurySelection } from 'models/treasurySelection' import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useDebugValue, useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingPayoutSplits } from 'redux/hooks/useEditingPayoutSplits' +import { useCreatingPayoutSplits } from 'redux/hooks/v2v3/create' type PayoutsFormProps = Partial<{ selection: TreasurySelection @@ -14,8 +17,8 @@ type PayoutsFormProps = Partial<{ export const usePayoutsForm = () => { const [form] = Form.useForm() - const { treasurySelection } = useAppSelector(state => state.editingV2Project) - const [splits, setSplits] = useEditingPayoutSplits() + const { treasurySelection } = useAppSelector(state => state.creatingV2Project) + const [splits, setSplits] = useCreatingPayoutSplits() useDebugValue(form.getFieldsValue()) const initialValues: PayoutsFormProps | undefined = useMemo(() => { diff --git a/src/packages/v4/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts b/src/packages/v4/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts index 6bdefa459e..115903809a 100644 --- a/src/packages/v4/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts +++ b/src/packages/v4/components/Create/components/pages/ProjectDetails/hooks/useProjectDetailsForm.ts @@ -8,8 +8,8 @@ import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' import { DEFAULT_MUST_START_AT_OR_AFTER, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' import { AmountInputValue } from '../ProjectDetailsPage' @@ -40,7 +40,7 @@ type ProjectDetailsFormProps = Partial<{ export const useProjectDetailsForm = () => { const [form] = useForm() const { projectMetadata, inputProjectOwner, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) + useAppSelector(state => state.creatingV2Project) const initialValues: ProjectDetailsFormProps = useMemo( () => ({ @@ -103,90 +103,90 @@ export const useProjectDetailsForm = () => { form, fieldName: 'projectName', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setName, + dispatchFunction: creatingV2ProjectActions.setName, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTagline', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setProjectTagline, + dispatchFunction: creatingV2ProjectActions.setProjectTagline, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectDescription', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setDescription, + dispatchFunction: creatingV2ProjectActions.setDescription, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'tags', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTags, + dispatchFunction: creatingV2ProjectActions.setTags, formatter: v => v ?? [], }) useFormDispatchWatch({ form, fieldName: 'logo', - dispatchFunction: editingV2ProjectActions.setLogoUri, + dispatchFunction: creatingV2ProjectActions.setLogoUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'coverImage', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setCoverImageUri, + dispatchFunction: creatingV2ProjectActions.setCoverImageUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectWebsite', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setInfoUri, + dispatchFunction: creatingV2ProjectActions.setInfoUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTwitter', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTwitter, + dispatchFunction: creatingV2ProjectActions.setTwitter, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectDiscord', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setDiscord, + dispatchFunction: creatingV2ProjectActions.setDiscord, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'projectTelegram', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setTelegram, + dispatchFunction: creatingV2ProjectActions.setTelegram, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'inputProjectOwner', ignoreUndefined: false, - dispatchFunction: editingV2ProjectActions.setInputProjectOwner, + dispatchFunction: creatingV2ProjectActions.setInputProjectOwner, formatter: v => v, }) useFormDispatchWatch({ form, fieldName: 'payButtonText', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPayButton, + dispatchFunction: creatingV2ProjectActions.setPayButton, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'payDisclosure', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPayDisclosure, + dispatchFunction: creatingV2ProjectActions.setPayDisclosure, formatter: v => v ?? '', }) @@ -194,21 +194,21 @@ export const useProjectDetailsForm = () => { form, fieldName: 'introVideoUrl', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setIntroVideoUrl, + dispatchFunction: creatingV2ProjectActions.setIntroVideoUrl, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'introImageUri', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setIntroImageUri, + dispatchFunction: creatingV2ProjectActions.setIntroImageUri, formatter: v => v ?? '', }) useFormDispatchWatch({ form, fieldName: 'softTarget', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setSoftTarget, + dispatchFunction: creatingV2ProjectActions.setSoftTarget, formatter: v => v ?? { amount: '', currency: V2V3_CURRENCY_USD }, }) @@ -222,13 +222,13 @@ export const useProjectDetailsForm = () => { // check if launch date is in ms or seconds if (launchDate > 1000000000000) { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter( + creatingV2ProjectActions.setMustStartAtOrAfter( (launchDate / 1000).toString(), ), ) } else { dispatch( - editingV2ProjectActions.setMustStartAtOrAfter(launchDate.toString()), + creatingV2ProjectActions.setMustStartAtOrAfter(launchDate.toString()), ) } }, [dispatch, startTimestamp]) diff --git a/src/packages/v4/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx b/src/packages/v4/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx index 9671ed27f0..92a9fcf18c 100644 --- a/src/packages/v4/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx +++ b/src/packages/v4/components/Create/components/pages/ProjectToken/components/CustomTokenSettings/CustomTokenSettings.tsx @@ -18,7 +18,7 @@ import { ReservedTokensList } from 'packages/v2v3/components/shared/ReservedToke import { MAX_MINT_RATE } from 'packages/v2v3/utils/math' import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' import { inputMustExistRule } from 'utils/antdRules' import { formatAmount } from 'utils/format/formatAmount' import * as ProjectTokenForm from '../../hooks/useProjectTokenForm' @@ -38,9 +38,9 @@ const calculateMintRateAfterDiscount = ({ export const CustomTokenSettings = () => { const isMobile = useMobile() const duration = useAppSelector( - state => state.editingV2Project.fundingCycleData.duration, + state => state.creatingV2Project.fundingCycleData.duration, ) - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() const form = Form.useFormInstance() const discountRate = Form.useWatch('discountRate', form) ?? diff --git a/src/packages/v4/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts b/src/packages/v4/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts index 47c1942e8c..e2bdde2235 100644 --- a/src/packages/v4/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts +++ b/src/packages/v4/components/Create/components/pages/ProjectToken/hooks/useProjectTokenForm.ts @@ -17,14 +17,16 @@ import { allocationToSplit, splitToAllocation, } from 'packages/v2v3/utils/splitToAllocation' +import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' import { useDebugValue, useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' -import { useEditingReservedTokensSplits } from 'redux/hooks/useEditingReservedTokensSplits' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { + useCreatingDistributionLimit, + useCreatingReservedTokensSplits, +} from 'redux/hooks/v2v3/create' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' -import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' export type ProjectTokensFormProps = Partial<{ selection: ProjectTokensSelection @@ -55,10 +57,10 @@ export const DefaultSettings: Required< export const useProjectTokensForm = () => { const [form] = Form.useForm() const { fundingCycleMetadata, fundingCycleData, projectTokensSelection } = - useAppSelector(state => state.editingV2Project) - const [tokenSplits] = useEditingReservedTokensSplits() + useAppSelector(state => state.creatingV2Project) + const [tokenSplits] = useCreatingReservedTokensSplits() useDebugValue(form.getFieldsValue()) - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() const redemptionRateDisabled = !distributionLimit || distributionLimit.amount.eq(MAX_PAYOUT_LIMIT) @@ -120,15 +122,15 @@ export const useProjectTokensForm = () => { useEffect(() => { // We only want to update changes when selection is set if (selection === undefined) return - dispatch(editingV2ProjectActions.setProjectTokensSelection(selection)) + dispatch(creatingV2ProjectActions.setProjectTokensSelection(selection)) if (selection === 'default') { form.setFieldsValue({ ...DefaultSettings }) - dispatch(editingV2ProjectActions.setTokenSettings(DefaultSettings)) + dispatch(creatingV2ProjectActions.setTokenSettings(DefaultSettings)) return } dispatch( - editingV2ProjectActions.setTokenSettings({ + creatingV2ProjectActions.setTokenSettings({ ...DefaultSettings, ...form.getFieldsValue(), }), @@ -138,7 +140,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'initialMintRate', - dispatchFunction: editingV2ProjectActions.setWeight, + dispatchFunction: creatingV2ProjectActions.setWeight, formatter: v => { if (v === undefined || typeof v !== 'string') return issuanceRateFrom(DefaultSettings.initialMintRate) @@ -149,7 +151,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'reservedTokensPercentage', - dispatchFunction: editingV2ProjectActions.setReservedRate, + dispatchFunction: creatingV2ProjectActions.setReservedRate, formatter: v => { if (v === undefined || typeof v !== 'number') return reservedRateFrom( @@ -164,7 +166,7 @@ export const useProjectTokensForm = () => { fieldName: 'reservedTokenAllocation', ignoreUndefined: true, // Needed to stop an infinite loop currentValue: tokenSplits, // Needed to stop an infinite loop - dispatchFunction: editingV2ProjectActions.setReservedTokensSplits, + dispatchFunction: creatingV2ProjectActions.setReservedTokensSplits, formatter: v => { if (v === undefined || typeof v !== 'object') return [] return v.map(allocationToSplit) @@ -174,7 +176,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'discountRate', - dispatchFunction: editingV2ProjectActions.setDiscountRate, + dispatchFunction: creatingV2ProjectActions.setDiscountRate, formatter: v => { if (v === undefined || typeof v !== 'number') return discountRateFrom(DefaultSettings.discountRate).toHexString() @@ -185,7 +187,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'redemptionRate', - dispatchFunction: editingV2ProjectActions.setRedemptionRate, + dispatchFunction: creatingV2ProjectActions.setRedemptionRate, formatter: v => { if (v === undefined || typeof v !== 'number') return redemptionRateFrom(DefaultSettings.redemptionRate).toHexString() @@ -195,7 +197,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'redemptionRate', - dispatchFunction: editingV2ProjectActions.setBallotRedemptionRate, + dispatchFunction: creatingV2ProjectActions.setBallotRedemptionRate, formatter: v => { if (v === undefined || typeof v !== 'number') return redemptionRateFrom(DefaultSettings.redemptionRate).toHexString() @@ -206,7 +208,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'tokenMinting', - dispatchFunction: editingV2ProjectActions.setAllowMinting, + dispatchFunction: creatingV2ProjectActions.setAllowMinting, formatter: v => { if (typeof v !== 'boolean') return false return v @@ -216,7 +218,7 @@ export const useProjectTokensForm = () => { useFormDispatchWatch({ form, fieldName: 'pauseTransfers', - dispatchFunction: editingV2ProjectActions.setPauseTransfers, + dispatchFunction: creatingV2ProjectActions.setPauseTransfers, ignoreUndefined: true, formatter: v => { if (typeof v !== 'boolean') return false diff --git a/src/packages/v4/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts b/src/packages/v4/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts index 23434ae661..92bd9755d7 100644 --- a/src/packages/v4/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts +++ b/src/packages/v4/components/Create/components/pages/ReconfigurationRules/hooks/useReconfigurationRulesForm.ts @@ -6,7 +6,7 @@ import { useAvailableReconfigurationStrategies } from 'packages/v2v3/components/ import { useEffect, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { isEqualAddress, isZeroAddress } from 'utils/address' import { useFormDispatchWatch } from '../../hooks/useFormDispatchWatch' @@ -47,7 +47,7 @@ export const useReconfigurationRulesForm = () => { fundingCycleData: { ballot }, reconfigurationRuleSelection, fundingCycleMetadata, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const initialValues: ReconfigurationRulesFormProps | undefined = useMemo(() => { const pausePayments = fundingCycleMetadata.pausePay @@ -128,15 +128,17 @@ export const useReconfigurationRulesForm = () => { address = customAddress break } - dispatch(editingV2ProjectActions.setBallot(address ?? '')) - dispatch(editingV2ProjectActions.setReconfigurationRuleSelection(selection)) + dispatch(creatingV2ProjectActions.setBallot(address ?? '')) + dispatch( + creatingV2ProjectActions.setReconfigurationRuleSelection(selection), + ) }, [customAddress, dispatch, selection, strategies]) useFormDispatchWatch({ form, fieldName: 'pausePayments', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setPausePay, + dispatchFunction: creatingV2ProjectActions.setPausePay, formatter: v => !!v, }) @@ -144,7 +146,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'holdFees', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setHoldFees, + dispatchFunction: creatingV2ProjectActions.setHoldFees, formatter: v => !!v, }) @@ -152,7 +154,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowTerminalConfiguration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowSetTerminals, + dispatchFunction: creatingV2ProjectActions.setAllowSetTerminals, formatter: v => !!v, }) @@ -160,7 +162,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowControllerConfiguration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowSetController, + dispatchFunction: creatingV2ProjectActions.setAllowSetController, formatter: v => !!v, }) @@ -168,7 +170,7 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowTerminalMigration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowTerminalMigration, + dispatchFunction: creatingV2ProjectActions.setAllowTerminalMigration, formatter: v => !!v, }) @@ -176,14 +178,14 @@ export const useReconfigurationRulesForm = () => { form, fieldName: 'allowControllerMigration', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setAllowControllerMigration, + dispatchFunction: creatingV2ProjectActions.setAllowControllerMigration, formatter: v => !!v, }) useFormDispatchWatch({ form, fieldName: 'projectRequiredOFACCheck', ignoreUndefined: true, - dispatchFunction: editingV2ProjectActions.setRequiredOFACCheck, + dispatchFunction: creatingV2ProjectActions.setRequiredOFACCheck, formatter: v => v, }) diff --git a/src/packages/v4/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx b/src/packages/v4/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx index 17d5d5554e..0c5a772a61 100644 --- a/src/packages/v4/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx +++ b/src/packages/v4/components/Create/components/pages/ReviewDeploy/ReviewDeployPage.tsx @@ -1,6 +1,8 @@ +import { Checkbox, Form } from 'antd' +import { useCallback, useContext, useEffect, useMemo, useState } from 'react' + import { CheckCircleFilled } from '@ant-design/icons' import { Trans } from '@lingui/macro' -import { Checkbox, Form } from 'antd' import { Callout } from 'components/Callout/Callout' import ExternalLink from 'components/ExternalLink' import TransactionModal from 'components/modals/TransactionModal' @@ -10,11 +12,10 @@ import { emitConfirmationDeletionModal } from 'hooks/emitConfirmationDeletionMod import useMobile from 'hooks/useMobile' import { useModal } from 'hooks/useModal' import { useRouter } from 'next/router' -import { useCallback, useContext, useEffect, useMemo, useState } from 'react' import { useDispatch } from 'react-redux' import { useAppSelector } from 'redux/hooks/useAppSelector' import { useSetCreateFurthestPageReached } from 'redux/hooks/useEditingCreateFurthestPageReached' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { helpPagePath } from 'utils/helpPagePath' import { useDeployProject } from '../../../hooks/DeployProject/useDeployProject' import { CreateBadge } from '../../CreateBadge' @@ -24,6 +25,7 @@ import { WizardContext } from '../../Wizard/contexts/WizardContext' import { FundingConfigurationReview } from './components/FundingConfigurationReview/FundingConfigurationReview' import { ProjectDetailsReview } from './components/ProjectDetailsReview/ProjectDetailsReview' import { ProjectTokenReview } from './components/ProjectTokenReview/ProjectTokenReview' +import { RewardsReview } from './components/RewardsReview/RewardsReview' import { RulesReview } from './components/RulesReview/RulesReview' enum ReviewDeployKey { @@ -64,7 +66,7 @@ export const ReviewDeployPage = () => { const { deployProject, isDeploying, deployTransactionPending } = useDeployProject() const nftRewards = useAppSelector( - state => state.editingV2Project.nftRewards.rewardTiers, + state => state.creatingV2Project.nftRewards.rewardTiers, ) const nftRewardsAreSet = useMemo( @@ -77,10 +79,10 @@ export const ReviewDeployPage = () => { const handleStartOverClicked = useCallback(() => { router.push('/create') goToPage?.('projectDetails') - dispatch(editingV2ProjectActions.resetState()) + dispatch(creatingV2ProjectActions.resetState()) }, [dispatch, goToPage, router]) - const onFinish = useCallback(async () => { + if (chainUnsupported) { await changeNetworks() return @@ -164,7 +166,7 @@ export const ReviewDeployPage = () => { > - {/* { } > - */} + { const { fundingCycleData, payoutsSelection, mustStartAtOrAfter } = - useAppSelector(state => state.editingV2Project) - const [distributionLimit] = useEditingDistributionLimit() - const [payoutSplits, setPayoutSplits] = useEditingPayoutSplits() + useAppSelector(state => state.creatingV2Project) + const [distributionLimit] = useCreatingDistributionLimit() + const [payoutSplits, setPayoutSplits] = useCreatingPayoutSplits() const fundingCycles = useMemo( () => (fundingCycleData.duration == '0' ? t`Manual` : t`Automated`), diff --git a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx index b7b74c3504..d5ea262bc2 100644 --- a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx +++ b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectDetailsReview/ProjectDetailsReview.tsx @@ -31,7 +31,7 @@ export const ProjectDetailsReview = () => { softTargetCurrency, }, inputProjectOwner, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const youtubeUrl = useMemo(() => { if (!introVideoUrl) return undefined diff --git a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts index c5f4b5da21..5c6a1cf39d 100644 --- a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts +++ b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/ProjectTokenReview/hooks/useProjectTokenReview.ts @@ -1,8 +1,11 @@ import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' -import { allocationToSplit, splitToAllocation } from 'packages/v2v3/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v2v3/utils/splitToAllocation' import { useCallback, useMemo } from 'react' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { useEditingReservedTokensSplits } from 'redux/hooks/useEditingReservedTokensSplits' +import { useCreatingReservedTokensSplits } from 'redux/hooks/v2v3/create' import { formatEnabled, formatPaused } from 'utils/format/formatBoolean' export const useProjectTokenReview = () => { @@ -14,8 +17,8 @@ export const useProjectTokenReview = () => { redemptionRate, global, }, - } = useAppSelector(state => state.editingV2Project) - const [tokenSplits, setTokenSplits] = useEditingReservedTokensSplits() + } = useAppSelector(state => state.creatingV2Project) + const [tokenSplits, setTokenSplits] = useCreatingReservedTokensSplits() const allocationSplits = useMemo( () => tokenSplits.map(splitToAllocation), diff --git a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx index 23c08e274d..fbfa22b23a 100644 --- a/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx +++ b/src/packages/v4/components/Create/components/pages/ReviewDeploy/components/RewardsReview/RewardsReview.tsx @@ -4,22 +4,21 @@ import { NftRewardTier } from 'models/nftRewards' import { useCallback, useMemo } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { formatEnabled } from 'utils/format/formatBoolean' import { v4 } from 'uuid' import { ReviewDescription } from '../ReviewDescription' export const RewardsReview = () => { - const { - nftRewards: { rewardTiers, flags }, - fundingCycleMetadata, - } = useAppSelector(state => state.editingV2Project) + const { nftRewards: nftRewardsData, fundingCycleMetadata } = useAppSelector( + state => state.creatingV2Project, + ) const dispatch = useAppDispatch() const rewards: NftRewardTier[] = useMemo(() => { return ( - rewardTiers?.map(t => ({ + nftRewardsData.rewardTiers?.map(t => ({ id: parseInt(v4()), name: t.name, contributionFloor: t.contributionFloor, @@ -33,12 +32,12 @@ export const RewardsReview = () => { votingWeight: t.votingWeight, })) ?? [] ) - }, [rewardTiers]) + }, [nftRewardsData.rewardTiers]) const setRewards = useCallback( (rewards: NftRewardTier[]) => { dispatch( - editingV2ProjectActions.setNftRewardTiers( + creatingV2ProjectActions.setNftRewardTiers( rewards.map(reward => ({ contributionFloor: reward.contributionFloor, maxSupply: reward.maxSupply, @@ -63,12 +62,16 @@ export const RewardsReview = () => { }, [fundingCycleMetadata.useDataSourceForRedeem]) const preventOverspending = useMemo(() => { - return formatEnabled(flags.preventOverspending) - }, [flags.preventOverspending]) + return formatEnabled(nftRewardsData.flags.preventOverspending) + }, [nftRewardsData.flags.preventOverspending]) return (
- +
{ reconfigurationRuleSelection, fundingCycleMetadata, projectMetadata, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) const pausePayments = useMemo(() => { return formatPaused(fundingCycleMetadata.pausePay) diff --git a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts index 75ab2342d8..fc145b2a2a 100644 --- a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts +++ b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useDeployNftProject.ts @@ -1,16 +1,84 @@ -import { TransactionCallbacks } from 'models/transaction' -import { useLaunchProjectWithNftsTx } from 'packages/v2v3/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx' -import { DEFAULT_JB_721_DELEGATE_VERSION } from 'packages/v2v3/hooks/defaultContracts/useDefaultJB721Delegate' -import { useCallback, useMemo } from 'react' +import { ONE_BILLION } from 'constants/numbers' +import { DEFAULT_JB_721_TIER_CATEGORY } from 'constants/transactionDefaults' +import { JBTiered721Flags, NftRewardTier } from 'models/nftRewards' +import { useLaunchProjectWithNftsTx } from 'packages/v4/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx' +import { LaunchTxOpts } from 'packages/v4/hooks/useLaunchProjectTx' +import { JB721TierConfig, JB721TiersHookFlags } from 'packages/v4/models/nfts' +import { useCallback } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' -import { DEFAULT_NFT_FLAGS } from 'redux/slices/editingV2Project' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' +import { DEFAULT_NFT_FLAGS } from 'redux/slices/shared/v2ProjectDefaultState' +import { encodeIpfsUri } from 'utils/ipfs' import { NFT_FUNDING_CYCLE_METADATA_OVERRIDES } from 'utils/nftFundingCycleMetadataOverrides' -import { buildJB721TierParams } from 'utils/nftRewards' +import { sortNftsByContributionFloor } from 'utils/nftRewards' +import { Address, parseEther, zeroAddress } from 'viem' + +export const DEFAULT_NFT_MAX_SUPPLY = ONE_BILLION - 1 + +function nftRewardTierToJB721TierConfig( + rewardTier: NftRewardTier, + cid: string, +): JB721TierConfig { + const price = parseEther(rewardTier.contributionFloor.toString()) + const initialSupply = rewardTier.maxSupply ?? DEFAULT_NFT_MAX_SUPPLY + const encodedIPFSUri = encodeIpfsUri(cid) + + const reserveFrequency = rewardTier.reservedRate + ? rewardTier.reservedRate - 1 + : 0 + const reserveBeneficiary = + (rewardTier.beneficiary as Address | undefined) ?? zeroAddress + const votingUnits = parseInt(rewardTier.votingWeight ?? '0') + // should default to 0, with useVotingUnits `true`, to save gas + + return { + price, + initialSupply, + votingUnits, + reserveFrequency, + reserveBeneficiary, + encodedIPFSUri, + allowOwnerMint: false, + useReserveBeneficiaryAsDefault: false, + transfersPausable: false, + useVotingUnits: true, + cannotBeRemoved: false, + cannotIncreaseDiscountPercent: false, + discountPercent: 0, + remainingSupply: initialSupply, + category: DEFAULT_JB_721_TIER_CATEGORY, + resolvedUri: '', + } +} + +function buildJB721TierParams({ + cids, // MUST BE SORTED BY CONTRIBUTION FLOOR (TODO: not ideal) + rewardTiers, +}: { + cids: string[] + rewardTiers: NftRewardTier[] +}): JB721TierConfig[] { + const sortedRewardTiers = sortNftsByContributionFloor(rewardTiers) + + return cids.map((cid, index) => { + const rewardTier = sortedRewardTiers[index] + + return nftRewardTierToJB721TierConfig(rewardTier, cid) + }) +} + +function toV4Flags(v2v3Flags: JBTiered721Flags): JB721TiersHookFlags { + return { + noNewTiersWithOwnerMinting: v2v3Flags.lockManualMintingChanges, + noNewTiersWithReserves: v2v3Flags.lockReservedTokenChanges, + noNewTiersWithVotes: v2v3Flags.lockVotingUnitChanges, + preventOverspending: v2v3Flags.preventOverspending, + } +} /** * Hook that returns a function that deploys a project with NFT rewards. @@ -28,27 +96,17 @@ export const useDeployNftProject = () => { reservedTokensGroupedSplits, inputProjectOwner, mustStartAtOrAfter, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() - - const collectionName = useMemo( - () => - nftRewards.collectionMetadata.name - ? nftRewards.collectionMetadata.name - : projectMetadata.name, - [nftRewards.collectionMetadata.name, projectMetadata.name], - ) - const collectionSymbol = useMemo( - () => nftRewards.collectionMetadata.symbol ?? '', - [nftRewards.collectionMetadata.symbol], - ) - const nftFlags = useMemo( - () => nftRewards.flags ?? DEFAULT_NFT_FLAGS, - [nftRewards.flags], - ) - const governanceType = nftRewards.governanceType + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() + + const collectionName = nftRewards.collectionMetadata.name + ? nftRewards.collectionMetadata.name + : projectMetadata.name + const collectionSymbol = nftRewards.collectionMetadata.symbol ?? '' + const nftFlags = nftRewards.flags ?? DEFAULT_NFT_FLAGS + // const governanceType = nftRewards.governanceType const currency = nftRewards.pricing.currency /** @@ -63,15 +121,14 @@ export const useDeployNftProject = () => { rewardTierCids, nftCollectionMetadataUri, - onDone, - onConfirmed, - onCancelled, - onError, + onTransactionPending, + onTransactionConfirmed, + onTransactionError, }: { metadataCid: string rewardTierCids: string[] nftCollectionMetadataUri: string - } & TransactionCallbacks) => { + } & LaunchTxOpts) => { if (!collectionName) throw new Error('No collection name or project name') if (!(rewardTierCids.length && nftRewards.rewardTiers)) throw new Error('No NFTs') @@ -80,8 +137,8 @@ export const useDeployNftProject = () => { const tiers = buildJB721TierParams({ cids: rewardTierCids, rewardTiers: nftRewards.rewardTiers, - version: DEFAULT_JB_721_DELEGATE_VERSION, }) + const flags = toV4Flags(nftFlags) return await launchProjectWithNftsTx( { @@ -90,9 +147,8 @@ export const useDeployNftProject = () => { collectionName, collectionSymbol, currency, - governanceType, tiers, - flags: nftFlags, + flags, }, projectData: { owner: inputProjectOwner?.length ? inputProjectOwner : undefined, @@ -108,10 +164,9 @@ export const useDeployNftProject = () => { }, }, { - onDone, - onConfirmed, - onCancelled, - onError, + onTransactionPending, + onTransactionConfirmed, + onTransactionError, }, ) }, @@ -123,7 +178,6 @@ export const useDeployNftProject = () => { reservedTokensGroupedSplits, launchProjectWithNftsTx, collectionSymbol, - governanceType, inputProjectOwner, fundingCycleData, mustStartAtOrAfter, diff --git a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts index 5d38d3d9d3..5dc9700221 100644 --- a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts +++ b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useIsNftProject.ts @@ -6,7 +6,7 @@ import { useAppSelector } from 'redux/hooks/useAppSelector' * @returns Whether the project to be deployed is an NFT project. */ export const useIsNftProject = (): boolean => { - const { nftRewards } = useAppSelector(state => state.editingV2Project) + const { nftRewards } = useAppSelector(state => state.creatingV2Project) return useMemo( () => diff --git a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts index 5b4193e286..2f795a20d1 100644 --- a/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts +++ b/src/packages/v4/components/Create/hooks/DeployProject/hooks/NFT/useUploadNftRewards.ts @@ -14,7 +14,7 @@ export const useUploadNftRewards = () => { const { nftRewards, projectMetadata: { name: projectName, logoUri, infoUri }, - } = useAppSelector(state => state.editingV2Project) + } = useAppSelector(state => state.creatingV2Project) return useCallback(async () => { if (!nftRewards?.rewardTiers || !nftRewards?.collectionMetadata) return diff --git a/src/packages/v4/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts b/src/packages/v4/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts index 2ec6c7a771..c22d9e7065 100644 --- a/src/packages/v4/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts +++ b/src/packages/v4/components/Create/hooks/DeployProject/hooks/useDeployStandardProject.ts @@ -1,11 +1,14 @@ -import { LaunchTxOpts, useLaunchProjectTx } from 'packages/v4/hooks/useLaunchProjectTx' +import { + LaunchTxOpts, + useLaunchProjectTx, +} from 'packages/v4/hooks/useLaunchProjectTx' import { useCallback } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' /** * Hook that returns a function that deploys a v4 project. @@ -20,21 +23,22 @@ export const useDeployStandardProject = () => { reservedTokensGroupedSplits, inputProjectOwner, mustStartAtOrAfter, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() const deployStandardProjectCallback = useCallback( async ({ metadataCid, onTransactionPending, onTransactionConfirmed, - onTransactionError + onTransactionError, }: { metadataCid: string } & LaunchTxOpts) => { const groupedSplits = [payoutGroupedSplits, reservedTokensGroupedSplits] + return await launchProjectTx( { owner: inputProjectOwner?.length ? inputProjectOwner : undefined, @@ -48,7 +52,7 @@ export const useDeployStandardProject = () => { { onTransactionPending, onTransactionConfirmed, - onTransactionError + onTransactionError, }, ) }, diff --git a/src/packages/v4/components/Create/hooks/DeployProject/useDeployProject.ts b/src/packages/v4/components/Create/hooks/DeployProject/useDeployProject.ts index a0de85a48a..0232d7bc7b 100644 --- a/src/packages/v4/components/Create/hooks/DeployProject/useDeployProject.ts +++ b/src/packages/v4/components/Create/hooks/DeployProject/useDeployProject.ts @@ -1,15 +1,19 @@ +import { useCallback, useState } from 'react' +import { useAppSelector } from 'redux/hooks/useAppSelector' + import { uploadProjectMetadata } from 'lib/api/ipfs' import { LaunchTxOpts } from 'packages/v4/hooks/useLaunchProjectTx' -import { useCallback, useState } from 'react' import { useAppDispatch } from 'redux/hooks/useAppDispatch' import { - useAppSelector, - useEditingV2V3FundAccessConstraintsSelector, - useEditingV2V3FundingCycleDataSelector, - useEditingV2V3FundingCycleMetadataSelector, -} from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' + useCreatingV2V3FundAccessConstraintsSelector, + useCreatingV2V3FundingCycleDataSelector, + useCreatingV2V3FundingCycleMetadataSelector, +} from 'redux/hooks/v2v3/create' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' import { emitErrorNotification } from 'utils/notifications' +import { useDeployNftProject } from './hooks/NFT/useDeployNftProject' +import { useIsNftProject } from './hooks/NFT/useIsNftProject' +import { useUploadNftRewards } from './hooks/NFT/useUploadNftRewards' import { useDeployStandardProject } from './hooks/useDeployStandardProject' const JUICEBOX_DOMAIN = 'juicebox' @@ -22,19 +26,18 @@ export const useDeployProject = () => { const [isDeploying, setIsDeploying] = useState(false) const [transactionPending, setTransactionPending] = useState() - // const isNftProject = useIsNftProject() - // const uploadNftRewards = useUploadNftRewards() - // const deployNftProject = useDeployNftProject() - + const isNftProject = useIsNftProject() + const uploadNftRewards = useUploadNftRewards() + const deployNftProject = useDeployNftProject() const deployStandardProject = useDeployStandardProject() const { projectMetadata, nftRewards: { postPayModal }, - } = useAppSelector(state => state.editingV2Project) - const fundingCycleMetadata = useEditingV2V3FundingCycleMetadataSelector() - const fundingCycleData = useEditingV2V3FundingCycleDataSelector() - const fundAccessConstraints = useEditingV2V3FundAccessConstraintsSelector() + } = useAppSelector(state => state.creatingV2Project) + const fundingCycleMetadata = useCreatingV2V3FundingCycleMetadataSelector() + const fundingCycleData = useCreatingV2V3FundingCycleDataSelector() + const fundAccessConstraints = useCreatingV2V3FundAccessConstraintsSelector() const dispatch = useAppDispatch() @@ -46,16 +49,14 @@ export const useDeployProject = () => { }, []) const operationCallbacks = useCallback( - ( - onProjectDeployed?: (projectId: number) => void, - ): LaunchTxOpts => ({ + (onProjectDeployed?: (projectId: number) => void): LaunchTxOpts => ({ onTransactionPending: () => { console.info('Project transaction executed. Await confirmation...') setTransactionPending(true) }, onTransactionConfirmed: async (hash, projectId) => { // Reset the project state - dispatch(editingV2ProjectActions.resetState()) + dispatch(creatingV2ProjectActions.resetState()) onProjectDeployed?.(projectId) }, onTransactionError: error => { @@ -89,15 +90,15 @@ export const useDeployProject = () => { setIsDeploying(false) throw new Error('Error deploying project.') } - // let nftCids: Awaited> | undefined - // try { - // if (isNftProject) { - // nftCids = await uploadNftRewards() - // } - // } catch (error) { - // handleDeployFailure(error) - // return - // } + let nftCids: Awaited> | undefined + try { + if (isNftProject) { + nftCids = await uploadNftRewards() + } + } catch (error) { + handleDeployFailure(error) + return + } let softTargetAmount: string | undefined let softTargetCurrency: string | undefined @@ -120,42 +121,42 @@ export const useDeployProject = () => { } try { - // let tx - // if (isNftProject) { - // tx = await deployNftProject({ - // metadataCid: projectMetadataCid, - // rewardTierCids: nftCids!.rewardTiers, - // nftCollectionMetadataUri: nftCids!.nfCollectionMetadata, - // ...operationCallbacks(onProjectDeployed), - // }) - // } else { - const tx = await deployStandardProject({ - metadataCid: projectMetadataCid, - ...operationCallbacks(onProjectDeployed), - }) - // } - // if (!tx) { - setIsDeploying(false) - setTransactionPending(false) - return - // } + let tx + if (isNftProject) { + tx = await deployNftProject({ + metadataCid: projectMetadataCid, + rewardTierCids: nftCids!.rewardTiers, + nftCollectionMetadataUri: nftCids!.nfCollectionMetadata, + ...operationCallbacks(onProjectDeployed), + }) + } else { + tx = await deployStandardProject({ + metadataCid: projectMetadataCid, + ...operationCallbacks(onProjectDeployed), + }) + } + if (!tx) { + setIsDeploying(false) + setTransactionPending(false) + return + } } catch (error) { handleDeployFailure(error) return } }, [ - // deployNftProject, + deployNftProject, deployStandardProject, fundAccessConstraints, fundingCycleData, fundingCycleMetadata, handleDeployFailure, - // isNftProject, + isNftProject, operationCallbacks, postPayModal, projectMetadata, - // uploadNftRewards, + uploadNftRewards, ], ) return { diff --git a/src/packages/v4/components/Create/hooks/useLoadInitialStateFromQuery.ts b/src/packages/v4/components/Create/hooks/useLoadInitialStateFromQuery.ts index efe17f29bb..cd368837da 100644 --- a/src/packages/v4/components/Create/hooks/useLoadInitialStateFromQuery.ts +++ b/src/packages/v4/components/Create/hooks/useLoadInitialStateFromQuery.ts @@ -10,10 +10,10 @@ import { useEffect, useState } from 'react' import { useDispatch } from 'react-redux' import { DEFAULT_REDUX_STATE, - INITIAL_REDUX_STATE, - editingV2ProjectActions, -} from 'redux/slices/editingV2Project' -import { CreateState, ProjectState } from 'redux/slices/editingV2Project/types' + creatingV2ProjectActions, +} from 'redux/slices/creatingV2Project' +import { INITIAL_REDUX_STATE } from 'redux/slices/shared/v2ProjectInitialReduxState' +import { CreateState, ProjectState } from 'redux/slices/shared/v2ProjectTypes' import { isEqualAddress } from 'utils/address' import { parseWad } from 'utils/format/formatNumber' import { zeroAddress } from 'viem' @@ -139,7 +139,7 @@ export function useLoadingInitialStateFromQuery() { parseCreateFlowStateFromInitialState(parsedInitialState) dispatch( - editingV2ProjectActions.setState({ + creatingV2ProjectActions.setState({ ...INITIAL_REDUX_STATE, ...createFlowState, ...parsedInitialState, diff --git a/src/packages/v4/components/Create/utils/projectTokenSettingsToReduxFormat.ts b/src/packages/v4/components/Create/utils/projectTokenSettingsToReduxFormat.ts index de6f55ff2d..fa7d98954e 100644 --- a/src/packages/v4/components/Create/utils/projectTokenSettingsToReduxFormat.ts +++ b/src/packages/v4/components/Create/utils/projectTokenSettingsToReduxFormat.ts @@ -5,7 +5,7 @@ import { reservedRateFrom, } from 'packages/v2v3/utils/math' import { allocationToSplit } from 'packages/v2v3/utils/splitToAllocation' -import { EMPTY_RESERVED_TOKENS_GROUPED_SPLITS } from 'redux/slices/editingV2Project' +import { EMPTY_RESERVED_TOKENS_GROUPED_SPLITS } from 'redux/slices/creatingV2Project' import { ProjectTokensFormProps } from '../components/pages/ProjectToken/hooks/useProjectTokenForm' export const projectTokenSettingsToReduxFormat = ( diff --git a/src/packages/v4/components/PayoutsTable/ConvertAmountsModal.tsx b/src/packages/v4/components/PayoutsTable/ConvertAmountsModal.tsx index 53a9afecb8..0bb137eda1 100644 --- a/src/packages/v4/components/PayoutsTable/ConvertAmountsModal.tsx +++ b/src/packages/v4/components/PayoutsTable/ConvertAmountsModal.tsx @@ -14,13 +14,14 @@ import { derivePayoutAmount, } from 'packages/v4/utils/distributions' import { formatCurrencyAmount } from 'packages/v4/utils/formatCurrencyAmount' -import { allocationToSplit, splitToAllocation } from 'packages/v4/utils/splitToAllocation' +import { + allocationToSplit, + splitToAllocation, +} from 'packages/v4/utils/splitToAllocation' import { isJuiceboxProjectSplit } from 'packages/v4/utils/v4Splits' import { ReactNode, useCallback, useMemo, useState } from 'react' -import { - ReduxDistributionLimit, - useEditingDistributionLimit, -} from 'redux/hooks/useEditingDistributionLimit' +import { useCreatingDistributionLimit } from 'redux/hooks/v2v3/create' +import { ReduxDistributionLimit } from 'redux/hooks/v2v3/shared' import { parseWad } from 'utils/format/formatNumber' import { formatPercent } from 'utils/format/formatPercent' import { helpPagePath } from 'utils/helpPagePath' @@ -37,7 +38,7 @@ export const ConvertAmountsModal = ({ onCancel: VoidFunction splits: Split[] }) => { - const [distributionLimit] = useEditingDistributionLimit() + const [distributionLimit] = useCreatingDistributionLimit() const [newDistributionLimit, setNewDistributionLimit] = useState('') const [currency, setCurrency] = useState( distributionLimit?.currency ?? V4_CURRENCY_ETH, @@ -155,7 +156,9 @@ export const ConvertAmountsModal = ({ }), currency, })}{' '} - {allocation.percent.formatPercentage()}% + + {allocation.percent.formatPercentage()}% + } /> diff --git a/src/packages/v4/components/PayoutsTable/PayoutTableSettings.tsx b/src/packages/v4/components/PayoutsTable/PayoutTableSettings.tsx index 6789390223..567ead4de6 100644 --- a/src/packages/v4/components/PayoutsTable/PayoutTableSettings.tsx +++ b/src/packages/v4/components/PayoutsTable/PayoutTableSettings.tsx @@ -4,7 +4,7 @@ import { SwitchToUnlimitedModal } from 'components/PayoutsTable/SwitchToUnlimite import { PopupMenu, PopupMenuItem } from 'components/ui/PopupMenu' import { handleConfirmationDeletion } from 'hooks/emitConfirmationDeletionModal' import { useState } from 'react' -import { ReduxDistributionLimit } from 'redux/hooks/useEditingDistributionLimit' +import { ReduxDistributionLimit } from 'redux/hooks/v2v3/shared' import { fromWad } from 'utils/format/formatNumber' import { ConvertAmountsModal } from './ConvertAmountsModal' import { usePayoutsTable } from './hooks/usePayoutsTable' diff --git a/src/packages/v4/components/PayoutsTable/PayoutsTableBody.tsx b/src/packages/v4/components/PayoutsTable/PayoutsTableBody.tsx index f61c05ef61..b21e359499 100644 --- a/src/packages/v4/components/PayoutsTable/PayoutsTableBody.tsx +++ b/src/packages/v4/components/PayoutsTable/PayoutsTableBody.tsx @@ -16,7 +16,8 @@ const Row = PayoutsTableRow const Cell = PayoutsTableCell export function PayoutsTableBody() { - const { topAccessory, hideHeader } = usePayoutsTableContext() + const { topAccessory, hideHeader, createTreasurySelection } = + usePayoutsTableContext() const { payoutSplits, currency, @@ -28,6 +29,11 @@ export function PayoutsTableBody() { const hasDistributionLimit = distributionLimit && distributionLimit > 0 + if (createTreasurySelection === 'zero') { + // TODO: This feels like a hack, this should not be coupled here. + return <>{topAccessory} + } + return ( <> {topAccessory} @@ -60,9 +66,11 @@ export function PayoutsTableBody() { Address or ID - {hasDistributionLimit ? + {hasDistributionLimit ? ( - : Percent} + ) : ( + Percent + )} ) : null} diff --git a/src/packages/v4/components/PayoutsTable/context/PayoutsTableContext.tsx b/src/packages/v4/components/PayoutsTable/context/PayoutsTableContext.tsx index 401730b83f..243633a352 100644 --- a/src/packages/v4/components/PayoutsTable/context/PayoutsTableContext.tsx +++ b/src/packages/v4/components/PayoutsTable/context/PayoutsTableContext.tsx @@ -1,5 +1,6 @@ import { CurrencyName } from 'constants/currency' import { JBSplit as Split } from 'juice-sdk-core' +import { TreasurySelection } from 'models/treasurySelection' import { ReactNode, createContext, useContext } from 'react' export interface PayoutsTableContextProps { @@ -15,6 +16,8 @@ export interface PayoutsTableContextProps { topAccessory?: ReactNode hideSettings?: boolean addPayoutsDisabled?: boolean + // TODO: Hack to allow the create payouts table to hide data if set to none. + createTreasurySelection?: TreasurySelection } export const PayoutsTableContext = createContext< diff --git a/src/packages/v4/components/ProjectDashboard/ReduxProjectCartProvider.tsx b/src/packages/v4/components/ProjectDashboard/ReduxProjectCartProvider.tsx index 02816d4d59..e84f41f073 100644 --- a/src/packages/v4/components/ProjectDashboard/ReduxProjectCartProvider.tsx +++ b/src/packages/v4/components/ProjectDashboard/ReduxProjectCartProvider.tsx @@ -1,8 +1,9 @@ -import { useWallet } from 'hooks/Wallet' +import { useV4NftRewards } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' import { V4CurrencyOption } from 'packages/v4/models/v4CurrencyOption' import React from 'react' import { useProjectDispatch } from './redux/hooks' -// import { projectCartActions } from './redux/projectCartSlice' +import { projectCartActions } from './redux/projectCartSlice' export type ProjectCartCurrencyAmount = { amount: number @@ -20,26 +21,22 @@ export const ReduxProjectCartProvider = ({ }: { children: React.ReactNode }) => { - // const { rewardTiers } = useContext(NftRewardsContext).nftRewards - - const { userAddress } = useWallet() - // const userNftCredits = useNftCredits(userAddress) - + const { + nftRewards: { rewardTiers }, + } = useV4NftRewards() + const nftCredits = useV4UserNftCredits() const dispatch = useProjectDispatch() // Set the nfts on load - // useEffect(() => { - // dispatch(projectCartActions.setAllNftRewards(rewardTiers ?? [])) - // }, [dispatch, rewardTiers]) + React.useEffect(() => { + dispatch(projectCartActions.setAllNftRewards(rewardTiers ?? [])) + }, [dispatch, rewardTiers]) // Set the user's NFT credits on load - // useEffect(() => { - // dispatch( - // projectCartActions.setUserNftCredits( - // userNftCredits.data?.toBigInt() ?? 0n, - // ), - // ) - // }, [dispatch, userNftCredits.data]) + React.useEffect(() => { + if (nftCredits.isLoading) return + dispatch(projectCartActions.setUserNftCredits(nftCredits.data ?? 0n)) + }, [dispatch, nftCredits.isLoading, nftCredits.data]) return <>{children} } diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/NftReward.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/NftReward.tsx deleted file mode 100644 index ac0f817e24..0000000000 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/NftReward.tsx +++ /dev/null @@ -1,93 +0,0 @@ -// const NftReward: React.FC<{ -// nft: ProjectCartNftReward -// className?: string -// }> = ({ nft, className }) => { -// const { -// price, -// name, -// quantity, -// fileUrl, -// removeNft, -// increaseQuantity, -// decreaseQuantity, -// } = useNftCartItem(nft) - -// const handleRemove = useCallback(() => { -// emitConfirmationDeletionModal({ -// onConfirm: removeNft, -// title: t`Remove NFT`, -// description: t`Are you sure you want to remove this NFT?`, -// }) -// }, [removeNft]) - -// const handleDecreaseQuantity = useCallback(() => { -// if (quantity - 1 <= 0) { -// handleRemove() -// } else { -// decreaseQuantity() -// } -// }, [decreaseQuantity, handleRemove, quantity]) - -// const priceText = price === null ? '-' : formatCurrencyAmount(price) - -// return ( -//
-//
-// -//
-//
-// -// NFT -//
- -//
{priceText}
-//
-//
- -//
-// -// -//
-//
-// ) -// } - -// const RemoveIcon: React.FC<{ onClick: () => void }> = ({ onClick }) => ( -// -// ) - -// const QuantityControl: React.FC<{ -// quantity: number -// onIncrease: () => void -// onDecrease: () => void -// }> = ({ quantity, onIncrease, onDecrease }) => { -// return ( -// -// -// {quantity} -// -// -// ) -// } diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/PayProjectModal.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/PayProjectModal.tsx index 466aede953..0fe15b45fa 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/PayProjectModal.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/PayProjectModal.tsx @@ -3,11 +3,13 @@ import EtherscanLink from 'components/EtherscanLink' import ExternalLink from 'components/ExternalLink' import { JuiceModal } from 'components/modals/JuiceModal' import { Formik } from 'formik' -import Image from "next/legacy/image" +import Image from 'next/legacy/image' +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' import { twMerge } from 'tailwind-merge' import { helpPagePath } from 'utils/helpPagePath' import { MessageSection } from './components/MessageSection' import { ReceiveSection } from './components/ReceiveSection' +import { usePayAmounts } from './hooks/usePayAmounts' import { PayProjectModalFormValues, usePayProjectModal, @@ -16,8 +18,6 @@ import { export const PayProjectModal: React.FC = () => { const { open, - primaryAmount, - secondaryAmount, validationSchema, isTransactionPending, isTransactionConfirmed, @@ -27,6 +27,7 @@ export const PayProjectModal: React.FC = () => { setOpen, onPaySubmit, } = usePayProjectModal() + const { formattedTotalAmount } = usePayAmounts() return ( @@ -50,7 +51,7 @@ export const PayProjectModal: React.FC = () => { position="top" okLoading={props.isSubmitting || isTransactionPending} okButtonForm="PayProjectModalForm" - okText={t`Pay ${primaryAmount}`} + okText={t`Pay ${formattedTotalAmount.primaryAmount}`} cancelText={ isTransactionPending || isTransactionConfirmed ? t`Close` @@ -97,19 +98,7 @@ export const PayProjectModal: React.FC = () => { ) : ( <>
-
- - Total amount - -
- {primaryAmount}{' '} - {secondaryAmount && ( - - ({secondaryAmount}) - - )} -
-
+ @@ -172,3 +161,60 @@ export const PayProjectModal: React.FC = () => { ) } + +const AmountSection = () => { + const { data: nftCredits } = useV4UserNftCredits() + const { formattedAmount, formattedNftCredits, formattedTotalAmount } = + usePayAmounts() + + const RowData = ({ + label, + primaryAmount, + secondaryAmount, + }: { + label: React.ReactNode + primaryAmount: React.ReactNode + secondaryAmount: React.ReactNode + }) => ( +
+ {label} +
+ {primaryAmount}{' '} + {secondaryAmount && ( + + ({secondaryAmount}) + + )} +
+
+ ) + + if (!nftCredits || nftCredits <= 0n || !formattedNftCredits) + return ( + + ) + + return ( +
+ + + +
+ ) +} diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveNftItem.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveNftItem.tsx new file mode 100644 index 0000000000..d1072d7a1c --- /dev/null +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveNftItem.tsx @@ -0,0 +1,37 @@ +import { Trans } from '@lingui/macro' +import { CartItemBadge } from 'components/CartItemBadge' +import { SmallNftSquare } from 'components/NftRewards/SmallNftSquare' +import { useNftCartItem } from 'packages/v4/hooks/useNftCartItem' +import { twMerge } from 'tailwind-merge' +import { ProjectCartNftReward } from '../../../ReduxProjectCartProvider' + +export const ReceiveNftItem = ({ + className, + nftReward, +}: { + className?: string + nftReward: ProjectCartNftReward +}) => { + const { fileUrl, name, quantity } = useNftCartItem(nftReward) + + return ( +
+
+
+ + {name} + + NFT + +
+
{quantity}
+
+
+ ) +} diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveSection.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveSection.tsx index 4d0a946216..fdb45559e5 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveSection.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveSection.tsx @@ -6,6 +6,7 @@ import { } from '../hooks/usePayProjectModal/usePayProjectModal' import { useProjectPaymentTokens } from '../hooks/useProjectPaymentTokens' import { EditRewardBeneficiary } from './EditRewardBeneficiary' +import { ReceiveNftItem } from './ReceiveNftItem' import { ReceiveTokensItem } from './ReceiveTokensItem' export const ReceiveSection = ({ className }: { className?: string }) => { @@ -36,6 +37,13 @@ export const ReceiveSection = ({ className }: { className?: string }) => {
+ {nftRewards.map(nftReward => ( + + ))}
) } diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveTokensItem.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveTokensItem.tsx index 3aa82bbce0..99a24668d8 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveTokensItem.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/components/ReceiveTokensItem.tsx @@ -2,7 +2,6 @@ import { Trans } from '@lingui/macro' import { CartItemBadge } from 'components/CartItemBadge' import { ProjectHeaderLogo } from 'components/Project/ProjectHeader/ProjectHeaderLogo' import { twMerge } from 'tailwind-merge' -// import { useProjectHasErc20Token } from 'packages/v2v3/components/V2V3Project/ProjectDashboard/hooks/useProjectHasErc20Token' // import { BUYBACK_DELEGATE_ENABLED_PROJECT_IDS } from 'packages/v2v3/constants/buybackDelegateEnabledProjectIds' import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' import { useProjectPaymentTokens } from '../hooks/useProjectPaymentTokens' @@ -11,7 +10,6 @@ export const ReceiveTokensItem = ({ className }: { className?: string }) => { const { receivedTickets, receivedTokenSymbolText } = useProjectPaymentTokens() const projectHasErc20Token = useProjectHasErc20Token() - if (receivedTickets === '0') { return null } @@ -24,11 +22,11 @@ export const ReceiveTokensItem = ({ className }: { className?: string }) => { {receivedTokenSymbolText} - { projectHasErc20Token ? + {projectHasErc20Token ? ( ERC-20 - : null} + ) : null}
{receivedTickets}
diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayAmounts.ts b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayAmounts.ts new file mode 100644 index 0000000000..2ea6141cc6 --- /dev/null +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayAmounts.ts @@ -0,0 +1,132 @@ +import { useCurrencyConverter } from 'hooks/useCurrencyConverter' +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' +import { V4_CURRENCY_ETH, V4_CURRENCY_USD } from 'packages/v4/utils/currency' +import { formatCurrencyAmount } from 'packages/v4/utils/formatCurrencyAmount' +import React from 'react' +import { fromWad, parseWad } from 'utils/format/formatNumber' +import { useProjectSelector } from '../../../redux/hooks' +import { usePayProjectModal } from './usePayProjectModal/usePayProjectModal' + +export const usePayAmounts = () => { + const converter = useCurrencyConverter() + const { payAmount } = useProjectSelector(state => state.projectCart) + const { primaryAmount, secondaryAmount } = usePayProjectModal() + const { data: nftCreditsData } = useV4UserNftCredits() + + const payAmountRaw = React.useMemo(() => { + if (!payAmount) return + + switch (payAmount.currency) { + case V4_CURRENCY_ETH: + return { + eth: parseWad(payAmount.amount), + usd: converter.weiToUsd(parseWad(payAmount.amount))!, + } + case V4_CURRENCY_USD: + return { + eth: converter.usdToWei(payAmount.amount), + usd: parseWad(payAmount.amount), + } + } + }, [converter, payAmount]) + + const appliedNFTCreditsRaw = React.useMemo(() => { + if (!payAmountRaw || !nftCreditsData) return + + const nftCreditsApplied = payAmountRaw.eth.lt(nftCreditsData) + ? payAmountRaw.eth + : nftCreditsData + + const eth = nftCreditsApplied + const usd = parseWad(converter.weiToUsd(nftCreditsApplied))! + + return { + eth, + usd, + } + }, [converter, nftCreditsData, payAmountRaw]) + + const formattedNftCredits = React.useMemo(() => { + if (!appliedNFTCreditsRaw || !payAmount) return + + switch (payAmount.currency) { + case V4_CURRENCY_ETH: + return { + primaryAmount: formatCurrencyAmount({ + amount: fromWad(appliedNFTCreditsRaw.eth), + currency: V4_CURRENCY_ETH, + }), + secondaryAmount: formatCurrencyAmount({ + amount: fromWad(appliedNFTCreditsRaw.usd), + currency: V4_CURRENCY_USD, + }), + } + case V4_CURRENCY_USD: + return { + primaryAmount: formatCurrencyAmount({ + amount: fromWad(appliedNFTCreditsRaw.usd), + currency: V4_CURRENCY_USD, + }), + secondaryAmount: formatCurrencyAmount({ + amount: fromWad(appliedNFTCreditsRaw.eth), + currency: V4_CURRENCY_ETH, + }), + } + } + }, [appliedNFTCreditsRaw, payAmount]) + + const formattedTotalAmount = React.useMemo(() => { + if (!payAmountRaw || !payAmount) return + + if (!appliedNFTCreditsRaw) { + return { + primaryAmount: primaryAmount, + secondaryAmount: secondaryAmount, + } + } + + const totalEth = payAmountRaw.eth.sub(appliedNFTCreditsRaw.eth) + const totalUsd = converter.weiToUsd(parseWad(totalEth)) + + const formattedEth = formatCurrencyAmount({ + amount: fromWad(totalEth), + currency: V4_CURRENCY_ETH, + }) + const formattedUsd = formatCurrencyAmount({ + amount: fromWad(totalUsd), + currency: V4_CURRENCY_USD, + }) + + switch (payAmount?.currency) { + case V4_CURRENCY_ETH: + return { + primaryAmount: formattedEth, + secondaryAmount: formattedUsd, + } + case V4_CURRENCY_USD: + return { + primaryAmount: formattedUsd, + secondaryAmount: formattedEth, + } + } + }, [ + appliedNFTCreditsRaw, + converter, + payAmount, + payAmountRaw, + primaryAmount, + secondaryAmount, + ]) + + return { + formattedAmount: { primaryAmount, secondaryAmount }, + formattedNftCredits: { + primaryAmount: formattedNftCredits?.primaryAmount, + secondaryAmount: formattedNftCredits?.secondaryAmount, + }, + formattedTotalAmount: { + primaryAmount: formattedTotalAmount?.primaryAmount, + secondaryAmount: formattedTotalAmount?.secondaryAmount, + }, + } +} diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayProjectModal/usePayProjectTx.ts b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayProjectModal/usePayProjectTx.ts index 16005cb97f..7116194971 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayProjectModal/usePayProjectTx.ts +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayProjectModal/hooks/usePayProjectModal/usePayProjectTx.ts @@ -1,19 +1,21 @@ +import { waitForTransactionReceipt } from '@wagmi/core' +import { TxHistoryContext } from 'contexts/Transaction/TxHistoryContext' import { FormikHelpers } from 'formik' import { useWallet } from 'hooks/Wallet' import { useCurrencyConverter } from 'hooks/useCurrencyConverter' -import { useProjectSelector } from 'packages/v4/components/ProjectDashboard/redux/hooks' -import { ProjectPayReceipt } from 'packages/v4/views/V4ProjectDashboard/hooks/useProjectPageQueries' -// import { NftRewardsContext } from 'packages/v4/contexts/NftRewards/NftRewardsContext' -// import { useProjectHasErc20 } from 'packages/v4/hooks/useProjectHasErc20' -import { waitForTransactionReceipt } from '@wagmi/core' -import { TxHistoryContext } from 'contexts/Transaction/TxHistoryContext' -import { NATIVE_TOKEN } from 'juice-sdk-core' +import { DEFAULT_METADATA, NATIVE_TOKEN } from 'juice-sdk-core' import { useJBContractContext, + useJBRulesetContext, + usePreparePayMetadata, useWriteJbMultiTerminalPay, } from 'juice-sdk-react' -// import { useProjectHasErc20 } from 'packages/v2v3/hooks/useProjectHasErc20' +import { useProjectSelector } from 'packages/v4/components/ProjectDashboard/redux/hooks' +import { useV4NftRewards } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' +import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' import { V4_CURRENCY_ETH } from 'packages/v4/utils/currency' +import { ProjectPayReceipt } from 'packages/v4/views/V4ProjectDashboard/hooks/useProjectPageQueries' import { wagmiConfig } from 'packages/v4/wagmiConfig' import { useCallback, useContext, useMemo } from 'react' import { buildPaymentMemo } from 'utils/buildPaymentMemo' @@ -39,15 +41,17 @@ export const usePayProjectTx = ({ ) => void }) => { const { userAddress } = useWallet() + const { data: nftCredits } = useV4UserNftCredits() const { payAmount, chosenNftRewards } = useProjectSelector( state => state.projectCart, ) - // const { - // nftRewards: { rewardTiers }, - // } = useContext(NftRewardsContext) + const { + nftRewards: { rewardTiers }, + } = useV4NftRewards() const converter = useCurrencyConverter() const { receivedTickets } = useProjectPaymentTokens() - // const projectHasErc20 = useProjectHasErc20() + // TODO: is this needed for preferClaimedTokens? + const projectHasErc20 = useProjectHasErc20Token() const buildPayReceipt = useCallback( (txHash: Hash): ProjectPayReceipt => { @@ -69,17 +73,37 @@ export const usePayProjectTx = ({ const weiAmount = useMemo(() => { if (!payAmount) { return 0n - } else if (payAmount.currency === V4_CURRENCY_ETH) { - return parseEther(payAmount.amount.toString()) - } else { - return converter.usdToWei(payAmount.amount).toBigInt() } - }, [payAmount, converter]) + let weiAmount = + payAmount.currency === V4_CURRENCY_ETH + ? parseEther(payAmount.amount.toString()) + : converter.usdToWei(payAmount.amount).toBigInt() + if (nftCredits) { + if (nftCredits >= weiAmount) { + weiAmount = 0n + } else { + weiAmount -= nftCredits + } + } - // const prepareDelegateMetadata = usePrepareDelegatePayMetadata(weiAmount, { - // nftRewards: chosenNftRewards, - // receivedTickets, - // }) + return weiAmount + }, [converter, nftCredits, payAmount]) + + const { + rulesetMetadata: { data: rulesetMetadata }, + } = useJBRulesetContext() + const metadata = usePreparePayMetadata( + rulesetMetadata?.dataHook + ? { + jb721Hook: { + dataHookAddress: rulesetMetadata.dataHook, + tierIdsToMint: chosenNftRewards + .map(({ id, quantity }) => Array(quantity).fill(BigInt(id))) + .flat(), + }, + } + : undefined, + ) const { writeContractAsync: writePay } = useWriteJbMultiTerminalPay() const { contracts, projectId } = useJBContractContext() @@ -91,7 +115,6 @@ export const usePayProjectTx = ({ formikHelpers: FormikHelpers, ) => { if ( - !weiAmount || !contracts.primaryNativeTerminal.data || !userAddress || !values.userAcceptsTerms @@ -103,13 +126,13 @@ export const usePayProjectTx = ({ const memo = buildPaymentMemo({ text: messageString, imageUrl: attachedUrl, - // nftUrls: chosenNftRewards - // .map( - // ({ id }) => - // (rewardTiers ?? []).find(({ id: tierId }) => tierId === id) - // ?.fileUrl, - // ) - // .filter((url): url is string => !!url), + nftUrls: chosenNftRewards + .map( + ({ id }) => + (rewardTiers ?? []).find(({ id: tierId }) => tierId === id) + ?.fileUrl, + ) + .filter((url): url is string => !!url), }) const beneficiary = (values.beneficiaryAddress ?? userAddress) as Address const args = [ @@ -119,9 +142,15 @@ export const usePayProjectTx = ({ beneficiary, 0n, memo, - '0x0', + metadata ?? DEFAULT_METADATA, ] as const + // SIMULATE TRANSACTION: + // const encodedData = encodeFunctionData({ + // abi: jbMultiTerminalAbi, // ABI of the contract + // functionName: 'pay', + // args, + // }) try { const hash = await writePay({ address: contracts.primaryNativeTerminal.data, @@ -147,21 +176,19 @@ export const usePayProjectTx = ({ } }, [ - // projectHasErc20, - buildPayReceipt, - // chosenNftRewards, - onTransactionConfirmedCallback, - onTransactionErrorCallback, - onTransactionPendingCallback, - // payProjectTx, - // rewardTiers, weiAmount, + contracts.primaryNativeTerminal.data, userAddress, - // prepareDelegateMetadata, + chosenNftRewards, projectId, + metadata, + rewardTiers, writePay, - contracts.primaryNativeTerminal.data, + onTransactionPendingCallback, addTransaction, + onTransactionConfirmedCallback, + buildPayReceipt, + onTransactionErrorCallback, ], ) } diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayRedeemInput.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayRedeemInput.tsx index 7afc137db8..681536befa 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayRedeemInput.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/PayRedeemInput.tsx @@ -1,10 +1,21 @@ -import { ArrowDownIcon } from '@heroicons/react/24/outline' +import { + ArrowDownIcon, + MinusIcon, + PlusIcon, + TrashIcon, +} from '@heroicons/react/24/outline' import { t } from '@lingui/macro' import { Tooltip } from 'antd' +import { CartItemBadge } from 'components/CartItemBadge' +import { SmallNftSquare } from 'components/NftRewards/SmallNftSquare' +import { TruncatedText } from 'components/TruncatedText' +import { emitConfirmationDeletionModal } from 'hooks/emitConfirmationDeletionModal' import { useCurrencyConverter } from 'hooks/useCurrencyConverter' +import { useNftCartItem } from 'packages/v4/hooks/useNftCartItem' import { V4_CURRENCY_USD } from 'packages/v4/utils/currency' import { formatCurrencyAmount } from 'packages/v4/utils/formatCurrencyAmount' -import { ReactNode, useMemo } from 'react' +import { useProjectPageQueries } from 'packages/v4/views/V4ProjectDashboard/hooks/useProjectPageQueries' +import React, { ReactNode, useMemo } from 'react' import { twMerge } from 'tailwind-merge' import { formatAmount } from 'utils/format/formatAmount' import { ProjectCartNftReward } from '../ReduxProjectCartProvider' @@ -134,14 +145,13 @@ export const PayRedeemInput = ({
)} - {/* {nfts && nfts?.length > 0 && ( + {nfts && nfts?.length > 0 && (
{nfts.map((nft, i) => ( ))}
)} - */}
{downArrow && ( @@ -208,3 +218,109 @@ const DownArrow = ({ className }: { className?: string }) => {
) } + +const NftReward: React.FC<{ + nft: ProjectCartNftReward + className?: string +}> = ({ nft, className }) => { + const { + price, + name, + quantity, + fileUrl, + removeNft, + increaseQuantity, + decreaseQuantity, + } = useNftCartItem(nft) + const { setProjectPageTab } = useProjectPageQueries() + + const handleRemove = React.useCallback(() => { + emitConfirmationDeletionModal({ + onConfirm: removeNft, + title: t`Remove NFT`, + description: t`Are you sure you want to remove this NFT?`, + }) + }, [removeNft]) + + const handleDecreaseQuantity = React.useCallback(() => { + if (quantity - 1 <= 0) { + handleRemove() + } else { + decreaseQuantity() + } + }, [decreaseQuantity, handleRemove, quantity]) + + const priceText = useMemo(() => { + if (price === null) { + return '-' + } + return formatCurrencyAmount(price) + }, [price]) + + return ( +
+
+ +
+
setProjectPageTab('nft_rewards')} + > + + NFT +
+ +
{priceText}
+
+
+ +
+ + +
+
+ ) +} + +const RemoveIcon: React.FC<{ onClick: () => void }> = ({ onClick }) => ( + +) + +const QuantityControl: React.FC<{ + quantity: number + onIncrease: () => void + onDecrease: () => void +}> = ({ quantity, onIncrease, onDecrease }) => { + return ( + + + {quantity} + + + ) +} diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/RedeemConfiguration.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/RedeemConfiguration.tsx index 17048aa8ee..65f9880744 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/RedeemConfiguration.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/RedeemConfiguration.tsx @@ -73,7 +73,7 @@ export const RedeemConfiguration: React.FC = ({ const balance = userTokenBalance ?? 0 return amount > balance }, [redeemAmount, userTokenBalance]) - + const tokenTicker = tokenSymbol || 'TOKENS' // 0.5% slippage for USD-denominated tokens diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4NftCreditsCallouts.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4NftCreditsCallouts.tsx new file mode 100644 index 0000000000..787d11e527 --- /dev/null +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4NftCreditsCallouts.tsx @@ -0,0 +1,41 @@ +import { CubeIcon } from '@heroicons/react/24/outline' +import { Trans } from '@lingui/macro' +import { Button } from 'antd' +import { formatEther } from 'juice-sdk-core' +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' +import { useProjectPageQueries } from 'packages/v4/views/V4ProjectDashboard/hooks/useProjectPageQueries' + +export function V4NftCreditsCallouts() { + const { setProjectPageTab } = useProjectPageQueries() + const { data: nftCredits } = useV4UserNftCredits() + + if (!nftCredits || nftCredits <= 0n) { + return null + } + + return ( +
+
+
+ +
+ + You have{' '} + {formatEther(nftCredits)} ETH{' '} + of unclaimed NFT credits + +
+ +
+ ) +} diff --git a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4PayRedeemCard.tsx b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4PayRedeemCard.tsx index fb63e4426d..850d808cd0 100644 --- a/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4PayRedeemCard.tsx +++ b/src/packages/v4/components/ProjectDashboard/V4PayRedeemCard/V4PayRedeemCard.tsx @@ -3,15 +3,19 @@ import { Trans, t } from '@lingui/macro' import { Tooltip } from 'antd' import { Callout } from 'components/Callout/Callout' import { useJBRulesetContext } from 'juice-sdk-react' +import { useV4NftRewards } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' import { usePayoutLimit } from 'packages/v4/hooks/usePayoutLimit' +import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' -import { ReactNode } from 'react' +import { useV4TokensPanel } from 'packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel' +import React, { ReactNode } from 'react' import { twMerge } from 'tailwind-merge' import { useProjectDispatch, useProjectSelector } from '../redux/hooks' import { payRedeemActions } from '../redux/payRedeemSlice' import { PayConfiguration } from './PayConfiguration' import { PayProjectModal } from './PayProjectModal/PayProjectModal' import { RedeemConfiguration } from './RedeemConfiguration' +import { V4NftCreditsCallouts } from './V4NftCreditsCallouts' type PayRedeemCardProps = { className?: string @@ -22,18 +26,18 @@ export const V4PayRedeemCard: React.FC = ({ }) => { const { ruleset, rulesetMetadata } = useJBRulesetContext() const state = useProjectSelector(state => state.payRedeem.cardState) - // const { value: hasNfts, loading: hasNftsLoading } = useHasNftRewards() + const nftRewards = useV4NftRewards() const { data: payoutLimit } = usePayoutLimit() const dispatch = useProjectDispatch() - const projectHasErc20Token = false // TODO + const projectHasErc20Token = useProjectHasErc20Token() // TODO: We should probably break out tokens panel hook into reusable module - // const { userTokenBalance: panelBalance } = useTokensPanel() - // const tokenBalance = panelBalance - // ? parseFloat(panelBalance.replaceAll(',', '')) - // : undefined - const tokenBalance = 0 // TODO + const { userTokenBalance: panelBalance } = useV4TokensPanel() + const tokenBalance = React.useMemo(() => { + if (!panelBalance) return undefined + return panelBalance.toFloat() + }, [panelBalance]) const redeems = { loading: ruleset.isLoading, enabled: @@ -41,15 +45,25 @@ export const V4PayRedeemCard: React.FC = ({ rulesetMetadata.data.redemptionRate.value > 0n, } - const weight = ruleset.data?.weight - const isIssuingTokens = Boolean(weight && weight.value > 0n) - // const showNfts = hasNfts && !hasNftsLoading - const noticeText = isIssuingTokens - ? // showNfts - // ? t`Project isn't currently issuing tokens, but is issuing NFTs` - // : - t`Project isn't currently issuing tokens` - : undefined + const isIssuingTokens = React.useMemo(() => { + const weight = ruleset.data?.weight + return Boolean(weight && weight.value > 0n) + }, [ruleset.data?.weight]) + + const noticeText = React.useMemo(() => { + if (!isIssuingTokens) { + return undefined + } + const showNfts = + !nftRewards.loading && + (nftRewards.nftRewards.rewardTiers ?? []).length > 0 + + if (showNfts) { + return t`Project is currently only issuing NFTs` + } + + return t`Project isn't currently issuing tokens` + }, [isIssuingTokens, nftRewards.loading, nftRewards.nftRewards.rewardTiers]) const redeemDisabled = !rulesetMetadata.data?.redemptionRate || @@ -111,9 +125,10 @@ export const V4PayRedeemCard: React.FC = ({ )} - {/* */} - {/* - {projectHasErc20Token && unclaimedTokenBalance?.gt(0) && ( + + + {/* TODO */} + {/* {projectHasErc20Token && unclaimedTokenBalance?.gt(0) && ( )} */} diff --git a/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/SuccessPayView.tsx b/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/SuccessPayView.tsx index abbee4066b..4a3ebc13cd 100644 --- a/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/SuccessPayView.tsx +++ b/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/SuccessPayView.tsx @@ -5,6 +5,7 @@ import dynamic from 'next/dynamic' import Link from 'next/link' import { v4ProjectRoute } from 'packages/v4/utils/routes' import { useChainId } from 'wagmi' +import { SuccessNftItem } from './components/SuccessNftItem' import { SuccessPayCard } from './components/SuccessPayCard' import { SuccessTokensItem } from './components/SuccessTokensItem' import { useSuccessPayView } from './hooks/useSuccessPayView' @@ -78,6 +79,9 @@ export const SuccessPayView = () => { Your NFTs & Rewards
+ {projectPayReceipt?.nfts.map(({ id }) => ( + + ))}
diff --git a/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/components/SuccessNftItem.tsx b/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/components/SuccessNftItem.tsx new file mode 100644 index 0000000000..c494bb7108 --- /dev/null +++ b/src/packages/v4/components/ProjectDashboard/components/SuccessPayView/components/SuccessNftItem.tsx @@ -0,0 +1,48 @@ +import { Trans } from '@lingui/macro' +import { CartItemBadge } from 'components/CartItemBadge' +import { NftPreview } from 'components/NftRewards/NftPreview' +import { SmallNftSquare } from 'components/NftRewards/SmallNftSquare' +import { useV4NftRewards } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import { useMemo, useState } from 'react' + +export const SuccessNftItem = ({ id }: { id: number }) => { + const { + nftRewards: { rewardTiers }, + } = useV4NftRewards() + const [previewVisible, setPreviewVisible] = useState(false) + + const openPreview = () => setPreviewVisible(true) + + const rewardTier = useMemo(() => { + if (!rewardTiers) return undefined + const nftReward = rewardTiers.find(reward => reward.id === id) + return nftReward + }, [id, rewardTiers]) + + return ( + <> +
+ + + {rewardTier?.name ?? ''} + + + NFT + +
+ {rewardTier && ( + + )} + + ) +} diff --git a/src/packages/v4/contexts/V4NftRewards/V4NftRewardsProvider.tsx b/src/packages/v4/contexts/V4NftRewards/V4NftRewardsProvider.tsx new file mode 100644 index 0000000000..44a6d1778c --- /dev/null +++ b/src/packages/v4/contexts/V4NftRewards/V4NftRewardsProvider.tsx @@ -0,0 +1,126 @@ +import { + jb721TiersHookStoreAbi, + useJBRulesetContext, + useReadJb721TiersHookPricingContext, + useReadJb721TiersHookStoreAddress, + useReadJb721TiersHookStoreFlagsOf, + useReadJb721TiersHookStoreTiersOf, +} from 'juice-sdk-react' +import { JB721GovernanceType } from 'models/nftRewards' +import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' +import React, { createContext } from 'react' +import { DEFAULT_NFT_PRICING } from 'redux/slices/editingV2Project' +import { NftRewardsData } from 'redux/slices/shared/v2ProjectTypes' +import { CIDsOfNftRewardTiersResponse } from 'utils/nftRewards' +import { ContractFunctionReturnType } from 'viem' +import { useNftRewards } from './useNftRewards' + +const DEFAULT_NFT_FLAGS = { + noNewTiersWithReserves: false, + noNewTiersWithVotes: false, + noNewTiersWithOwnerMinting: false, + preventOverspending: false, +} + +// TODO: This should be imported from the SDK +export type JB721TierV4 = ContractFunctionReturnType< + typeof jb721TiersHookStoreAbi, + 'view', + 'tiersOf' +>[0] + +type NftRewardsContextType = { + // nftRewards: is useReadJb721TiersHookStoreTiersOf.data returned + nftRewards: Omit< + NftRewardsData, + 'flags' | 'collectionMetadata' | 'postPayModal' + > + loading: boolean | undefined +} + +export const V4NftRewardsContext = createContext({ + nftRewards: { + CIDs: undefined, + rewardTiers: undefined, + // postPayModal: undefined, + // collectionMetadata: EMPTY_NFT_COLLECTION_METADATA, + // flags: DEFAULT_NFT_FLAGS, + governanceType: JB721GovernanceType.NONE, + pricing: DEFAULT_NFT_PRICING, + }, + loading: false, +}) + +export const V4NftRewardsProvider: React.FC< + React.PropsWithChildren +> = ({ children }) => { + const jbRuleSet = useJBRulesetContext() + const dataHookAddress = jbRuleSet.rulesetMetadata.data?.dataHook + + const storeAddress = useReadJb721TiersHookStoreAddress({ + address: dataHookAddress, + }) + + const tiersOf = useReadJb721TiersHookStoreTiersOf({ + address: storeAddress.data, + args: [ + dataHookAddress ?? `0x${'0'.repeat(40)}`, + [], // _categories + false, // _includeResolvedUri, return in each tier a result from a tokenUriResolver if one is included in the delegate + 0n, // _startingId + 10n, // limit + ], + }) + + const { data: loadedRewardTiers, isLoading: nftRewardTiersLoading } = + useNftRewards(tiersOf.data ?? [], 4, storeAddress.data) + + const loadedCIDs = CIDsOfNftRewardTiersResponse(tiersOf.data ?? []) + + const p = useReadJb721TiersHookPricingContext() + const currency = Number(p.data ? p.data[0] : 0) as V2V3CurrencyOption + + const flags = useReadJb721TiersHookStoreFlagsOf({ + address: '0x7b1F4Ba6312A104E645B06Ab97e4CaA1ef0F773f', + }) + + const loading = React.useMemo( + () => + storeAddress.isLoading || + tiersOf.isLoading || + nftRewardTiersLoading || + p.isLoading || + flags.isLoading, + [ + storeAddress.isLoading, + tiersOf.isLoading, + nftRewardTiersLoading, + p.isLoading, + flags.isLoading, + ], + ) + + const ctx = { + nftRewards: { + CIDs: loadedCIDs, + rewardTiers: loadedRewardTiers, + pricing: { currency }, + governanceType: JB721GovernanceType.NONE, + // collectionMetadata: { + // ...EMPTY_NFT_COLLECTION_METADATA, + // uri: collection + // } + // postPayModal: projectMetadata?.nftPaymentSuccessModal, + // flags: flags.data ?? DEFAULT_NFT_FLAGS, + }, + loading, + } + + return ( + + {children} + + ) +} + +export const useV4NftRewards = () => React.useContext(V4NftRewardsContext) diff --git a/src/packages/v4/contexts/V4NftRewards/useNftRewards.ts b/src/packages/v4/contexts/V4NftRewards/useNftRewards.ts new file mode 100644 index 0000000000..463806752b --- /dev/null +++ b/src/packages/v4/contexts/V4NftRewards/useNftRewards.ts @@ -0,0 +1,59 @@ +import { useQuery, UseQueryResult } from '@tanstack/react-query' +import axios from 'axios' +import { formatEther } from 'juice-sdk-core' +import { IPFSNftRewardTier, NftRewardTier } from 'models/nftRewards' +import { withHttps } from 'utils/externalLink' +import { cidFromUrl, decodeEncodedIpfsUri, ipfsGatewayUrl } from 'utils/ipfs' +import { JB721TierV4 } from './V4NftRewardsProvider' + +async function fetchRewardTierMetadata({ tier }: { tier: JB721TierV4 }) { + const tierCid = decodeEncodedIpfsUri(tier.encodedIPFSUri) + const url = ipfsGatewayUrl(tierCid) + + const response = await axios.get(url) + const tierMetadata: IPFSNftRewardTier = response.data + + const maxSupply = tier.initialSupply + + // Some projects have image links hard-coded to the old IPFS gateway. + const pinataRegex = /^(https?:\/\/jbx\.mypinata\.cloud)/ + if (tierMetadata?.image && pinataRegex.test(tierMetadata.image)) { + const imageUrlCid = cidFromUrl(tierMetadata.image) + tierMetadata.image = ipfsGatewayUrl(imageUrlCid) + } + + const rawContributionFloor = tier.price + + return { + id: tier.id, + name: tierMetadata.name, + description: tierMetadata.description, + externalLink: withHttps(tierMetadata.externalLink), + // convert rawContributionFloor bigint to a number + contributionFloor: formatEther(rawContributionFloor), + maxSupply, + remainingSupply: tier.remainingSupply, + fileUrl: tierMetadata.image, + beneficiary: tier.reserveBeneficiary, + reservedRate: tier.reserveFrequency, + votingWeight: tier.votingUnits, + } +} + +export const useNftRewards = ( + tiers: readonly JB721TierV4[], + projectId: number | undefined, + dataSourceAddress: string | undefined, +): UseQueryResult => { + const enabled = Boolean(tiers?.length) + + return useQuery({ + queryKey: ['nftRewards', projectId, dataSourceAddress], + enabled, + queryFn: async () => { + return await Promise.all( + tiers.map(tier => fetchRewardTierMetadata({ tier })), + ) + }, + }) +} diff --git a/src/packages/v4/contexts/V4ProjectMetadataProvider.tsx b/src/packages/v4/contexts/V4ProjectMetadataProvider.tsx index 9841567941..d92dc5bbfd 100644 --- a/src/packages/v4/contexts/V4ProjectMetadataProvider.tsx +++ b/src/packages/v4/contexts/V4ProjectMetadataProvider.tsx @@ -1,6 +1,7 @@ +import { useJBProjectMetadataContext } from 'juice-sdk-react' + import { PV_V4 } from 'constants/pv' import { ProjectMetadataContext } from 'contexts/ProjectMetadataContext' -import { useJBProjectMetadataContext } from 'juice-sdk-react' import { PropsWithChildren } from 'react' export default function V4ProjectMetadataProvider({ diff --git a/src/packages/v4/contexts/V4SettingsProvider.tsx b/src/packages/v4/contexts/V4SettingsProvider.tsx index 7584fdfe32..ff076eedd5 100644 --- a/src/packages/v4/contexts/V4SettingsProvider.tsx +++ b/src/packages/v4/contexts/V4SettingsProvider.tsx @@ -9,6 +9,7 @@ import { WagmiProvider } from 'wagmi' import { chainNameMap } from '../utils/networks' import { EditCycleFormProvider } from '../views/V4ProjectSettings/EditCyclePage/EditCycleFormContext' import { wagmiConfig } from '../wagmiConfig' +import { V4NftRewardsProvider } from './V4NftRewards/V4NftRewardsProvider' import V4ProjectMetadataProvider from './V4ProjectMetadataProvider' export const V4SettingsProvider: React.FC = ({ @@ -33,15 +34,17 @@ export const V4SettingsProvider: React.FC = ({ metadata: { ipfsGatewayHostname: OPEN_IPFS_GATEWAY_HOSTNAME }, }} > - - - - - {children} - - - - + + + + + + {children} + + + + + diff --git a/src/packages/v4/contexts/V4UserNftCreditsProvider.tsx b/src/packages/v4/contexts/V4UserNftCreditsProvider.tsx new file mode 100644 index 0000000000..d9bcaebb05 --- /dev/null +++ b/src/packages/v4/contexts/V4UserNftCreditsProvider.tsx @@ -0,0 +1,37 @@ +import { useWallet } from 'hooks/Wallet' +import { + useJBRulesetContext, + useReadJb721TiersHookPayCreditsOf, +} from 'juice-sdk-react' +import React, { PropsWithChildren } from 'react' + +const V4UserNftCreditsContext = React.createContext<{ + data: bigint | undefined + isLoading: boolean +}>({ + data: undefined, + isLoading: false, +}) + +export const V4UserNftCreditsProvider: React.FC = ({ + children, +}) => { + const { userAddress } = useWallet() + const { + rulesetMetadata: { data: rulesetMetadata }, + } = useJBRulesetContext() + const creds = useReadJb721TiersHookPayCreditsOf({ + address: rulesetMetadata?.dataHook, + args: userAddress ? [userAddress] : undefined, + }) + + return ( + + {children} + + ) +} + +export const useV4UserNftCredits = () => { + return React.useContext(V4UserNftCreditsContext) +} diff --git a/src/packages/v4/contexts/V4UserTotalTokensBalanceProvider.tsx b/src/packages/v4/contexts/V4UserTotalTokensBalanceProvider.tsx new file mode 100644 index 0000000000..b92ec5bcaa --- /dev/null +++ b/src/packages/v4/contexts/V4UserTotalTokensBalanceProvider.tsx @@ -0,0 +1,34 @@ +import { useWallet } from 'hooks/Wallet' +import { + useJBContractContext, + useReadJbTokensTotalBalanceOf, +} from 'juice-sdk-react' +import React, { PropsWithChildren } from 'react' +import { zeroAddress } from 'viem' + +const V4UserTotalTokensBalanceContext = React.createContext<{ + data: bigint | undefined + isLoading: boolean +}>({ + data: undefined, + isLoading: false, +}) + +export const V4UserTotalTokensBalanceProvider: React.FC = ({ + children, +}) => { + const { userAddress } = useWallet() + const { projectId } = useJBContractContext() + const value = useReadJbTokensTotalBalanceOf({ + args: [userAddress ?? zeroAddress, projectId], + }) + + return ( + + {children} + + ) +} + +export const useV4UserTotalTokensBalance = () => + React.useContext(V4UserTotalTokensBalanceContext) diff --git a/src/packages/v4/hooks/JB721Delegate/contractReader/useNftDeployerCanReconfigure.ts b/src/packages/v4/hooks/JB721Delegate/contractReader/useNftDeployerCanReconfigure.ts new file mode 100644 index 0000000000..a53b48f518 --- /dev/null +++ b/src/packages/v4/hooks/JB721Delegate/contractReader/useNftDeployerCanReconfigure.ts @@ -0,0 +1,16 @@ +import { V4OperatorPermission } from 'packages/v4/models/v4Permissions' +import { useV4WalletHasPermission } from '../../useV4WalletHasPermission' + +/** + * Checks whether the given [projectOwnerAddress] has given the JBTiered721DelegateProjectDeployer + * permission to queue rulesets for the given [projectId]. + * + * This must be true for the following circumstances (non-exhaustive): + * - A project is reconfiguring their FC to include NFTs + * - A project is launching their V3 FC with NFTs + */ +export function useNftDeployerCanReconfigure() { + const JBTiered721DelegateProjectDeployerCanReconfigure = useV4WalletHasPermission(V4OperatorPermission.QUEUE_RULESETS) + + return JBTiered721DelegateProjectDeployerCanReconfigure +} diff --git a/src/packages/v4/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts b/src/packages/v4/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts new file mode 100644 index 0000000000..9fd869a9a0 --- /dev/null +++ b/src/packages/v4/hooks/JB721Delegate/transactor/useLaunchProjectWithNftsTx.ts @@ -0,0 +1,220 @@ +import { + DEFAULT_MEMO, + NATIVE_TOKEN, + NATIVE_TOKEN_DECIMALS, +} from 'juice-sdk-core' +import { + jbPricesAddress, + useJBContractContext, + useWriteJb721TiersHookProjectDeployerLaunchProjectFor +} from 'juice-sdk-react' +import { + JBDeploy721TiersHookConfig, + LaunchProjectWithNftsTxArgs, +} from 'packages/v4/models/nfts' +import { Address, WaitForTransactionReceiptReturnType, zeroAddress } from 'viem' +import { + LaunchV2V3ProjectArgs, + transformV2V3CreateArgsToV4, +} from '../../../utils/launchProjectTransformers' +import { + LaunchTxOpts, + SUPPORTED_JB_CONTROLLER_ADDRESS, + SUPPORTED_JB_MULTITERMINAL_ADDRESS, +} from '../../useLaunchProjectTx' + +import { waitForTransactionReceipt } from '@wagmi/core' +import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' +import { TxHistoryContext } from 'contexts/Transaction/TxHistoryContext' +import { useWallet } from 'hooks/Wallet' +import { isValidMustStartAtOrAfter } from 'packages/v2v3/utils/fundingCycle' +import { wagmiConfig } from 'packages/v4/wagmiConfig' +import { useContext } from 'react' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' +import { ipfsUri } from 'utils/ipfs' +import { useChainId } from 'wagmi' + +/** + * Return the project ID created from a `launchProjectFor` transaction. + * @param txReceipt receipt of `launchProjectFor` transaction + */ +export const getProjectIdFromNftLaunchReceipt = ( + txReceipt: WaitForTransactionReceiptReturnType, +): number => { + const projectIdHex: string | undefined = txReceipt?.logs[0]?.topics?.[1] + if (!projectIdHex) return 0 + + const projectId = parseInt(projectIdHex, 16) + return projectId +} + +/** + * The contract addresses to use for deployment + * @todo not ideal to hardcode these addresses + */ +export const SUPPORTED_JB_721_TIER_STORE = { + '84532': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, + '421614': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, + '11155111': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, + '11155420': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, +} + +export function useLaunchProjectWithNftsTx() { + const { contracts } = useJBContractContext() + const { addTransaction } = useContext(TxHistoryContext) + + const { userAddress } = useWallet() + const chainId = useChainId() + const chainIdStr = + chainId?.toString() as keyof typeof SUPPORTED_JB_MULTITERMINAL_ADDRESS + + const defaultJBController = chainId + ? SUPPORTED_JB_CONTROLLER_ADDRESS[chainIdStr] + : undefined + const defaultJBETHPaymentTerminal = chainId + ? SUPPORTED_JB_MULTITERMINAL_ADDRESS[chainIdStr] + : undefined + const JBTiered721DelegateStoreAddress = chainId + ? SUPPORTED_JB_721_TIER_STORE[chainIdStr] + : undefined + + const { writeContractAsync: writeLaunchProject } = + useWriteJb721TiersHookProjectDeployerLaunchProjectFor() + + return async ( + { + tiered721DelegateData: { + collectionUri, + collectionName, + collectionSymbol, + currency, + tiers, + flags, + }, + projectData: { + projectMetadataCID, + fundingCycleData, + fundingCycleMetadata, + fundAccessConstraints, + groupedSplits = [], + mustStartAtOrAfter = DEFAULT_MUST_START_AT_OR_AFTER, + owner, + }, + }: LaunchProjectWithNftsTxArgs, + { + onTransactionPending: onTransactionPendingCallback, + onTransactionConfirmed: onTransactionConfirmedCallback, + onTransactionError: onTransactionErrorCallback, + }: LaunchTxOpts, + ) => { + if ( + !userAddress || + !contracts || + !defaultJBController || + !defaultJBETHPaymentTerminal || + !JBTiered721DelegateStoreAddress || + !isValidMustStartAtOrAfter(mustStartAtOrAfter, fundingCycleData.duration) + ) { + const missingParam = !userAddress + ? 'userAddress' + : !contracts + ? 'contracts' + : !defaultJBController + ? 'defaultJBController' + : !JBTiered721DelegateStoreAddress + ? 'JBTiered721DelegateProjectDeployer' + : null + + onTransactionErrorCallback?.( + new DOMException( + `Transaction failed, missing argument "${ + missingParam ?? '' + }".`, + ), + ) + + return Promise.resolve(false) + } + const _owner = (owner?.length ? owner : userAddress) as Address + + const deployTiered721HookData: JBDeploy721TiersHookConfig = { + name: collectionName, + symbol: collectionSymbol, + baseUri: ipfsUri(''), + tokenUriResolver: zeroAddress, + contractUri: ipfsUri(collectionUri), + tiersConfig: { + currency, + decimals: NATIVE_TOKEN_DECIMALS, + prices: jbPricesAddress[chainIdStr], + tiers, + }, + reserveBeneficiary: zeroAddress, + flags, + } + + const v2v3LaunchProjectArgs = [ + _owner, + [projectMetadataCID, JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN], + fundingCycleData, + fundingCycleMetadata, + mustStartAtOrAfter, + groupedSplits, + fundAccessConstraints, + [defaultJBETHPaymentTerminal], // _terminals, just supporting single for now + // Eventually should be something like: + // getTerminalsFromFundAccessConstraints( + // fundAccessConstraints, + // contracts.primaryNativeTerminal.data, + // ), + DEFAULT_MEMO, + ] as LaunchV2V3ProjectArgs + const launchProjectData = transformV2V3CreateArgsToV4({ + v2v3Args: v2v3LaunchProjectArgs, + primaryNativeTerminal: defaultJBETHPaymentTerminal, + currencyTokenAddress: NATIVE_TOKEN, + }) + + const args = [ + _owner, + deployTiered721HookData, //_deployTiered721HookData + { + projectUri: launchProjectData[1], + rulesetConfigurations: launchProjectData[2], + terminalConfigurations: launchProjectData[3], + memo: launchProjectData[4], + }, // _launchProjectData, + defaultJBController, + // createSalt(), + ] as const + + try { + // SIMULATE TX: TODO update for nfts + // const encodedData = encodeFunctionData({ + // abi: jbControllerAbi, // ABI of the contract + // functionName: 'launchProjectFor', + // args, + // }) + + const hash = await writeLaunchProject({ + chainId: chainId as 84532 | 421614 | 11155111 | 11155420, // TODO: cleanup + args, + }) + + onTransactionPendingCallback(hash) + addTransaction?.('Launch Project', { hash }) + const transactionReceipt: WaitForTransactionReceiptReturnType = + await waitForTransactionReceipt(wagmiConfig, { + hash, + }) + + const newProjectId = getProjectIdFromNftLaunchReceipt(transactionReceipt) + + onTransactionConfirmedCallback(hash, newProjectId) + } catch (e) { + onTransactionErrorCallback( + (e as Error) ?? new Error('Transaction failed'), + ) + } + } +} diff --git a/src/packages/v4/hooks/useCurrentRouteChainId.ts b/src/packages/v4/hooks/useCurrentRouteChainId.ts index 58db1b737a..d5766f5bf1 100644 --- a/src/packages/v4/hooks/useCurrentRouteChainId.ts +++ b/src/packages/v4/hooks/useCurrentRouteChainId.ts @@ -5,7 +5,7 @@ export function useCurrentRouteChainId() { const router = useRouter() const { chainName } = router.query if (!chainName) { - return null + return undefined } return chainNameMap[chainName as string] diff --git a/src/packages/v4/hooks/useETHReceivedFromTokens.ts b/src/packages/v4/hooks/useETHReceivedFromTokens.ts index 0847ee6b22..d68802b0c5 100644 --- a/src/packages/v4/hooks/useETHReceivedFromTokens.ts +++ b/src/packages/v4/hooks/useETHReceivedFromTokens.ts @@ -25,19 +25,28 @@ export function useETHReceivedFromTokens( const redemptionRate = rulesetMetadata.data?.redemptionRate?.value if ( - !redemptionRate || - !totalSupply || - !tokensReserved || - !tokenAmountWei || - !nativeTokenSurplus + redemptionRate === undefined || + totalSupply === undefined || + tokensReserved === undefined || + tokenAmountWei === undefined || + nativeTokenSurplus === undefined ) { return } - return getTokenRedemptionQuoteEth(tokenAmountWei, { - redemptionRate: Number(redemptionRate), - totalSupply, - tokensReserved, - overflowWei: nativeTokenSurplus, - }) + try { + return getTokenRedemptionQuoteEth(tokenAmountWei, { + redemptionRate: Number(redemptionRate), + totalSupply, + tokensReserved, + overflowWei: nativeTokenSurplus, + }) + } catch (e) { + // Division by zero can cause a RangeError + if (e instanceof RangeError) { + return + } else { + throw e + } + } } diff --git a/src/packages/v4/hooks/useHasNftRewards.ts b/src/packages/v4/hooks/useHasNftRewards.ts new file mode 100644 index 0000000000..7e26319d7f --- /dev/null +++ b/src/packages/v4/hooks/useHasNftRewards.ts @@ -0,0 +1,11 @@ +import { useJBRulesetContext } from "juice-sdk-react" +import { zeroAddress } from "viem" + +export function useHasNftRewards() { + const { rulesetMetadata: { data: rulesetMetadata }} = + useJBRulesetContext() + return ( + rulesetMetadata?.dataHook && + rulesetMetadata.dataHook !== zeroAddress + ) +} diff --git a/src/packages/v4/hooks/useLaunchProjectTx.ts b/src/packages/v4/hooks/useLaunchProjectTx.ts index a337c808aa..ae49aa1ba6 100644 --- a/src/packages/v4/hooks/useLaunchProjectTx.ts +++ b/src/packages/v4/hooks/useLaunchProjectTx.ts @@ -1,3 +1,10 @@ +import { useCallback, useContext } from 'react' +import { Address, WaitForTransactionReceiptReturnType } from 'viem' +import { + LaunchV2V3ProjectArgs, + transformV2V3CreateArgsToV4, +} from '../utils/launchProjectTransformers' + import { waitForTransactionReceipt } from '@wagmi/core' import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' import { DEFAULT_MEMO } from 'constants/transactionDefaults' @@ -6,16 +13,9 @@ import { useWallet } from 'hooks/Wallet' import { NATIVE_TOKEN } from 'juice-sdk-core' import { useWriteJbControllerLaunchProjectFor } from 'juice-sdk-react' import { LaunchV2V3ProjectData } from 'packages/v2v3/hooks/transactor/useLaunchProjectTx' -import { useCallback, useContext } from 'react' -import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/editingV2Project' -import { Address, WaitForTransactionReceiptReturnType } from 'viem' -import { sepolia } from 'viem/chains' -import { - LaunchV2V3ProjectArgs, - transformV2V3CreateArgsToV4, -} from '../utils/launchProject' +import { DEFAULT_MUST_START_AT_OR_AFTER } from 'redux/slices/shared/v2ProjectDefaultState' +import { useChainId } from 'wagmi' import { wagmiConfig } from '../wagmiConfig' -import { useCurrentRouteChainId } from './useCurrentRouteChainId' const CREATE_EVENT_IDX = 2 const PROJECT_ID_TOPIC_IDX = 1 @@ -31,7 +31,7 @@ export interface LaunchTxOpts { * Return the project ID created from a `launchProjectFor` transaction. * @param txReceipt receipt of `launchProjectFor` transaction */ -const getProjectIdFromLaunchReceipt = ( +export const getProjectIdFromLaunchReceipt = ( txReceipt: WaitForTransactionReceiptReturnType, ): number => { const projectIdHex: string | undefined = @@ -46,14 +46,14 @@ const getProjectIdFromLaunchReceipt = ( * The contract addresses to use for deployment * @todo not ideal to hardcode these addresses */ -const SUPPORTED_JB_MULTITERMINAL_ADDRESS = { +export const SUPPORTED_JB_MULTITERMINAL_ADDRESS = { '84532': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, '421614': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, '11155111': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, '11155420': '0x4DeF0AA5B9CA095d11705284221b2878731ab4EF' as Address, } -const SUPPORTED_JB_CONTROLLER_ADDRESS = { +export const SUPPORTED_JB_CONTROLLER_ADDRESS = { '84532': '0x219A5cE6d1c512D5b050ad2E3d380b8746BE0Cb8' as Address, '421614': '0x219A5cE6d1c512D5b050ad2E3d380b8746BE0Cb8' as Address, '11155111': '0x219A5cE6d1c512D5b050ad2E3d380b8746BE0Cb8' as Address, @@ -68,13 +68,15 @@ export function useLaunchProjectTx() { const { writeContractAsync: writeLaunchProject } = useWriteJbControllerLaunchProjectFor() - const chainId = useCurrentRouteChainId() ?? sepolia.id // default to sepolia + const chainId = useChainId() + const chainIdStr = + chainId?.toString() as keyof typeof SUPPORTED_JB_MULTITERMINAL_ADDRESS const terminalAddress = chainId - ? SUPPORTED_JB_MULTITERMINAL_ADDRESS[chainId] + ? SUPPORTED_JB_MULTITERMINAL_ADDRESS[chainIdStr] : undefined const controllerAddress = chainId - ? SUPPORTED_JB_CONTROLLER_ADDRESS[chainId] + ? SUPPORTED_JB_CONTROLLER_ADDRESS[chainIdStr] : undefined const { addTransaction } = useContext(TxHistoryContext) @@ -134,7 +136,6 @@ export function useLaunchProjectTx() { // functionName: 'launchProjectFor', // args, // }) - const hash = await writeLaunchProject({ chainId, address: controllerAddress, diff --git a/src/packages/v4/hooks/useNftCartItem.ts b/src/packages/v4/hooks/useNftCartItem.ts new file mode 100644 index 0000000000..6f9b23766f --- /dev/null +++ b/src/packages/v4/hooks/useNftCartItem.ts @@ -0,0 +1,53 @@ +import { useProjectDispatch } from 'packages/v2v3/components/V2V3Project/ProjectDashboard/redux/hooks' +import React from 'react' +import { projectCartActions } from '../components/ProjectDashboard/redux/projectCartSlice' +import { ProjectCartNftReward } from '../components/ProjectDashboard/ReduxProjectCartProvider' +import { useV4NftRewards } from '../contexts/V4NftRewards/V4NftRewardsProvider' +import { V4_CURRENCY_ETH } from '../utils/currency' + +export const useNftCartItem = ({ id, quantity }: ProjectCartNftReward) => { + const dispatch = useProjectDispatch() + const { nftRewards } = useV4NftRewards() + const rewardTiers = React.useMemo( + () => nftRewards.rewardTiers ?? [], + [nftRewards.rewardTiers], + ) + + const rewardTier = React.useMemo( + () => rewardTiers.find(tier => tier.id === id), + [rewardTiers, id], + ) + + const price = React.useMemo( + () => ({ + amount: (rewardTier?.contributionFloor ?? 0) * quantity, + currency: V4_CURRENCY_ETH, + }), + [quantity, rewardTier?.contributionFloor], + ) + + const removeNft = React.useCallback( + () => dispatch(projectCartActions.removeNftReward({ id })), + [dispatch, id], + ) + + const increaseQuantity = React.useCallback( + () => dispatch(projectCartActions.increaseNftRewardQuantity({ id })), + [dispatch, id], + ) + + const decreaseQuantity = React.useCallback( + () => dispatch(projectCartActions.decreaseNftRewardQuantity({ id })), + [dispatch, id], + ) + + return { + name: rewardTier?.name, + fileUrl: rewardTier?.fileUrl, + quantity, + price, + removeNft, + increaseQuantity, + decreaseQuantity, + } +} diff --git a/src/packages/v4/hooks/useNftRewardsEnabledForPay.ts b/src/packages/v4/hooks/useNftRewardsEnabledForPay.ts new file mode 100644 index 0000000000..5a18cbfa54 --- /dev/null +++ b/src/packages/v4/hooks/useNftRewardsEnabledForPay.ts @@ -0,0 +1,25 @@ +import { JBRulesetContext, useJBRulesetContext } from 'juice-sdk-react' +import React from 'react' +import { zeroAddress } from 'viem' +import { useV4NftRewards } from '../contexts/V4NftRewards/V4NftRewardsProvider' + +type RulesetMetadata = JBRulesetContext['rulesetMetadata']['data'] + +export function useNftRewardsEnabledForPay() { + const jbRuleset = useJBRulesetContext() + const { nftRewards } = useV4NftRewards() + + const hasNftRewards = React.useMemo( + () => nftRewards.rewardTiers?.length !== 0, + [nftRewards.rewardTiers], + ) + + return hasNftRewards && hasDataSourceForPay(jbRuleset.rulesetMetadata.data) +} + +const hasDataSourceForPay = (rulesetMetadata: RulesetMetadata) => { + return ( + rulesetMetadata?.dataHook !== zeroAddress && + !!rulesetMetadata?.useDataHookForPay + ) +} diff --git a/src/packages/v4/models/fundAccessLimits.ts b/src/packages/v4/models/fundAccessLimits.ts new file mode 100644 index 0000000000..d5e1f0b919 --- /dev/null +++ b/src/packages/v4/models/fundAccessLimits.ts @@ -0,0 +1,12 @@ +export type FundAccessLimitGroup = { + terminal: `0x${string}`; + token: `0x${string}`; + payoutLimits: { + amount: bigint; + currency: number; + }[]; + surplusAllowances: { + amount: bigint; + currency: number; + }[]; +} diff --git a/src/packages/v4/models/nfts.ts b/src/packages/v4/models/nfts.ts new file mode 100644 index 0000000000..df7026a90f --- /dev/null +++ b/src/packages/v4/models/nfts.ts @@ -0,0 +1,99 @@ +import { JBRulesetData, JBRulesetMetadata } from 'juice-sdk-core' +import { Address, ContractFunctionReturnType } from 'viem' + +import { jb721TiersHookStoreAbi } from 'juice-sdk-react' +import { LaunchV2V3ProjectData } from 'packages/v2v3/hooks/transactor/useLaunchProjectTx' +import { LaunchV4ProjectGroupedSplit } from '../utils/launchProjectTransformers' +import { FundAccessLimitGroup } from './fundAccessLimits' +import { LaunchProjectJBTerminal } from './terminals' +import { V4CurrencyOption } from './v4CurrencyOption' + +/** + * @see https://github.com/Bananapus/nana-721-hook/blob/main/src/structs/JB721TierConfig.sol + */ +export type JB721TierConfig = Omit< + ContractFunctionReturnType< + typeof jb721TiersHookStoreAbi, + 'view', + 'tiersOf' + >[0], + 'id' | 'votingUnits' +> & { + useReserveBeneficiaryAsDefault: boolean + useVotingUnits: boolean + votingUnits: number +} + +type JB721InitTiersConfig = { + tiers: JB721TierConfig[] + currency: number + decimals: number + prices: Address // JBPrices address +} + +export type JB721TiersHookFlags = { + noNewTiersWithReserves: boolean + noNewTiersWithVotes: boolean + noNewTiersWithOwnerMinting: boolean + preventOverspending: boolean +} + +/** + * string name; + string symbol; + string baseUri; + IJB721TokenUriResolver tokenUriResolver; + string contractUri; + JB721InitTiersConfig tiersConfig; + address reserveBeneficiary; + JB721TiersHookFlags flags; + */ +export type JBDeploy721TiersHookConfig = { + name: string + symbol: string + baseUri: string + tokenUriResolver: Address //IJB721TokenUriResolver; + contractUri: string + tiersConfig: JB721InitTiersConfig + reserveBeneficiary: Address + flags: JB721TiersHookFlags +} + +export type JBPayDataHookRulesetConfig = JBRulesetData & { + metadata: JBPayDataHookRulesetMetadata + memo?: string + fundAccessLimitGroups: FundAccessLimitGroup[] + mustStartAtOrAfter?: string // epoch seconds. anything less than "now" will start immediately. + terminals: string[] + duration: bigint + weight: bigint + decayPercent: bigint + approvalHook: Address + splitGroups: LaunchV4ProjectGroupedSplit[] +} + +interface DeployTiered721DelegateData { + collectionUri: string + collectionName: string + collectionSymbol: string + currency: V4CurrencyOption + tiers: JB721TierConfig[] + flags: JB721TiersHookFlags +} + +export interface LaunchProjectWithNftsTxArgs { + tiered721DelegateData: DeployTiered721DelegateData + projectData: LaunchV2V3ProjectData +} + +export type JB721DelegateLaunchProjectData = { + rulesetConfigurations: JBPayDataHookRulesetConfig[] + terminalConfigurations: LaunchProjectJBTerminal[] + projectMetadataUri: string + memo?: string +} + +export type JBPayDataHookRulesetMetadata = Omit< + JBRulesetMetadata, + 'useDataSourceForPay' | 'dataSource' +> diff --git a/src/packages/v4/models/splits.ts b/src/packages/v4/models/splits.ts new file mode 100644 index 0000000000..7e5fb0e075 --- /dev/null +++ b/src/packages/v4/models/splits.ts @@ -0,0 +1,6 @@ +import { JBSplit } from "juice-sdk-core" + +export interface GroupedSplits { + groupId: G + splits: JBSplit[] +} diff --git a/src/packages/v4/models/terminals.ts b/src/packages/v4/models/terminals.ts new file mode 100644 index 0000000000..c5f474928f --- /dev/null +++ b/src/packages/v4/models/terminals.ts @@ -0,0 +1,10 @@ +import { Address } from 'viem'; + +export type LaunchProjectJBTerminal = { + terminal: Address; + accountingContextsToAccept: { + token: `0x${string}`; + decimals: 18; + currency: number; + }[]; +} diff --git a/src/packages/v4/models/v4CurrencyOption.ts b/src/packages/v4/models/v4CurrencyOption.ts index 3f8b85a472..caf7053b1e 100644 --- a/src/packages/v4/models/v4CurrencyOption.ts +++ b/src/packages/v4/models/v4CurrencyOption.ts @@ -1,4 +1,4 @@ -// same as v2v3 for now (@todo: make V4 specific) -export type V4CurrencyETH = 1 -export type V4CurrencyUSD = 2 +// TODO: This is for backward compatibility - correct token codes are listed as comments +export type V4CurrencyETH = 1 // TODO: 61166 +export type V4CurrencyUSD = 2 // TODO: 1 export type V4CurrencyOption = V4CurrencyETH | V4CurrencyUSD diff --git a/src/packages/v4/utils/currency.ts b/src/packages/v4/utils/currency.ts index e7bad5d225..cf5d920f5d 100644 --- a/src/packages/v4/utils/currency.ts +++ b/src/packages/v4/utils/currency.ts @@ -1,16 +1,23 @@ -import { CURRENCY_METADATA, CurrencyMetadata, CurrencyName } from "constants/currency" -import { V4CurrencyETH, V4CurrencyOption, V4CurrencyUSD } from "../models/v4CurrencyOption" +import { + CURRENCY_METADATA, + CurrencyMetadata, + CurrencyName, +} from 'constants/currency' +import { + V4CurrencyETH, + V4CurrencyOption, + V4CurrencyUSD, +} from '../models/v4CurrencyOption' -export const V4_CURRENCY_ETH: V4CurrencyETH = 1 -export const V4_CURRENCY_USD: V4CurrencyUSD = 2 +// TODO: This is for backward compatibility - correct token codes are listed as comments +export const V4_CURRENCY_ETH: V4CurrencyETH = 1 // TODO: 61166 +export const V4_CURRENCY_USD: V4CurrencyUSD = 2 // TODO: 1 -export const V4_CURRENCY_METADATA: Record< - V4CurrencyOption, - CurrencyMetadata -> = { - [V4_CURRENCY_ETH]: CURRENCY_METADATA.ETH, - [V4_CURRENCY_USD]: CURRENCY_METADATA.USD, -} +export const V4_CURRENCY_METADATA: Record = + { + [V4_CURRENCY_ETH]: CURRENCY_METADATA.ETH, + [V4_CURRENCY_USD]: CURRENCY_METADATA.USD, + } export const V4CurrencyName = ( currency?: V4CurrencyOption, diff --git a/src/packages/v4/utils/editRuleset.ts b/src/packages/v4/utils/editRuleset.ts index ca46980f54..5ab3d38fd2 100644 --- a/src/packages/v4/utils/editRuleset.ts +++ b/src/packages/v4/utils/editRuleset.ts @@ -1,9 +1,10 @@ -import { NATIVE_TOKEN } from "juice-sdk-core"; -import round from "lodash/round"; -import { issuanceRateFrom } from "packages/v2v3/utils/math"; -import { parseWad } from "utils/format/formatNumber"; -import { otherUnitToSeconds } from "utils/format/formatTime"; -import { EditCycleFormFields } from "../views/V4ProjectSettings/EditCyclePage/EditCycleFormFields"; +import { NATIVE_TOKEN } from 'juice-sdk-core' +import round from 'lodash/round' +import { issuanceRateFrom } from 'packages/v2v3/utils/math' +import { parseWad } from 'utils/format/formatNumber' +import { otherUnitToSeconds } from 'utils/format/formatTime' +import { EditCycleFormFields } from '../views/V4ProjectSettings/EditCyclePage/EditCycleFormFields' +import { BASE_CURRENCY_ETH } from './shared/currency' export function transformEditCycleFormFieldsToTxArgs({ formValues, @@ -11,21 +12,21 @@ export function transformEditCycleFormFieldsToTxArgs({ tokenAddress, projectId, }: { - formValues: EditCycleFormFields; - primaryNativeTerminal: `0x${string}`; - tokenAddress: `0x${string}`; - projectId: bigint; + formValues: EditCycleFormFields + primaryNativeTerminal: `0x${string}` + tokenAddress: `0x${string}` + projectId: bigint }) { - const now = round(new Date().getTime() / 1000); - const mustStartAtOrAfter = now; + const now = round(new Date().getTime() / 1000) + const mustStartAtOrAfter = now const duration = otherUnitToSeconds({ duration: formValues.duration, unit: formValues.durationUnit.value, }) - const weight = BigInt(issuanceRateFrom(formValues.issuanceRate.toString())); - const decayPercent = round(formValues.decayPercent * 10000000); - const approvalHook = formValues.approvalHook; + const weight = BigInt(issuanceRateFrom(formValues.issuanceRate.toString())) + const decayPercent = round(formValues.decayPercent * 10000000) + const approvalHook = formValues.approvalHook const rulesetConfigurations = [ { @@ -38,7 +39,7 @@ export function transformEditCycleFormFieldsToTxArgs({ metadata: { reservedPercent: formValues.reservedPercent * 100, redemptionRate: formValues.redemptionRate * 100, - baseCurrency: 1, // Assuming base currency is a constant value, typically USD + baseCurrency: BASE_CURRENCY_ETH, pausePay: formValues.pausePay, pauseRedeem: false, // Defaulting this value since it's not in formValues pauseCreditTransfers: !formValues.tokenTransfers, @@ -54,15 +55,15 @@ export function transformEditCycleFormFieldsToTxArgs({ useTotalSurplusForRedemptions: false, // Defaulting to false as it's not in formValues useDataHookForPay: false, // Defaulting to false as it's not in formValues useDataHookForRedeem: false, // Defaulting to false as it's not in formValues - dataHook: "0x0000000000000000000000000000000000000000" as `0x${string}`, // Defaulting to a null address + dataHook: '0x0000000000000000000000000000000000000000' as `0x${string}`, // Defaulting to a null address metadata: 0, // Assuming no additional metadata is provided - allowCrosschainSuckerExtension: false + allowCrosschainSuckerExtension: false, }, splitGroups: [ { groupId: BigInt(NATIVE_TOKEN), - splits: formValues.payoutSplits.map((split) => ({ + splits: formValues.payoutSplits.map(split => ({ preferAddToBalance: Boolean(split.preferAddToBalance), percent: Number(split.percent.value), projectId: BigInt(split.projectId), @@ -73,7 +74,7 @@ export function transformEditCycleFormFieldsToTxArgs({ }, { groupId: BigInt(1), - splits: formValues.reservedTokensSplits.map((split) => ({ + splits: formValues.reservedTokensSplits.map(split => ({ preferAddToBalance: Boolean(split.preferAddToBalance), percent: Number(split.percent.value), projectId: BigInt(split.projectId), @@ -103,11 +104,7 @@ export function transformEditCycleFormFieldsToTxArgs({ }, ], }, - ]; + ] - return [ - projectId, - rulesetConfigurations, - formValues.memo ?? "", - ] as const; + return [projectId, rulesetConfigurations, formValues.memo ?? ''] as const } diff --git a/src/packages/v4/utils/launchProject.ts b/src/packages/v4/utils/launchProject.ts deleted file mode 100644 index 21292b1834..0000000000 --- a/src/packages/v4/utils/launchProject.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { NATIVE_TOKEN, NATIVE_TOKEN_DECIMALS, SplitGroup } from 'juice-sdk-core' -import round from 'lodash/round' -import { V2FundingCycleMetadata } from 'packages/v2/models/fundingCycle' -import { - V2V3FundAccessConstraint, - V2V3FundingCycleData, -} from 'packages/v2v3/models/fundingCycle' -import { GroupedSplits } from 'packages/v2v3/models/splits' -import { V3FundingCycleMetadata } from 'packages/v3/models/fundingCycle' -import { Address } from 'viem' - -export type LaunchV2V3ProjectArgs = [ - string, // _owner - [string, number], // _projectMetadata [projectMetadataCID, JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN] - V2V3FundingCycleData, // _data - V2FundingCycleMetadata | V3FundingCycleMetadata, // _metadata - string, // _mustStartAtOrAfter - GroupedSplits[], // _groupedSplits - V2V3FundAccessConstraint[], // _fundAccessConstraints - string[], // _terminals - string, // _memo -] - -export function transformV2V3CreateArgsToV4({ - v2v3Args, - primaryNativeTerminal, - currencyTokenAddress, -}: { - v2v3Args: LaunchV2V3ProjectArgs - primaryNativeTerminal: Address - currencyTokenAddress: Address -}) { - const [ - _owner, - _projectMetadata, - _data, - _metadata, - _mustStartAtOrAfter, - _groupedSplits, - _fundAccessConstraints, - _terminals, - _memo, - ] = v2v3Args - - const mustStartAtOrAfterNum = parseInt(_mustStartAtOrAfter) - const now = round(new Date().getTime() / 1000) - - const ruleset = { - mustStartAtOrAfter: mustStartAtOrAfterNum > now ? mustStartAtOrAfterNum : now, - duration: _data.duration.toNumber(), - weight: _data.weight.toBigInt(), - decayPercent: _data.discountRate.toNumber(), - - approvalHook: _data.ballot as Address, - - metadata: { - reservedPercent: _metadata.reservedRate.toNumber(), - redemptionRate: _metadata.redemptionRate.toNumber(), - baseCurrency: 1, // Not present in v2v3, passing 1 by default - pausePay: _metadata.pausePay, - pauseRedeem: _metadata.pauseRedeem, - pauseCreditTransfers: Boolean(_metadata.global.pauseTransfers), - allowOwnerMinting: _metadata.allowMinting, - allowSetCustomToken: false, // Assuming false by default - allowTerminalMigration: _metadata.allowTerminalMigration, - allowSetTerminals: _metadata.global.allowSetTerminals, - allowSetController: _metadata.global.allowSetController, - allowAddAccountingContext: false, // Not present in v2v3, passing false by default - allowAddPriceFeed: false, // Not present in v2v3, passing false by default - ownerMustSendPayouts: false, // Not present in v2v3, passing false by default - holdFees: _metadata.holdFees, - useTotalSurplusForRedemptions: _metadata.useTotalOverflowForRedemptions, - useDataHookForPay: _metadata.useDataSourceForPay, - useDataHookForRedeem: _metadata.useDataSourceForRedeem, - dataHook: _metadata.dataSource as Address, - metadata: 0, - allowCrosschainSuckerExtension: false, - }, - - splitGroups: _groupedSplits.map(group => ({ - groupId: - group.group === SplitGroup.ETHPayout - ? BigInt(NATIVE_TOKEN) - : 1n, // TODO dont hardcode reserved token group as 1n - splits: group.splits.map(split => ({ - preferAddToBalance: Boolean(split.preferClaimed), - percent: split.percent, - projectId: BigInt(parseInt(split.projectId ?? '0x00', 16)), - beneficiary: split.beneficiary as Address, - lockedUntil: split.lockedUntil ?? 0, - hook: split.allocator as Address, - })), - })), - - fundAccessLimitGroups: _fundAccessConstraints.map(constraint => ({ - terminal: primaryNativeTerminal, - token: currencyTokenAddress, - payoutLimits: [ - { - amount: constraint.distributionLimit.toBigInt(), - currency: Number(BigInt(NATIVE_TOKEN)), // TODO support USD somehow - }, - ], - surplusAllowances: [ - { - amount: constraint.overflowAllowance.toBigInt(), - currency: Number(BigInt(NATIVE_TOKEN)), - }, - ], - })), - } - - const rulesetConfigurations = [ruleset] - - const terminalConfigurations = _terminals.map(terminal => ({ - terminal: terminal as Address, - accountingContextsToAccept: [ - { - token: currencyTokenAddress, - decimals: NATIVE_TOKEN_DECIMALS, - currency: Number(BigInt(currencyTokenAddress)), - }, - ], - })) - - return [ - _owner as Address, - _projectMetadata[0], - rulesetConfigurations, - terminalConfigurations, - _memo, - ] as const -} diff --git a/src/packages/v4/utils/launchProjectTransformers.ts b/src/packages/v4/utils/launchProjectTransformers.ts new file mode 100644 index 0000000000..3627112d2d --- /dev/null +++ b/src/packages/v4/utils/launchProjectTransformers.ts @@ -0,0 +1,196 @@ +import { + JBSplit, + NATIVE_TOKEN, + NATIVE_TOKEN_DECIMALS, + SplitGroup, +} from 'juice-sdk-core' +import { + V2V3FundAccessConstraint, + V2V3FundingCycleData, +} from 'packages/v2v3/models/fundingCycle' + +import round from 'lodash/round' +import { V2FundingCycleMetadata } from 'packages/v2/models/fundingCycle' +import { GroupedSplits as V2V3GroupedSplits } from 'packages/v2v3/models/splits' +import { V3FundingCycleMetadata } from 'packages/v3/models/fundingCycle' +import { Address } from 'viem' +import { FundAccessLimitGroup } from '../models/fundAccessLimits' +import { GroupedSplits as V4GroupedSplits } from '../models/splits' +import { LaunchProjectJBTerminal } from '../models/terminals' +import { BASE_CURRENCY_ETH } from './shared/currency' + +export type LaunchV2V3ProjectArgs = [ + string, // _owner + [string, number], // _projectMetadata [projectMetadataCID, JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN] + V2V3FundingCycleData, // _fundingCycleData + V2FundingCycleMetadata | V3FundingCycleMetadata, // _fundingCycleMetadata + string, // _mustStartAtOrAfter + V2V3GroupedSplits[], // _groupedSplits + V2V3FundAccessConstraint[], // _fundAccessConstraints + string[], // _terminals + string, // _memo +] + +export function transformV2V3CreateArgsToV4({ + v2v3Args, + primaryNativeTerminal, + currencyTokenAddress, +}: { + v2v3Args: LaunchV2V3ProjectArgs + primaryNativeTerminal: Address + currencyTokenAddress: Address +}) { + const [ + _owner, + _projectMetadata, + _fundingCycleData, + _fundingCycleMetadata, + _mustStartAtOrAfter, + _groupedSplits, + _fundAccessConstraints, + _terminals, + _memo, + ] = v2v3Args + + const mustStartAtOrAfterNum = parseInt(_mustStartAtOrAfter) + const now = round(new Date().getTime() / 1000) + + const ruleset = { + mustStartAtOrAfter: + mustStartAtOrAfterNum > now ? mustStartAtOrAfterNum : now, + duration: _fundingCycleData.duration.toNumber(), + weight: _fundingCycleData.weight.toBigInt(), + decayPercent: _fundingCycleData.discountRate.toNumber(), + + approvalHook: _fundingCycleData.ballot as Address, + + metadata: transformFCMetadataToRulesetMetadata({ + fundingCycleMetadata: _fundingCycleMetadata, + }), + + splitGroups: transformV2V3SplitsToV4({ v2v3Splits: _groupedSplits }), + + fundAccessLimitGroups: transformV2V3FundAccessConstraintsToV4({ + v2V3FundAccessConstraints: _fundAccessConstraints, + primaryNativeTerminal, + currencyTokenAddress, + }), + } + + const rulesetConfigurations = [ruleset] + + const terminalConfigurations = generateV4LaunchTerminalConfigurationsArg({ + terminals: _terminals, + currencyTokenAddress, + }) + + return [ + _owner as Address, + _projectMetadata[0], + rulesetConfigurations, + terminalConfigurations, + _memo, + ] as const +} + +export function transformFCMetadataToRulesetMetadata({ + fundingCycleMetadata, +}: { + fundingCycleMetadata: V2FundingCycleMetadata | V3FundingCycleMetadata +}) { + return { + reservedPercent: fundingCycleMetadata.reservedRate.toNumber(), + redemptionRate: fundingCycleMetadata.redemptionRate.toNumber(), + baseCurrency: BASE_CURRENCY_ETH, + pausePay: fundingCycleMetadata.pausePay, + pauseRedeem: fundingCycleMetadata.pauseRedeem, + pauseCreditTransfers: Boolean(fundingCycleMetadata.global.pauseTransfers), + allowOwnerMinting: fundingCycleMetadata.allowMinting, + allowSetCustomToken: false, // Assuming false by default + allowTerminalMigration: fundingCycleMetadata.allowTerminalMigration, + allowSetTerminals: fundingCycleMetadata.global.allowSetTerminals, + allowSetController: fundingCycleMetadata.global.allowSetController, + allowAddAccountingContext: false, // Not present in v2v3, passing false by default + allowAddPriceFeed: false, // Not present in v2v3, passing false by default + ownerMustSendPayouts: false, // Not present in v2v3, passing false by default + holdFees: fundingCycleMetadata.holdFees, + useTotalSurplusForRedemptions: + fundingCycleMetadata.useTotalOverflowForRedemptions, + useDataHookForPay: fundingCycleMetadata.useDataSourceForPay, + useDataHookForRedeem: fundingCycleMetadata.useDataSourceForRedeem, + dataHook: fundingCycleMetadata.dataSource as Address, + metadata: 0, + allowCrosschainSuckerExtension: false, + } +} + +type LaunchProjectJBSplit = Omit & { percent: number } + +export type LaunchV4ProjectGroupedSplit = Omit< + V4GroupedSplits, + 'splits' | 'groupId' +> & { splits: LaunchProjectJBSplit[]; groupId: bigint } + +export function transformV2V3SplitsToV4({ + v2v3Splits, +}: { + v2v3Splits: V2V3GroupedSplits[] +}): LaunchV4ProjectGroupedSplit[] { + return v2v3Splits.map(group => ({ + groupId: group.group === SplitGroup.ETHPayout ? BigInt(NATIVE_TOKEN) : 1n, // TODO dont hardcode reserved token group as 1n + splits: group.splits.map(split => ({ + preferAddToBalance: Boolean(split.preferClaimed), + percent: split.percent, + projectId: BigInt(parseInt(split.projectId ?? '0x00', 16)), + beneficiary: split.beneficiary as Address, + lockedUntil: split.lockedUntil ?? 0, + hook: split.allocator as Address, + })), + })) +} + +export function transformV2V3FundAccessConstraintsToV4({ + v2V3FundAccessConstraints, + primaryNativeTerminal, + currencyTokenAddress, +}: { + v2V3FundAccessConstraints: V2V3FundAccessConstraint[] + primaryNativeTerminal: Address + currencyTokenAddress: Address +}): FundAccessLimitGroup[] { + return v2V3FundAccessConstraints.map(constraint => ({ + terminal: primaryNativeTerminal, + token: currencyTokenAddress, + payoutLimits: [ + { + amount: constraint.distributionLimit.toBigInt(), + currency: Number(BigInt(NATIVE_TOKEN)), // TODO support USD somehow + }, + ], + surplusAllowances: [ + { + amount: constraint.overflowAllowance.toBigInt(), + currency: Number(BigInt(NATIVE_TOKEN)), + }, + ], + })) +} + +function generateV4LaunchTerminalConfigurationsArg({ + terminals, + currencyTokenAddress, +}: { + terminals: string[] + currencyTokenAddress: Address +}): LaunchProjectJBTerminal[] { + return terminals.map(terminal => ({ + terminal: terminal as Address, + accountingContextsToAccept: [ + { + token: currencyTokenAddress, + decimals: NATIVE_TOKEN_DECIMALS, + currency: Number(BigInt(currencyTokenAddress)), + }, + ], + })) +} diff --git a/src/packages/v4/utils/math.ts b/src/packages/v4/utils/math.ts index a5d55b13ce..422f772fa4 100644 --- a/src/packages/v4/utils/math.ts +++ b/src/packages/v4/utils/math.ts @@ -1,6 +1,8 @@ import { feeForAmount } from 'utils/math' -export const MAX_PAYOUT_LIMIT = BigInt('26959946667150639794667015087019630673637144422540572481103610249215') // uint 224, probably a better way lol +export const MAX_PAYOUT_LIMIT = BigInt( + '26959946667150639794667015087019630673637144422540572481103610249215', +) // uint 224, probably a better way lol export const amountSubFee = ( amountWad: bigint | undefined, diff --git a/src/packages/v4/utils/shared/currency.ts b/src/packages/v4/utils/shared/currency.ts new file mode 100644 index 0000000000..5c84cc8dee --- /dev/null +++ b/src/packages/v4/utils/shared/currency.ts @@ -0,0 +1 @@ +export const BASE_CURRENCY_ETH = 61166 diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectDashboard.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectDashboard.tsx index 52880d268e..3bdfa54f86 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectDashboard.tsx +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectDashboard.tsx @@ -11,7 +11,7 @@ import { useProjectPageQueries } from './hooks/useProjectPageQueries' import { V4ProjectHeader } from './V4ProjectHeader' import { V4ProjectTabs } from './V4ProjectTabs/V4ProjectTabs' -export function V4ProjectDashboard() { +export default function V4ProjectDashboard() { const { projectPayReceipt } = useProjectPageQueries() if (projectPayReceipt !== undefined) { diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectProviders.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectProviders.tsx new file mode 100644 index 0000000000..bd305f0437 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectProviders.tsx @@ -0,0 +1,49 @@ +import { AppWrapper } from 'components/common/CoreAppWrapper/CoreAppWrapper' +import { OPEN_IPFS_GATEWAY_HOSTNAME } from 'constants/ipfs' +import { JBChainId, JBProjectProvider } from 'juice-sdk-react' +import { ReduxProjectCartProvider } from 'packages/v4/components/ProjectDashboard/ReduxProjectCartProvider' +import store from 'packages/v4/components/ProjectDashboard/redux/store' +import { V4NftRewardsProvider } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import V4ProjectMetadataProvider from 'packages/v4/contexts/V4ProjectMetadataProvider' +import { V4UserNftCreditsProvider } from 'packages/v4/contexts/V4UserNftCreditsProvider' +import { V4UserTotalTokensBalanceProvider } from 'packages/v4/contexts/V4UserTotalTokensBalanceProvider' +import { chainNameMap } from 'packages/v4/utils/networks' +import { wagmiConfig } from 'packages/v4/wagmiConfig' +import React, { PropsWithChildren } from 'react' +import { Provider } from 'react-redux' +import { WagmiProvider } from 'wagmi' + +const V4ProjectProviders: React.FC< + PropsWithChildren & { chainName: string; projectId: bigint } +> = ({ chainName, projectId, children }) => { + const chainId = chainNameMap[chainName] as JBChainId + + return ( + + + + + + + + + + {children} + + + + + + + + + + ) +} +export default V4ProjectProviders diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/V4ActivityList.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/V4ActivityList.tsx index 27db6ece2d..a6f83fd979 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/V4ActivityList.tsx +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/V4ActivityList.tsx @@ -1,38 +1,38 @@ import { t } from '@lingui/macro' import Loading from 'components/Loading' -import { - NativeTokenValue, - useJBContractContext, - useJBTokenContext, -} from 'juice-sdk-react' +import RichNote from 'components/RichNote/RichNote' +import { NativeTokenValue, useJBContractContext } from 'juice-sdk-react' import { OrderDirection, PayEvent_OrderBy, PayEventsDocument, } from 'packages/v4/graphql/client/graphql' import { useSubgraphQuery } from 'packages/v4/graphql/useSubgraphQuery' +import React from 'react' import { ActivityEvent } from './activityEventElems/ActivityElement' import { ActivityOptions } from './ActivityOptions' import { PayEvent } from './models/ActivityEvents' import { transformPayEventsRes } from './utils/transformEventsData' export function V4ActivityList() { - const { token } = useJBTokenContext() const { projectId } = useJBContractContext() // TODO: pageSize (pagination) const { data: payEventsData, isLoading } = useSubgraphQuery({ - document: PayEventsDocument, + document: PayEventsDocument, variables: { orderBy: PayEvent_OrderBy.timestamp, orderDirection: OrderDirection.desc, where: { projectId: Number(projectId), }, - } + }, }) - const payEvents = transformPayEventsRes(payEventsData) ?? [] + const payEvents = React.useMemo( + () => transformPayEventsRes(payEventsData) ?? [], + [payEventsData], + ) return (
@@ -62,15 +62,10 @@ export function V4ActivityList() { header={t`Paid`} subject={ - - - } - extra={ - - bought {event.beneficiaryTokenCount?.format(6)}{' '} - {token.data?.symbol ?? 'tokens'} + } + extra={} />
) diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/models/ActivityEvents.ts b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/models/ActivityEvents.ts index f960855f98..3e3c623afb 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/models/ActivityEvents.ts +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/models/ActivityEvents.ts @@ -7,6 +7,7 @@ export type PayEvent = { amountUSD: Ether | undefined beneficiary: Address beneficiaryTokenCount?: JBProjectToken + note: string timestamp: number txHash: string } diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/utils/transformEventsData.ts b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/utils/transformEventsData.ts index 243a00239d..4083ca7de4 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/utils/transformEventsData.ts +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ActivityPanel/utils/transformEventsData.ts @@ -9,11 +9,14 @@ export function transformPayEventsRes( return { id: event.id, amount: new Ether(BigInt(event.amount)), - amountUSD: event.amountUSD ? new Ether(BigInt(event.amountUSD)) : undefined, + amountUSD: event.amountUSD + ? new Ether(BigInt(event.amountUSD)) + : undefined, beneficiary: event.beneficiary, beneficiaryTokenCount: new JBProjectToken( BigInt(event.beneficiaryTokenCount), ), + note: event.note, timestamp: event.timestamp, txHash: event.txHash, } diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/AddNftButton.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/AddNftButton.tsx new file mode 100644 index 0000000000..8bac6cf1af --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/AddNftButton.tsx @@ -0,0 +1,25 @@ +import { PlusIcon } from '@heroicons/react/24/solid' +import { Trans } from '@lingui/macro' +import { stopPropagation } from 'react-stop-propagation' +import { twMerge } from 'tailwind-merge' + +export const nftHoverButtonClasses = + 'absolute bottom-0 flex h-12 w-full items-center justify-center rounded-b-lg text-base font-medium text-white opacity-0 transition-all duration-200 ease-in-out group-hover:opacity-100' + +// Button that appears when hovering an NFT reward card +export function AddNftButton({ onClick }: { onClick: VoidFunction }) { + return ( +
+ + + Add NFT + +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftDetails.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftDetails.tsx new file mode 100644 index 0000000000..053d5d1fdd --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftDetails.tsx @@ -0,0 +1,67 @@ +import { Skeleton } from 'antd' +import { TruncatedText } from 'components/TruncatedText' +import ETHAmount from 'components/currency/ETHAmount' +import { NftRewardTier } from 'models/nftRewards' +import { twMerge } from 'tailwind-merge' +import { parseWad } from 'utils/format/formatNumber' + +export function NftDetails({ + rewardTier, + loading, + hideAttributes, + remainingSupplyText, +}: { + rewardTier: NftRewardTier | undefined + loading: boolean | undefined + hideAttributes?: boolean + remainingSupplyText: string +}) { + return ( +
+ + + + {!hideAttributes ? ( +
+ {rewardTier?.contributionFloor ? ( + + + + + + ) : null} + + + {remainingSupplyText} + + +
+ ) : null} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftReward.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftReward.tsx new file mode 100644 index 0000000000..e17b50d006 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftReward.tsx @@ -0,0 +1,157 @@ +import { t } from '@lingui/macro' +import { Tooltip } from 'antd' +import { NftPreview } from 'components/NftRewards/NftPreview' +import { NftRewardTier } from 'models/nftRewards' +import { DEFAULT_NFT_MAX_SUPPLY } from 'packages/v2v3/constants/nftRewards' +import { usePayProjectDisabled } from 'packages/v2v3/hooks/usePayProjectDisabled' +import { useProjectSelector } from 'packages/v4/components/ProjectDashboard/redux/hooks' +import { useNftRewardsEnabledForPay } from 'packages/v4/hooks/useNftRewardsEnabledForPay' +import { useMemo, useState } from 'react' +import { twMerge } from 'tailwind-merge' +import { ipfsUriToGatewayUrl } from 'utils/ipfs' +import { AddNftButton } from './AddNftButton' +import { NftDetails } from './NftDetails' +import { NftThumbnail } from './NftThumbnail' +import { PreviewAddRemoveNftButton } from './PreviewAddRemoveNftButton' +import { RemoveNftButton } from './RemoveNftButton' + +type NftRewardProps = { + className?: string + rewardTier?: NftRewardTier + loading?: boolean + onSelect: (quantity?: number) => void + onDeselect: VoidFunction + previewDisabled?: boolean + hideAttributes?: boolean +} + +export function NftReward({ + className, + loading, + rewardTier, + previewDisabled, + onSelect, + onDeselect, + hideAttributes, +}: NftRewardProps) { + const [previewVisible, setPreviewVisible] = useState(false) + const chosenNftRewards = useProjectSelector( + state => state.projectCart.chosenNftRewards, + ) + + const nftsEnabledForPay = useNftRewardsEnabledForPay() + const { + payDisabled, + message, + loading: payDisabledLoading, + } = usePayProjectDisabled() + + const quantitySelected = useMemo( + () => + chosenNftRewards.find(nft => nft.id === rewardTier?.id)?.quantity ?? 0, + [chosenNftRewards, rewardTier?.id], + ) + const isSelected = quantitySelected > 0 + + const fileUrl = useMemo( + () => + rewardTier?.fileUrl ? ipfsUriToGatewayUrl(rewardTier.fileUrl) : undefined, + [rewardTier?.fileUrl], + ) + + const remainingSupply = rewardTier?.remainingSupply + const hasRemainingSupply = remainingSupply && remainingSupply > 0 + const remainingSupplyText = !hasRemainingSupply + ? t`SOLD OUT` + : rewardTier.maxSupply === DEFAULT_NFT_MAX_SUPPLY + ? t`Unlimited` + : t`${rewardTier?.remainingSupply} remaining` + + const disabled = Boolean( + !hasRemainingSupply || !nftsEnabledForPay || payDisabled, + ) + const disabledReason = useMemo(() => { + if (!hasRemainingSupply) return t`Sold out` + if (!nftsEnabledForPay) return t`NFTs are not enabled for pay` + if (payDisabled) return message + }, [nftsEnabledForPay, hasRemainingSupply, payDisabled, message]) + + const openPreview = () => { + setPreviewVisible(true) + } + + return ( + <> + +
+ + + {!disabled && + (isSelected ? ( + onDeselect()} /> + ) : ( + onSelect(1)} /> + ))} +
+
+ + {rewardTier && !previewDisabled && previewVisible ? ( + onSelect(1)} + onDeselect={onDeselect} + isSelected={isSelected} + /> + } + /> + ) : null} + + ) +} + +export const NftRewardSkeleton = () => ( +
+
+
+
+
+
+
+) diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftThumbnail.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftThumbnail.tsx new file mode 100644 index 0000000000..4a26f9d577 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/NftThumbnail.tsx @@ -0,0 +1,32 @@ +import { JuiceVideoThumbnailOrImage } from 'components/JuiceVideo/JuiceVideoThumbnailOrImage' +import { NftRewardTier } from 'models/nftRewards' +import { twMerge } from 'tailwind-merge' + +export function NftThumbnail({ + fileUrl, + isSelected, + rewardTier, +}: { + fileUrl: string | undefined + isSelected: boolean + rewardTier: NftRewardTier | undefined +}) { + return ( +
+ {fileUrl ? ( + + ) : null} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/PreviewAddRemoveNftButton.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/PreviewAddRemoveNftButton.tsx new file mode 100644 index 0000000000..dd3d5a37c9 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/PreviewAddRemoveNftButton.tsx @@ -0,0 +1,58 @@ +import { MinusIcon, PlusIcon } from '@heroicons/react/24/solid' +import { Trans, t } from '@lingui/macro' +import { Button } from 'antd' +import { emitConfirmationDeletionModal } from 'hooks/emitConfirmationDeletionModal' +import { useCallback } from 'react' +import { twMerge } from 'tailwind-merge' + +const iconClasses = 'mr-1 h-6 w-6' +const containerClasses = 'flex items-center justify-center' + +export function PreviewAddRemoveNftButton({ + className, + isSelected, + onSelect, + onDeselect, +}: { + className?: string + isSelected?: boolean + onSelect: VoidFunction + onDeselect: VoidFunction +}) { + const buttonContents = isSelected ? ( +
+ + + Remove NFT + +
+ ) : ( +
+ + + Add NFT + +
+ ) + + const handleDeselect = useCallback(() => { + emitConfirmationDeletionModal({ + onConfirm: onDeselect, + title: t`Remove NFT`, + description: t`Are you sure you want to remove this NFT?`, + }) + }, [onDeselect]) + + return ( + + ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/RemoveNftButton.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/RemoveNftButton.tsx new file mode 100644 index 0000000000..b218c69098 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/NftReward/RemoveNftButton.tsx @@ -0,0 +1,33 @@ +import { TrashIcon } from '@heroicons/react/24/solid' +import { Trans, t } from '@lingui/macro' +import { emitConfirmationDeletionModal } from 'hooks/emitConfirmationDeletionModal' +import { useCallback } from 'react' +import { stopPropagation } from 'react-stop-propagation' +import { twMerge } from 'tailwind-merge' +import { nftHoverButtonClasses } from './AddNftButton' + +// Button that appears when hovering an NFT reward card +export function RemoveNftButton({ onClick }: { onClick: VoidFunction }) { + const handleDeselect = useCallback(() => { + emitConfirmationDeletionModal({ + onConfirm: onClick, + title: t`Remove NFT`, + description: t`Are you sure you want to remove this NFT?`, + }) + }, [onClick]) + + return ( +
+ + + Remove NFT + +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/NftCreditsSection.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/NftCreditsSection.tsx new file mode 100644 index 0000000000..22f2b12fb4 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/NftCreditsSection.tsx @@ -0,0 +1,26 @@ +import { Trans } from '@lingui/macro' +import TooltipIcon from 'components/TooltipIcon' +import ETHAmount from 'components/currency/ETHAmount' +import { BigNumber } from 'ethers' + +export function NftCreditsSection({ credits }: { credits: bigint }) { + return ( + <> +
+ Your credits +
+
+ {/* // TODO: make ETHAmount take BigInts */} + credits{' '} + + You have NFT credits from previous payments. Select NFTs to mint + and use your credits. + + } + /> +
+ + ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTile.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTile.tsx new file mode 100644 index 0000000000..ba3881d138 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTile.tsx @@ -0,0 +1,32 @@ +import { Tooltip } from 'antd' +import { JuiceVideoThumbnailOrImage } from 'components/JuiceVideo/JuiceVideoThumbnailOrImage' +import { NftRewardTier } from 'models/nftRewards' +import { useMemo } from 'react' +import { pinataToGatewayUrl } from 'utils/ipfs' + +export function RedeemNftTile({ + rewardTier, + tokenId, +}: { + rewardTier: NftRewardTier | undefined + tokenId: string +}) { + const _name = rewardTier?.name ?? `NFT ${tokenId}` + const fileUrl = useMemo(() => { + if (!rewardTier?.fileUrl) return + return pinataToGatewayUrl(rewardTier.fileUrl) + }, [rewardTier?.fileUrl]) + return ( + +
+ +
+
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTiles.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTiles.tsx new file mode 100644 index 0000000000..a5cf4c8391 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftTiles.tsx @@ -0,0 +1,34 @@ +import Loading from 'components/Loading' +import { NfTsQuery } from 'generated/graphql' +import { useJB721DelegateTokenToNftReward } from '../hooks/useJB721DelegateTokenToNftReward' +import { RedeemNftTile } from './RedeemNftTile' + +function RedeemNftTileLoader({ nft }: { nft: NfTsQuery['nfts'][number] }) { + const tokenId = nft.tokenId.toHexString() + const _nft = { + ...nft, + tokenId, + } + const { data: rewardTier } = useJB721DelegateTokenToNftReward(_nft) + if (!rewardTier) + return ( +
+ +
+ ) + return +} + +export function RedeemNftTiles({ + nftAccountBalance, +}: { + nftAccountBalance: NfTsQuery | undefined +}) { + return ( +
+ {nftAccountBalance?.nfts.map((nft, i) => ( + + ))} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftsSection.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftsSection.tsx new file mode 100644 index 0000000000..7d5cc929ae --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/RedeemNftsSection/RedeemNftsSection.tsx @@ -0,0 +1,75 @@ +import { useV4UserNftCredits } from 'packages/v4/contexts/V4UserNftCreditsProvider' +import { NftCreditsSection } from './NftCreditsSection' + +export function RedeemNftsSection() { + // const [redeemNftsModalVisible, setRedeemNftsModalVisible] = useState(false) + + const nftCredits = useV4UserNftCredits() + + // TODO: This needs to be implemented + // const { fundingCycleMetadata, primaryTerminalCurrentOverflow } = + // useContext(V2V3ProjectContext) + // const { data, loading } = useNftAccountBalance({ + // accountAddress: userAddress, + // dataSourceAddress: fundingCycleMetadata?.dataSource, + // }) + // const { data: credits, loading: loadingCredits } = useNftCredits(userAddress) + + // const hasOverflow = primaryTerminalCurrentOverflow?.gt(0) + // const hasRedemptionRate = fundingCycleMetadata?.redemptionRate.gt(0) + // const canRedeem = + // hasOverflow && + // hasRedemptionRate && + // fundingCycleMetadata?.useDataSourceForRedeem + + // const hasRedeemableNfts = (data?.nfts?.length ?? 0) > 0 + + // const showRedeemSection = !loading && hasRedeemableNfts && !!userAddress + const showCreditSection = + !nftCredits.isLoading && nftCredits.data && nftCredits.data > 0n + + // if (!showRedeemSection && !showCreditSection) return null + if (!showCreditSection) return null + + return ( +
+ {showCreditSection ? ( +
+ +
+ ) : null} + + {/* TODO: Redeem nft section */} + {/* {showRedeemSection ? ( +
+
+ Your NFTs +
+ +
+ + + +
+ + {redeemNftsModalVisible && ( + setRedeemNftsModalVisible(false)} + onConfirmed={() => setRedeemNftsModalVisible(false)} + /> + )} +
+ ) : null} */} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/V4NftRewardsPanel.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/V4NftRewardsPanel.tsx new file mode 100644 index 0000000000..70de871008 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/V4NftRewardsPanel.tsx @@ -0,0 +1,47 @@ +import { Trans, t } from '@lingui/macro' +import { EmptyScreen } from 'components/Project/ProjectTabs/EmptyScreen' +import { NftReward, NftRewardSkeleton } from './NftReward/NftReward' +import { RedeemNftsSection } from './RedeemNftsSection/RedeemNftsSection' +import { useNftRewardsPanel } from './hooks/useNftRewardsPanel' + +export const V4NftRewardsPanel = () => { + const { + rewardTiers, + handleTierSelect, + handleTierDeselect, + loading: nftsLoading, + } = useNftRewardsPanel() + + return ( +
+

+ NFTs +

+ + + {!nftsLoading && rewardTiers?.length ? ( +
+ {rewardTiers?.map((tier, i) => ( +
+ handleTierSelect(tier.id, quantity)} + onDeselect={() => handleTierDeselect(tier.id)} + /> +
+ ))} +
+ ) : nftsLoading ? ( +
+ {[...Array(6)].map((_, i) => ( + + ))} +
+ ) : ( + + )} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useJB721DelegateTokenToNftReward.ts b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useJB721DelegateTokenToNftReward.ts new file mode 100644 index 0000000000..26542c7ece --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useJB721DelegateTokenToNftReward.ts @@ -0,0 +1,37 @@ +import { Nft } from 'generated/graphql' +import { NftRewardTier } from 'models/nftRewards' +import { + NFT_METADATA_CONTRIBUTION_FLOOR_ATTRIBUTES_INDEX, + useJB721DelegateTokenMetadata, +} from 'packages/v2v3/components/V2V3Project/ManageNftsSection/RedeemNftsModal/RedeemNftCard' + +export type RedeemingNft = Pick & { + tokenId: string +} + +export function useJB721DelegateTokenToNftReward(nft: RedeemingNft): { + data: NftRewardTier | undefined +} { + const { data: tierData } = useJB721DelegateTokenMetadata(nft.tokenUri) + const contributionFloor = + tierData?.attributes[NFT_METADATA_CONTRIBUTION_FLOOR_ATTRIBUTES_INDEX] + .value ?? 0 + + return { + data: tierData + ? { + name: tierData.name, + contributionFloor, + id: parseInt(nft.tokenId), + remainingSupply: undefined, + maxSupply: undefined, + fileUrl: tierData.image, + externalLink: undefined, + description: undefined, + beneficiary: undefined, + reservedRate: undefined, + votingWeight: undefined, + } + : undefined, + } +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useNftRewardsPanel.ts b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useNftRewardsPanel.ts new file mode 100644 index 0000000000..5184ab5a59 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4NftRewardsPanel/hooks/useNftRewardsPanel.ts @@ -0,0 +1,36 @@ +import { useProjectDispatch } from 'packages/v4/components/ProjectDashboard/redux/hooks' +import { payRedeemActions } from 'packages/v4/components/ProjectDashboard/redux/payRedeemSlice' +import { projectCartActions } from 'packages/v4/components/ProjectDashboard/redux/projectCartSlice' +import { V4NftRewardsContext } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import { useCallback, useContext } from 'react' + +export const useNftRewardsPanel = () => { + const dispatch = useProjectDispatch() + const { + nftRewards: { rewardTiers }, + loading, + } = useContext(V4NftRewardsContext) + + const handleTierSelect = useCallback( + (tierId: number, quantity: number) => { + dispatch(payRedeemActions.changeToPay()) + dispatch(projectCartActions.upsertNftReward({ id: tierId, quantity })) + }, + [dispatch], + ) + + const handleTierDeselect = useCallback( + (tierId: number) => { + dispatch(payRedeemActions.changeToPay()) + dispatch(projectCartActions.removeNftReward({ id: tierId })) + }, + [dispatch], + ) + + return { + rewardTiers, + loading, + handleTierSelect, + handleTierDeselect, + } +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ProjectTabs.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ProjectTabs.tsx index f88a7c5575..0f0534b016 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ProjectTabs.tsx +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4ProjectTabs.tsx @@ -8,6 +8,7 @@ import { useProjectPageQueries } from '../hooks/useProjectPageQueries' import V4AboutPanel from './V4AboutPanel' import { V4ActivityPanel } from './V4ActivityPanel/V4ActivityPanel' import { V4CyclesPayoutsPanel } from './V4CyclesPayoutsPanel/V4CyclesPayoutsPanel' +import { V4NftRewardsPanel } from './V4NftRewardsPanel/V4NftRewardsPanel' import { V4TokensPanel } from './V4TokensPanel/V4TokensPanel' type ProjectTabConfig = { @@ -20,6 +21,8 @@ type ProjectTabConfig = { export const V4ProjectTabs = ({ className }: { className?: string }) => { const { projectPageTab, setProjectPageTab } = useProjectPageQueries() + const showNftRewards = true + const containerRef = useRef(null) const panelRef = useRef(null) const isPanelVisible = useOnScreen(panelRef) @@ -47,6 +50,12 @@ export const V4ProjectTabs = ({ className }: { className?: string }) => { () => [ { id: 'activity', name: t`Activity`, panel: }, { id: 'about', name: t`About`, panel: }, + { + id: 'nft_rewards', + name: t`NFTs`, + panel: , + hideTab: !showNftRewards, + }, { id: 'cycle_payouts', name: t`Cycles & Payouts`, @@ -54,7 +63,7 @@ export const V4ProjectTabs = ({ className }: { className?: string }) => { }, { id: 'tokens', name: t`Tokens`, panel: }, ], - [], + [showNftRewards], ) const selectedTabIndex = useMemo(() => { diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4BurnOrRedeemModal.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4BurnOrRedeemModal.tsx new file mode 100644 index 0000000000..a4a6c36814 --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4BurnOrRedeemModal.tsx @@ -0,0 +1,409 @@ +import { t, Trans } from '@lingui/macro' +import { waitForTransactionReceipt } from '@wagmi/core' +import { Checkbox, Descriptions, Form } from 'antd' +import { useForm } from 'antd/lib/form/Form' +import InputAccessoryButton from 'components/buttons/InputAccessoryButton' +import { Callout } from 'components/Callout/Callout' +import ETHAmount from 'components/currency/ETHAmount' +import FormattedNumberInput from 'components/inputs/FormattedNumberInput' +import TransactionModal from 'components/modals/TransactionModal' +import { TokenAmount } from 'components/TokenAmount' +import { TxHistoryContext } from 'contexts/Transaction/TxHistoryContext' +import { BigNumber } from 'ethers' +import { useWallet } from 'hooks/Wallet' +import { formatEther, NATIVE_TOKEN } from 'juice-sdk-core' +import { + useJBContractContext, + useJBRulesetContext, + useJBTokenContext, + useNativeTokenSurplus, + useWriteJbControllerBurnTokensOf, + useWriteJbMultiTerminalRedeemTokensOf, +} from 'juice-sdk-react' +import { useV4UserTotalTokensBalance } from 'packages/v4/contexts/V4UserTotalTokensBalanceProvider' +import { useETHReceivedFromTokens } from 'packages/v4/hooks/useETHReceivedFromTokens' +import { usePayoutLimit } from 'packages/v4/hooks/usePayoutLimit' +import { useV4TotalTokenSupply } from 'packages/v4/hooks/useV4TotalTokenSupply' +import { V4_CURRENCY_USD } from 'packages/v4/utils/currency' +import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' +import { wagmiConfig } from 'packages/v4/wagmiConfig' +import React, { useState } from 'react' +import { emitErrorNotification } from 'utils/notifications' +import { tokenSymbolText } from 'utils/tokenSymbolText' +import { parseEther } from 'viem' + +// This doubles as the 'Redeem' and 'Burn' modal depending on if project has overflow +export function V4BurnOrRedeemModal({ + open, + onCancel, + onConfirmed, +}: { + open?: boolean + onCancel?: VoidFunction + onConfirmed?: VoidFunction +}) { + const { contracts, projectId } = useJBContractContext() + const { addTransaction } = React.useContext(TxHistoryContext) + const { token } = useJBTokenContext() + const { userAddress } = useWallet() + const payoutLimitResult = usePayoutLimit() + const payoutLimit = payoutLimitResult.data.amount ?? 0n + const surplusResult = useNativeTokenSurplus() + const totalTokenSupplyResult = useV4TotalTokenSupply() + const rulesetMetadata = useJBRulesetContext().rulesetMetadata.data + const userTokenBalance = useV4UserTotalTokensBalance().data ?? 0n + + const { writeContractAsync: writeRedeem } = + useWriteJbMultiTerminalRedeemTokensOf() + const { writeContractAsync: writeBurnTokens } = + useWriteJbControllerBurnTokensOf() + + const [form] = useForm<{ + redeemAmount: string | undefined + legalCheckbox: boolean + }>() + const checkedLegal = Form.useWatch('legalCheckbox', form) + const redeemAmount = Form.useWatch('redeemAmount', form) + + const redeemAmountBigInt = React.useMemo( + () => parseEther(redeemAmount ?? '0'), + [redeemAmount], + ) + const [loading, setLoading] = useState() + const [memo] = useState('') + const [transactionPending, setTransactionPending] = useState() + + const maxClaimable = useETHReceivedFromTokens(userTokenBalance) ?? 0n + const rewardAmount = useETHReceivedFromTokens(redeemAmountBigInt) ?? 0n + + const surplus = React.useMemo( + () => surplusResult.data ?? 0n, + [surplusResult.data], + ) + const redemptionEnabled = React.useMemo( + () => payoutLimit !== MAX_PAYOUT_LIMIT, + [payoutLimit], + ) + const hasSurplus = React.useMemo(() => surplus > 0n, [surplus]) + const canRedeem = React.useMemo( + () => hasSurplus && redemptionEnabled, + [hasSurplus, redemptionEnabled], + ) + + const totalSupplyExceeded = React.useMemo(() => { + if (!redeemAmount) return + return parseEther(redeemAmount) > (totalTokenSupplyResult.data ?? 0n) + }, [redeemAmount, totalTokenSupplyResult.data]) + + const personalBalanceExceeded = React.useMemo(() => { + if (!redeemAmount) return + return parseEther(redeemAmount) > userTokenBalance + }, [redeemAmount, userTokenBalance]) + + const inUsd = React.useMemo( + () => payoutLimitResult.data.currency === V4_CURRENCY_USD, + [payoutLimitResult.data.currency], + ) + + const totalTokenSupply = totalTokenSupplyResult.data ?? 0n + // 0.5% slippage for USD-denominated projects + const minReturnedTokens = + payoutLimitResult.data.currency === V4_CURRENCY_USD + ? ((rewardAmount ?? 0n) * 1000n) / 1005n + : rewardAmount ?? 0n + + const modalTitle = React.useMemo(() => { + const tokensTextLong = tokenSymbolText({ + tokenSymbol: token.data?.symbol, + capitalize: false, + plural: true, + includeTokenWord: true, + }) + if (canRedeem) { + return t`Redeem ${tokensTextLong} for ETH` + } + return t`Burn ${tokensTextLong}` + }, [canRedeem, token.data?.symbol]) + + const validateRedeemAmount = () => { + if (redeemAmountBigInt === 0n) { + return Promise.reject(t`Required`) + } else if (redeemAmountBigInt > userTokenBalance) { + return Promise.reject(t`Insufficient token balance`) + } else if (redeemAmountBigInt > totalTokenSupply) { + // Error message already showing for this case + return Promise.reject() + } + return Promise.resolve() + } + + const executeRedeemTransaction = async () => { + await form.validateFields() + if (!minReturnedTokens) return + if (!contracts.primaryNativeTerminal.data || !projectId) { + emitErrorNotification('Failed to prepare transaction') + return + } + if (!userAddress) { + emitErrorNotification('No wallet connected') + return + } + + setLoading(true) + + try { + const hash = await writeRedeem({ + address: contracts.primaryNativeTerminal.data, + args: [ + userAddress, + BigInt(projectId), + NATIVE_TOKEN, + redeemAmountBigInt, + 0n, + userAddress, + '0x0', + ] as const, + }) + addTransaction?.('Redeem', { hash }) + + setTransactionPending(true) + form.resetFields() + + await waitForTransactionReceipt(wagmiConfig, { + hash, + }) + setTransactionPending(false) + setLoading(false) + onConfirmed?.() + } catch (e) { + setTransactionPending(false) + setLoading(false) + emitErrorNotification((e as unknown as Error).message) + } + } + + const executeBurnTransaction = async () => { + await form.validateFields() + if (!contracts.controller.data || !projectId) { + emitErrorNotification('Failed to prepare transaction') + return + } + if (!userAddress) { + emitErrorNotification('No wallet connected') + return + } + + setLoading(true) + + try { + const hash = await writeBurnTokens({ + address: contracts.controller.data, + args: [userAddress, projectId, redeemAmountBigInt, memo] as const, + }) + addTransaction?.('Burn', { hash }) + setTransactionPending(true) + form.resetFields() + + await waitForTransactionReceipt(wagmiConfig, { + hash, + }) + setTransactionPending(false) + setLoading(false) + onConfirmed?.() + } catch (e) { + setTransactionPending(false) + setLoading(false) + emitErrorNotification((e as unknown as Error).message) + } + } + + return ( + { + canRedeem ? executeRedeemTransaction() : executeBurnTransaction() + }} + onCancel={() => { + form.resetFields() + onCancel?.() + }} + okText={modalTitle} + okButtonProps={{ + disabled: + !redeemAmount || parseFloat(redeemAmount) === 0 || !checkedLegal, + }} + width={540} + centered + > +
+
+ {canRedeem ? ( +
+ + Tokens are burned when they are redeemed. + +
+ + Redeem your tokens to reclaim some ETH that isn't needed for + payouts. This cycle's redemption rate{' '} + determines the amount of ETH you'll receive. + +
+
+ ) : ( + + {!hasSurplus && ( + + + This project has no ETH available for redemptions + + . You won't receive any ETH for burning your tokens. + + )} + {!redemptionEnabled && ( + + This project has a redemptions turned off. + You won't receive any ETH for burning your tokens. + + )} + + )} +
+ + + Redemption rate}> + {rulesetMetadata?.redemptionRate.formatPercentage()} + + + Your{' '} + {tokenSymbolText({ + tokenSymbol: token.data?.symbol, + })}{' '} + balance + + } + > + + + Total redemption value}> + + + + +
+ + Tokens to redeem + ) : ( + Tokens to burn + ) + } + rules={[{ validator: validateRedeemAmount }]} + > + { + form.setFieldsValue({ + redeemAmount: formatEther(userTokenBalance), + }) + }} + /> + } + disabled={userTokenBalance === 0n} + // onChange={val => form.se(val)} + /> + + + value + ? Promise.resolve() + : Promise.reject( + new Error(t`You must confirm your compliance.`), + ), + }, + ]} + > + + + + I confirm that the use and redemption of crypto tokens is + legal in my jurisdiction, and that I am fully responsible + for compliance with all relevant laws and regulations. + + + + + + {/* Will comment memo form due to [note] missing in subgraph - see discussion in https://discord.com/channels/939317843059679252/1035458515709464586/1053400936971771974 */} + {/* + + */} + + + {canRedeem && !totalSupplyExceeded && minReturnedTokens > 0n ? ( +
+ <> + {/* If USD denominated, can only define the lower limit (not exact amount), hence 'at least' */} + {/* Using 4 full sentences for translation purposes */} + {!personalBalanceExceeded ? ( + <> + {inUsd ? ( + + You will receive at least{' '} + + + ) : ( + + You will receive{' '} + + + )} + + ) : ( + <> + {inUsd ? ( + + You would receive at least{' '} + + + ) : ( + + You would receive{' '} + + + )} + + )} + +
+ ) : null} +
+
+
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4RedeemTokensButton.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4RedeemTokensButton.tsx new file mode 100644 index 0000000000..4cc06070ef --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4RedeemTokensButton.tsx @@ -0,0 +1,71 @@ +import { Trans, t } from '@lingui/macro' +import { Button, Tooltip } from 'antd' +import { useNativeTokenSurplus } from 'juice-sdk-react' +import { useV4UserTotalTokensBalance } from 'packages/v4/contexts/V4UserTotalTokensBalanceProvider' +import { usePayoutLimit } from 'packages/v4/hooks/usePayoutLimit' +import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' +import React, { useCallback, useMemo, useState } from 'react' +import { V4BurnOrRedeemModal } from './V4BurnOrRedeemModal' + +export const V4RedeemTokensButton = ({ + className, + containerClassName, +}: { + className?: string + containerClassName?: string +}) => { + const payoutLimitResult = usePayoutLimit() + const payoutLimit = payoutLimitResult.data.amount ?? 0n + const surplusResult = useNativeTokenSurplus() + const surplus = surplusResult.data ?? 0n + const userTokenBalance = useV4UserTotalTokensBalance().data ?? 0n + + const loading = React.useMemo( + () => payoutLimitResult.isLoading && surplusResult.isLoading, + [payoutLimitResult.isLoading, surplusResult.isLoading], + ) + + const [open, setOpen] = useState(false) + const openModal = useCallback(() => setOpen(true), []) + const closeModal = useCallback(() => setOpen(false), []) + + const hasSurplus = React.useMemo(() => surplus > 0n, [surplus]) + + const redeemTokensDisabled = useMemo(() => { + if (!userTokenBalance || !hasSurplus || payoutLimit === MAX_PAYOUT_LIMIT) + return true + return userTokenBalance === 0n + }, [hasSurplus, payoutLimit, userTokenBalance]) + + const redeemDisabledTooltip = useMemo(() => { + if (!userTokenBalance || userTokenBalance === 0n) + return t`No tokens to redeem.` + if (!hasSurplus) + return t`This project has no ETH, or is using all of its ETH for payouts.` + if (payoutLimit === 0n) return t`This project has redemptions turned off.` + return undefined + }, [hasSurplus, payoutLimit, userTokenBalance]) + + return ( + + + + + ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokenRedemptionCallout.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokenRedemptionCallout.tsx new file mode 100644 index 0000000000..28a35fd7ea --- /dev/null +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokenRedemptionCallout.tsx @@ -0,0 +1,46 @@ +import { InformationCircleIcon } from '@heroicons/react/24/outline' +import { t } from '@lingui/macro' +import { useJBRulesetContext } from 'juice-sdk-react' +import { usePayoutLimit } from 'packages/v4/hooks/usePayoutLimit' +import { MAX_PAYOUT_LIMIT } from 'packages/v4/utils/math' +import React, { useMemo } from 'react' +import { twMerge } from 'tailwind-merge' + +export const V4TokenRedemptionCallout = () => { + const rulesetMetadata = useJBRulesetContext().rulesetMetadata.data + const payoutLimit = usePayoutLimit() + + const redemptionEnabled = React.useMemo(() => { + if (!rulesetMetadata || payoutLimit.isLoading) return + // TODO: Update redemptionRate to be cashOut + return ( + rulesetMetadata.redemptionRate.value > 0 && + payoutLimit.data.amount !== MAX_PAYOUT_LIMIT + ) + }, [payoutLimit.data.amount, payoutLimit.isLoading, rulesetMetadata]) + + const loading = useMemo( + () => redemptionEnabled === undefined, + [redemptionEnabled], + ) + + const text = t`This cycle has token redemptions ${ + redemptionEnabled ? 'enabled' : 'disabled' + }` + + if (loading) return null + + return ( +
+ + {text} +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokensPanel.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokensPanel.tsx index de2f7b7234..852df78c49 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokensPanel.tsx +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/V4TokensPanel.tsx @@ -13,6 +13,7 @@ import { AddTokenToMetamaskButton } from 'components/buttons/AddTokenToMetamaskB import { ISSUE_ERC20_EXPLANATION } from 'components/strings' import { useJBContractContext } from 'juice-sdk-react' import { V4TokenHoldersModal } from 'packages/v4/components/modals/V4TokenHoldersModal/V4TokenHoldersModal' +import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' import { v4ProjectRoute } from 'packages/v4/utils/routes' import { useCallback, useState } from 'react' import { reloadWindow } from 'utils/windowUtils' @@ -20,9 +21,12 @@ import { useChainId } from 'wagmi' import { useV4BalanceMenuItemsUserFlags } from './hooks/useV4BalanceMenuItemsUserFlags' import { useV4TokensPanel } from './hooks/useV4TokensPanel' import { useV4YourBalanceMenuItems } from './hooks/useV4YourBalanceMenuItems' +import { V4BurnOrRedeemModal } from './V4BurnOrRedeemModal' import { V4ClaimTokensModal } from './V4ClaimTokensModal' import { V4MintModal } from './V4MintModal' +import { V4RedeemTokensButton } from './V4RedeemTokensButton' import { V4ReservedTokensSubPanel } from './V4ReservedTokensSubPanel' +import { V4TokenRedemptionCallout } from './V4TokenRedemptionCallout' export const V4TokensPanel = () => { const { @@ -34,6 +38,7 @@ export const V4TokensPanel = () => { projectToken, totalSupply, } = useV4TokensPanel() + const projectHasErc20Token = useProjectHasErc20Token() const { canMintTokens } = useV4BalanceMenuItemsUserFlags() @@ -49,8 +54,8 @@ export const V4TokensPanel = () => { const { items, - // redeemModalVisible, - // setRedeemModalVisible, + redeemModalVisible, + setRedeemModalVisible, claimTokensModalVisible, setClaimTokensModalVisible, mintModalVisible, @@ -66,7 +71,7 @@ export const V4TokensPanel = () => {

Tokens

- {/* */} +
{!userTokenBalanceLoading && userTokenBalance !== undefined && ( @@ -76,7 +81,7 @@ export const V4TokensPanel = () => { {userTokenBalance.format(8)} tokens
- {/* {projectHasErc20Token && ( + {projectHasErc20Token && ( - )} */} - {/* */} + />
} @@ -151,11 +156,11 @@ export const V4TokensPanel = () => { open={tokenHolderModalOpen} onClose={closeTokenHolderModal} /> - {/* setRedeemModalVisible(false)} onConfirmed={reloadWindow} - /> */} + /> setClaimTokensModalVisible(false)} @@ -179,7 +184,7 @@ const ProjectTokenCard = () => { const chainId = useChainId() const { projectId: projectIdBig } = useJBContractContext() const projectId = Number(projectIdBig) - + const { projectToken, projectTokenAddress, @@ -203,25 +208,26 @@ const ProjectTokenCard = () => {
{projectTokenAddress && projectHasErc20Token && ( )} {canCreateErc20Token ? ( - - - ): null} + ) : null} } /> diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.ts b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.ts index aaeb54f165..ebc3beae96 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.ts +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4TokensPanel.ts @@ -1,20 +1,17 @@ -import { useWallet } from 'hooks/Wallet' import { JBProjectToken } from 'juice-sdk-core' -import { useJBContractContext, useJBTokenContext, useReadJbTokensTotalBalanceOf } from 'juice-sdk-react' +import { useJBTokenContext } from 'juice-sdk-react' +import { useV4UserTotalTokensBalance } from 'packages/v4/contexts/V4UserTotalTokensBalanceProvider' import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' import { useV4TotalTokenSupply } from 'packages/v4/hooks/useV4TotalTokenSupply' import { useV4WalletHasPermission } from 'packages/v4/hooks/useV4WalletHasPermission' import { V4OperatorPermission } from 'packages/v4/models/v4Permissions' import { useMemo } from 'react' import { tokenSymbolText } from 'utils/tokenSymbolText' -import { zeroAddress } from 'viem' export const useV4TokensPanel = () => { - const { projectId } = useJBContractContext() - const { userAddress } = useWallet() const { token } = useJBTokenContext() const tokenAddress = token?.data?.address - + const { data: _totalTokenSupply } = useV4TotalTokenSupply() const projectToken = tokenSymbolText({ @@ -29,12 +26,8 @@ export const useV4TokensPanel = () => { const projectHasErc20Token = useProjectHasErc20Token() const { data: _userTokenBalance, isLoading: userTokenBalanceLoading } = - useReadJbTokensTotalBalanceOf({ - args: [ - userAddress ?? zeroAddress, - projectId - ] - }) + useV4UserTotalTokensBalance() + const userTokenBalance = useMemo(() => { if (_userTokenBalance === undefined) return return new JBProjectToken(_userTokenBalance ?? 0n) diff --git a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4YourBalanceMenuItems.tsx b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4YourBalanceMenuItems.tsx index f122e8b256..e5e5486336 100644 --- a/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4YourBalanceMenuItems.tsx +++ b/src/packages/v4/views/V4ProjectDashboard/V4ProjectTabs/V4TokensPanel/hooks/useV4YourBalanceMenuItems.tsx @@ -1,6 +1,7 @@ import { + FireIcon, PlusCircleIcon, - ReceiptRefundIcon + ReceiptRefundIcon, } from '@heroicons/react/24/outline' import { t } from '@lingui/macro' import { PopupMenuItem } from 'components/ui/PopupMenu' @@ -8,7 +9,7 @@ import { ReactNode, useMemo, useState } from 'react' import { useV4BalanceMenuItemsUserFlags } from './useV4BalanceMenuItemsUserFlags' export const useV4YourBalanceMenuItems = () => { - const { canClaimErcTokens, canMintTokens } = + const { canBurnTokens, canClaimErcTokens, canMintTokens } = useV4BalanceMenuItemsUserFlags() const [redeemModalVisible, setRedeemModalVisible] = useState(false) @@ -21,18 +22,18 @@ export const useV4YourBalanceMenuItems = () => { const items = useMemo(() => { const tokenMenuItems: PopupMenuItem[] = [] - // if (canBurnTokens) { - // tokenMenuItems.push({ - // id: 'burn', - // label: ( - // } - // /> - // ), - // onClick: () => setRedeemModalVisible(true), - // }) - // } + if (canBurnTokens) { + tokenMenuItems.push({ + id: 'burn', + label: ( + } + /> + ), + onClick: () => setRedeemModalVisible(true), + }) + } if (canClaimErcTokens) { tokenMenuItems.push({ id: 'claim', @@ -70,7 +71,7 @@ export const useV4YourBalanceMenuItems = () => { // }) // } return tokenMenuItems - }, [canClaimErcTokens, canMintTokens]) + }, [canBurnTokens, canClaimErcTokens, canMintTokens]) return { items, diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/EditNftsPage.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/EditNftsPage.tsx new file mode 100644 index 0000000000..f4fac3115b --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/EditNftsPage.tsx @@ -0,0 +1,30 @@ +import { ProjectMetadataContext } from 'contexts/ProjectMetadataContext' +import { useJBRulesetContext } from 'juice-sdk-react' +import { useNftDeployerCanReconfigure } from 'packages/v2v3/hooks/JB721Delegate/contractReader/useNftDeployerCanReconfigure' +import { useHasNftRewards } from 'packages/v4/hooks/useHasNftRewards' +import useProjectOwnerOf from 'packages/v4/hooks/useV4ProjectOwnerOf' +import { useContext } from 'react' +import { LaunchNftsPage } from './LaunchNftCollection' +import { EnableNftsCard } from './LaunchNftCollection/EnableNftsCard' +import { UpdateNftsPage } from './UpdateNftsPage' + +export function EditNftsPage() { + const { projectId } = useContext(ProjectMetadataContext) + + const { data: projectOwnerAddress } = useProjectOwnerOf() + const { rulesetMetadata: { data: _rulesetMetadata } } = useJBRulesetContext() + const hasExistingNfts = useHasNftRewards() + + const nftDeployerCanReconfigure = useNftDeployerCanReconfigure({ + projectId, + projectOwnerAddress, + }) + + if (hasExistingNfts) { + return + } else if (!nftDeployerCanReconfigure) { + return + } else { + return + } +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsCard.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsCard.tsx new file mode 100644 index 0000000000..9fd6f4d9a4 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsCard.tsx @@ -0,0 +1,39 @@ +import { Trans } from '@lingui/macro' +import { Button } from 'antd' +import Image from "next/legacy/image" +import { useState } from 'react' +import { EnableNftsModal } from './EnableNftsModal' +import noNftsImage from '/public/assets/images/settings/no-nfts.webp' + +export function EnableNftsCard() { + const [enableNftsModalOpen, setEnableNftsModalOpen] = useState(false) + return ( + <> +
+ {`No + + You haven't launched an NFT collection yet. + + +
+ + setEnableNftsModalOpen(false)} + /> + + ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsModal.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsModal.tsx new file mode 100644 index 0000000000..47d2858843 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/EnableNftsModal.tsx @@ -0,0 +1,64 @@ +import { Trans, t } from '@lingui/macro' + +import ExternalLink from 'components/ExternalLink' +import TooltipIcon from 'components/TooltipIcon' +import TransactionModal from 'components/modals/TransactionModal' +import { reloadWindow } from 'utils/windowUtils' +import { useSetNftOperatorPermissionsTx } from 'packages/v2v3/hooks/JB721Delegate/transactor/useSetNftOperatorPermissionsTx' +import { useState } from 'react' + +// V4TODO: this whole component needs to be v4-ified +export function EnableNftsModal({ + open, + onClose, +}: { + open: boolean + onClose: VoidFunction +}) { + const [loading, setLoading] = useState(false) + + const setNftOperatorPermissionsTx = useSetNftOperatorPermissionsTx() + + const setPermissions = async () => { + setLoading(true) + await setNftOperatorPermissionsTx(undefined, { + onConfirmed: () => { + setLoading(false) + reloadWindow() + }, + onError() { + setLoading(false) + }, + }) + } + + return ( + + + To add NFTs to your next cycle, you'll need to{' '} + grant NFT permissions. + {' '} + + Allow the{' '} + + Juicebox NFT deployer contract + {' '} + to edit this project's cycle. + + } + /> + + ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx new file mode 100644 index 0000000000..fa900a1651 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/LaunchNftsCollection.tsx @@ -0,0 +1,64 @@ +import { AddNftCollectionForm } from 'components/NftRewards/AddNftCollectionForm/AddNftCollectionForm' +import { Button } from 'antd' +import { Trans } from '@lingui/macro' +import TransactionModal from 'components/modals/TransactionModal' +import { TransactionSuccessModal } from '../../EditCyclePage/TransactionSuccessModal' +import { useAppSelector } from 'redux/hooks/useAppSelector' +import { useLaunchNftsForm } from './hooks/useLaunchNftsForm' + +// v4TODO: this whole component needs to be v4-ified +export function LaunchNftsPage() { + const { + form, + launchCollection, + launchButtonLoading, + launchTxPending, + successModalOpen, + setSuccessModalOpen, + } = useLaunchNftsForm() + + const postPayModalData = useAppSelector( + state => state.creatingV2Project.nftRewards.postPayModal, + ) + const nftRewardsData = useAppSelector( + state => state.creatingV2Project.nftRewards, + ) + + return ( + <> + + Deploy NFT collection + + } + /> + + setSuccessModalOpen(false)} + content={ + <> +
+ Your new NFTs have been deployed +
+
+ + New NFTs will be available in your next cycle as long as it + starts after your edit deadline. + +
+ + } + /> + + ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/hooks/useLaunchNftsForm.ts b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/hooks/useLaunchNftsForm.ts new file mode 100644 index 0000000000..294aa175cf --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/hooks/useLaunchNftsForm.ts @@ -0,0 +1,122 @@ +import { + DEFAULT_NFT_FLAGS, + DEFAULT_NFT_PRICING, +} from 'redux/slices/editingV2Project' +import { + EditingFundingCycleConfig, + useEditingFundingCycleConfig, +} from 'packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useEditingFundingCycleConfig' +import { + defaultNftCollectionDescription, + defaultNftCollectionName, + pinNftCollectionMetadata, + pinNftRewards, +} from 'utils/nftRewards' + +import { JB721GovernanceType } from 'models/nftRewards' +import { NftRewardsFormProps } from 'components/NftRewards/AddNftCollectionForm/AddNftCollectionForm' +import { useAppSelector } from 'redux/hooks/useAppSelector' +import { useForm } from 'antd/lib/form/Form' +import { useReconfigureFundingCycle } from 'packages/v2v3/components/V2V3Project/V2V3ProjectSettings/hooks/useReconfigureFundingCycle' +import { useState } from 'react' + +// v4TODO: this whole component needs to be v4-ified +export const useLaunchNftsForm = () => { + const [form] = useForm() + + const [ipfsUploading, setIpfsUploading] = useState(false) + const [successModalOpen, setSuccessModalOpen] = useState(false) + + const { + projectMetadata: { logoUri, name: projectName }, + } = useAppSelector(state => state.editingV2Project) + + const editingFundingCycleConfig = useEditingFundingCycleConfig() + const { + reconfigureLoading, + reconfigureFundingCycle, + txPending: launchTxPending, + } = useReconfigureFundingCycle({ + editingFundingCycleConfig, + memo: 'First NFT collection', + launchedNewNfts: true, + onComplete: () => setSuccessModalOpen(true), + }) + + const launchButtonLoading = ipfsUploading || reconfigureLoading + + const { + editingPayoutGroupedSplits, + editingReservedTokensGroupedSplits, + editingFundingCycleMetadata, + editingFundingCycleData, + editingFundAccessConstraints, + editingMustStartAtOrAfter, + } = editingFundingCycleConfig + + const launchCollection = async () => { + setIpfsUploading(true) + const formValues = form.getFieldsValue(true) as NftRewardsFormProps + const newRewardTiers = formValues.rewards + const collectionName = + formValues.collectionName ?? defaultNftCollectionName(projectName) + const collectionDescription = + formValues.collectionDescription ?? + defaultNftCollectionDescription(projectName) + const collectionLogoUri = logoUri ?? '' + const collectionInfoUri = '' + + const [rewardTiersCIDs, nftCollectionMetadataUri] = await Promise.all([ + newRewardTiers ? pinNftRewards(newRewardTiers) : [], + pinNftCollectionMetadata({ + collectionName, + collectionDescription, + collectionLogoUri, + collectionInfoUri, + }), + ]) + + const latestEditingData: EditingFundingCycleConfig = { + editingPayoutGroupedSplits, + editingReservedTokensGroupedSplits, + editingFundingCycleMetadata, + editingFundingCycleData, + editingFundAccessConstraints, + editingNftRewards: { + rewardTiers: newRewardTiers, + collectionMetadata: { + uri: nftCollectionMetadataUri, + symbol: formValues.collectionSymbol, + name: collectionName, + description: collectionDescription, + }, + CIDs: rewardTiersCIDs, + postPayModal: { + ctaText: formValues.postPayButtonText, + ctaLink: formValues.postPayButtonLink, + content: formValues.postPayMessage, + }, + flags: { + ...DEFAULT_NFT_FLAGS, + preventOverspending: + formValues.preventOverspending ?? + DEFAULT_NFT_FLAGS.preventOverspending, + }, + governanceType: JB721GovernanceType.NONE, + pricing: DEFAULT_NFT_PRICING, // TODO add to form + }, + editingMustStartAtOrAfter, + } + reconfigureFundingCycle(latestEditingData) + setIpfsUploading(false) + } + + return { + form, + launchButtonLoading, + launchCollection, + successModalOpen, + setSuccessModalOpen, + launchTxPending, + } +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/index.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/index.tsx new file mode 100644 index 0000000000..ac2a006b48 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/LaunchNftCollection/index.tsx @@ -0,0 +1 @@ +export * from './LaunchNftsCollection' diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditCollectionDetailsSection.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditCollectionDetailsSection.tsx new file mode 100644 index 0000000000..ead7c72941 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditCollectionDetailsSection.tsx @@ -0,0 +1,158 @@ +import { Button, Form } from 'antd' +import { useCallback, useContext, useEffect, useMemo, useState } from 'react' + +import { Callout } from 'components/Callout/Callout' +import Loading from 'components/Loading' +import { MarketplaceFormFields } from './formFields' +import { NftCollectionDetailsFormItems } from './NftCollectionDetailsFormItems' +import { NftCollectionMetadata } from 'models/nftRewards' +import { NftRewardsContext } from 'packages/v2v3/contexts/NftRewards/NftRewardsContext' +import { Trans } from '@lingui/macro' +import { useForm } from 'antd/lib/form/Form' +import { useNftCollectionMetadata } from 'packages/v2v3/hooks/JB721Delegate/useNftCollectionMetadata' +import { useReconfigureNftCollectionMetadata } from 'packages/v2v3/hooks/transactor/useReconfigureNftCollectionMetadata' + +// v4TODO: this whole component needs to be v4-ified +const useCollectionDetailsForm = () => { + const [form] = useForm() + const { + nftRewards: { + collectionMetadata: { uri: collectionMetadataUri }, + governanceType, + }, + } = useContext(NftRewardsContext) + + const { data: collectionMetadata, isLoading } = useNftCollectionMetadata( + collectionMetadataUri, + ) + + const initialValues: MarketplaceFormFields = useMemo(() => { + return { + collectionName: collectionMetadata?.name ?? '', + collectionDescription: collectionMetadata?.description ?? '', + collectionSymbol: collectionMetadata?.symbol ?? '', + onChainGovernance: governanceType, + } + }, [ + collectionMetadata?.name, + collectionMetadata?.description, + collectionMetadata?.symbol, + governanceType, + ]) + + return { form, initialValues, isLoading } +} + +export function EditCollectionDetailsSection() { + const { + form: marketplaceForm, + initialValues, + isLoading, + } = useCollectionDetailsForm() + const [formHasUpdated, setFormHasUpdated] = useState() + const [txLoading, setTxLoading] = useState() + const [txSuccessful, setTxSuccessful] = useState() + const [txFailed, setTxFailed] = useState() + + const reconfigureNftCollectionMetadata = useReconfigureNftCollectionMetadata() + + const handleFormChange = useCallback(() => { + const hasChanged = (name: string, initialValue: unknown) => + initialValue !== marketplaceForm.getFieldValue(name) + const collectionNameChanged = hasChanged( + 'collectionName', + initialValues.collectionName, + ) + const collectionDescriptionChanged = hasChanged( + 'collectionDescription', + initialValues.collectionDescription, + ) + const collectionSymbolChanged = hasChanged( + 'collectionSymbol', + initialValues.collectionSymbol, + ) + + const hasUpdated = + collectionNameChanged || + collectionDescriptionChanged || + collectionSymbolChanged + + setFormHasUpdated(hasUpdated) + }, [marketplaceForm, initialValues, setFormHasUpdated]) + + useEffect(() => handleFormChange(), [handleFormChange]) + + const submitCollectionMetadata = async () => { + setTxLoading(true) + const newCollectionMetadata: NftCollectionMetadata = { + name: marketplaceForm.getFieldValue('collectionName'), + description: marketplaceForm.getFieldValue('collectionDescription'), + symbol: marketplaceForm.getFieldValue('collectionSymbol'), + } + + const txOpts = { + onConfirmed() { + setTxLoading(false) + setTxSuccessful(true) + }, + } + + const txSuccess = await reconfigureNftCollectionMetadata( + { + ...newCollectionMetadata, + }, + txOpts, + ) + + if (!txSuccess) { + setTxFailed(true) + setTxLoading(false) + } + } + + if (isLoading) return + + return ( +
+ + + Changes to your collection details may not be reflected in some + marketplaces (like Opensea). Contact the marketplace for support. + + +
+ +
+ + {txSuccessful ? ( + + Saved! + + ) : txFailed ? ( + + Something went wrong! + + ) : null} +
+ +
+ ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx new file mode 100644 index 0000000000..5614d68192 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/EditNftsSection.tsx @@ -0,0 +1,156 @@ +import { Button, Empty } from 'antd' +import { Trans, t } from '@lingui/macro' +import { useCallback, useState } from 'react' + +import { Callout } from 'components/Callout/Callout' +import Loading from 'components/Loading' +import { RewardsList } from 'components/NftRewards/RewardsList/RewardsList' +import TransactionModal from 'components/modals/TransactionModal' +import { TransactionSuccessModal } from '../../EditCyclePage/TransactionSuccessModal' +import { useAppSelector } from 'redux/hooks/useAppSelector' +import { useEditingNfts } from '../hooks/useEditingNfts' +import { useHasNftRewards } from 'packages/v4/hooks/useHasNftRewards' +import { useUpdateCurrentCollection } from '../hooks/useUpdateCurrentCollection' + +// v4TODO: need to build launch NFT capabilities into this +export function EditNftsSection() { + const nftRewardsData = useAppSelector( + state => state.editingV2Project.nftRewards, + ) + const [submitLoading, setSubmitLoading] = useState(false) + const [successModalOpen, setSuccessModalOpen] = useState(false) + + const { rewardTiers, setRewardTiers, editedRewardTierIds, loading } = + useEditingNfts() + const hasNftRewards = useHasNftRewards() + const { updateExistingCollection, txLoading } = useUpdateCurrentCollection({ + editedRewardTierIds, + rewardTiers, + onConfirmed: () => setSuccessModalOpen(true), + }) + + const showNftRewards = hasNftRewards + + const onNftFormSaved = useCallback(async () => { + if (!rewardTiers) return + + setSubmitLoading(true) + await updateExistingCollection() + setSubmitLoading(false) + }, [rewardTiers, updateExistingCollection]) + + // const editingFundingCycleConfig = useEditingFundingCycleConfig() + // const { + // reconfigureLoading: removeDatasourceLoading, + // reconfigureFundingCycle, + // } = useReconfigureFundingCycle({ + // editingFundingCycleConfig, + // memo: 'Detach NFT collection', + // removeDatasource: true, + // onComplete: () => setSuccessModalOpen(true), + // }) + + // const removeDatasource = () => { + // reconfigureFundingCycle() + // } + + if (loading) return + + const allNftsRemoved = showNftRewards && rewardTiers?.length === 0 + + // const hasDataSourceButNoNfts = hasNftRewards && !rewardTiers + + return ( + <> + + Changes to NFTs will take effect immediately. + + +
+ + + {rewardTiers?.length === 0 && ( + + )} +
+ + {allNftsRemoved && ( + + +

+ You're about to delete all NFTs from your collection. This will + take effect immediately, and you can add NFTs back to the + collection at any time. +

+

+ If you want to COMPLETELY detach NFTs from your project, you can + do so in the Danger Zone section below. +

+
+
+ )} + + + + {/* {hasDataSourceButNoNfts && ( + +
+ Danger Zone +
+

+ This will remove the NFT Extension Contract from + your project's next funding cycle. You can relaunch a new NFT + collection for later cycles. +

+ +
+ )} */} + + + setSuccessModalOpen(false)} + content={ + <> +
+ Your NFTs have been edited successfully +
+
+ + New NFTs will available on your project page shortly. + +
+ + } + /> + + ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/NftCollectionDetailsFormItems.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/NftCollectionDetailsFormItems.tsx new file mode 100644 index 0000000000..a335185660 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/NftCollectionDetailsFormItems.tsx @@ -0,0 +1,28 @@ +import { t } from '@lingui/macro' +import { Form, Input } from 'antd' + +export function NftCollectionDetailsFormItems({ + isReconfigure, +}: { + isReconfigure?: boolean +}) { + return ( + <> + + + + {!isReconfigure ? ( + + + + ) : null} + + + + + ) +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/UpdateNftsPage.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/UpdateNftsPage.tsx new file mode 100644 index 0000000000..037a8c3a6b --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/UpdateNftsPage.tsx @@ -0,0 +1,17 @@ +import { t } from '@lingui/macro' +import { Tabs } from 'antd' +import { EditCollectionDetailsSection } from './EditCollectionDetailsSection' +import { EditNftsSection } from './EditNftsSection' + +export function UpdateNftsPage() { + const items = [ + { label: t`NFTs`, key: 'nfts', children: }, + { + label: t`Collection details`, + key: 'collection', + children: , + }, + ] + + return +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/formFields.ts b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/formFields.ts new file mode 100644 index 0000000000..e909771591 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/formFields.ts @@ -0,0 +1,5 @@ +export type MarketplaceFormFields = { + collectionName: string + collectionSymbol: string + collectionDescription: string +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/index.tsx b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/index.tsx new file mode 100644 index 0000000000..511e1182d5 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/UpdateNftsPage/index.tsx @@ -0,0 +1 @@ +export * from './UpdateNftsPage' diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useEditingNfts.ts b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useEditingNfts.ts new file mode 100644 index 0000000000..ea4d3f535e --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useEditingNfts.ts @@ -0,0 +1,49 @@ +import { useContext, useEffect, useState } from 'react' + +import { useForm } from 'antd/lib/form/Form' +import { NftRewardTier } from 'models/nftRewards' +import { V4NftRewardsContext } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' +import { tiersEqual } from 'utils/nftRewards' +import { MarketplaceFormFields } from '../UpdateNftsPage/formFields' + +export function useEditingNfts() { + const [rewardTiers, _setRewardTiers] = useState() + const [marketplaceForm] = useForm() + // a list of the `tierRanks` (IDs) of tiers that have been edited + const [editedRewardTierIds, setEditedRewardTierIds] = useState([]) + + const { nftRewards, loading } = useContext(V4NftRewardsContext) + + const deriveAndSetEditedIds = (newRewards: NftRewardTier[]) => { + if (!nftRewards.rewardTiers) return + const editedIds = nftRewards.rewardTiers + .filter( + oldReward => + // oldReward does not exist (exactly) in newRewards. + !newRewards.some(newReward => + tiersEqual({ tier1: oldReward, tier2: newReward }), + ), + ) + .map(reward => reward.id) + + setEditedRewardTierIds(editedIds) + } + + const setRewardTiers = (newRewards: NftRewardTier[]) => { + deriveAndSetEditedIds(newRewards) + _setRewardTiers(newRewards) + } + + // Load the redux state into the state variable + useEffect(() => { + _setRewardTiers(nftRewards.rewardTiers) + }, [nftRewards.rewardTiers]) + + return { + rewardTiers, + setRewardTiers, + marketplaceForm, + editedRewardTierIds, + loading, + } +} diff --git a/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useUpdateCurrentCollection.ts b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useUpdateCurrentCollection.ts new file mode 100644 index 0000000000..a834432668 --- /dev/null +++ b/src/packages/v4/views/V4ProjectSettings/EditNftsPage/hooks/useUpdateCurrentCollection.ts @@ -0,0 +1,91 @@ +import { useJBRulesetContext, useWriteJb721TiersHookAdjustTiers } from 'juice-sdk-react' +import { JB_721_TIER_PARAMS_V4, NftRewardTier } from 'models/nftRewards' +import { useCallback, useContext, useState } from 'react' +import { buildJB721TierParams, pinNftRewards } from 'utils/nftRewards' + +import { t } from '@lingui/macro' +import { waitForTransactionReceipt } from '@wagmi/core' +import { NEW_NFT_ID_LOWER_LIMIT } from 'components/NftRewards/RewardsList/AddEditRewardModal' +import { TxHistoryContext } from 'contexts/Transaction/TxHistoryContext' +import { JB721DelegateVersion } from 'models/JB721Delegate' +import { SUPPORTED_JB_MULTITERMINAL_ADDRESS } from 'packages/v4/hooks/useLaunchProjectTx' +import { wagmiConfig } from 'packages/v4/wagmiConfig' +import { emitErrorNotification } from 'utils/notifications' +import { useChainId } from 'wagmi' + +export function useUpdateCurrentCollection({ + rewardTiers, + editedRewardTierIds, + onConfirmed, +}: { + rewardTiers: NftRewardTier[] | undefined + editedRewardTierIds: number[] + onConfirmed?: VoidFunction +}) { + const { addTransaction } = useContext(TxHistoryContext) + const { rulesetMetadata: { data: rulesetMetadata }} = + useJBRulesetContext() + + const { writeContractAsync: writeAdjustTiers } = useWriteJb721TiersHookAdjustTiers() + const chainId = useChainId() + const chainIdStr = + chainId?.toString() as keyof typeof SUPPORTED_JB_MULTITERMINAL_ADDRESS + + const [txLoading, setTxLoading] = useState(false) + + const updateExistingCollection = useCallback(async () => { + if (!rewardTiers || !rulesetMetadata?.dataHook) { + emitErrorNotification(t`There are no NFT tiers to update.`) + return + } + + const newRewardTiers = rewardTiers.filter( + rewardTier => + rewardTier.id > NEW_NFT_ID_LOWER_LIMIT || // rewardTiers with id > NEW_NFT_ID_LOWER_LIMIT are new + editedRewardTierIds.includes(rewardTier.id), + ) + + // upload new rewardTiers and get their CIDs + const rewardTiersCIDs = await pinNftRewards(newRewardTiers) + + const tiersToAdd = buildJB721TierParams({ + cids: rewardTiersCIDs, + rewardTiers: newRewardTiers, + version: JB721DelegateVersion.JB721DELEGATE_V4 + }) as JB_721_TIER_PARAMS_V4[] + + if (!newRewardTiers) { + emitErrorNotification( + t`Your project's NFT contract version is not supported.`, + ) + return + } + try { + const hash = await writeAdjustTiers({ + args: [ + tiersToAdd, + editedRewardTierIds.map(id => BigInt(id)), + ], + address: rulesetMetadata.dataHook, + }) + + + addTransaction?.('Update NFT rewards', { hash }) + await waitForTransactionReceipt(wagmiConfig, { + hash, + }) + + setTxLoading(false) + onConfirmed?.() + } catch (e) { + setTxLoading(false) + + emitErrorNotification((e as unknown as Error).message) + } + }, [editedRewardTierIds, writeAdjustTiers, onConfirmed, rewardTiers, addTransaction]) + + return { + updateExistingCollection, + txLoading, + } +} diff --git a/src/packages/v4/views/V4ProjectSettings/ProjectSettingsContent.tsx b/src/packages/v4/views/V4ProjectSettings/ProjectSettingsContent.tsx index c9ff01032d..b70c023c82 100644 --- a/src/packages/v4/views/V4ProjectSettings/ProjectSettingsContent.tsx +++ b/src/packages/v4/views/V4ProjectSettings/ProjectSettingsContent.tsx @@ -1,17 +1,21 @@ -import { ChevronRightIcon } from '@heroicons/react/20/solid' -import { ArrowLeftIcon } from '@heroicons/react/24/outline' -import { Trans, t } from '@lingui/macro' import { Button, Layout } from 'antd' -import Link from 'next/link' -import { useMemo } from 'react' -import { twJoin } from 'tailwind-merge' +import { Trans, t } from '@lingui/macro' + import { ArchiveProjectSettingsPage } from './ArchiveProjectSettingsPage' +import { ArrowLeftIcon } from '@heroicons/react/24/outline' +import { ChevronRightIcon } from '@heroicons/react/20/solid' import { CreateErc20TokenSettingsPage } from './CreateErc20TokenSettingsPage' import { EditCyclePage } from './EditCyclePage/EditCyclePage' -import { useSettingsPagePath } from './hooks/useSettingsPagePath' +import { EditNftsPage } from './EditNftsPage/EditNftsPage' +import Link from 'next/link' import { ProjectDetailsSettingsPage } from './ProjectDetailsSettingsPage/ProjectDetailsSettingsPage' -import { SettingsPageKey } from './ProjectSettingsDashboard' import { ProjectSettingsLayout } from './ProjectSettingsLayout' +import { SettingsPageKey } from './ProjectSettingsDashboard' +import { isZeroAddress } from 'utils/address' +import { twJoin } from 'tailwind-merge' +import { useJBRulesetContext } from 'juice-sdk-react' +import { useMemo } from 'react' +import { useSettingsPagePath } from './hooks/useSettingsPagePath' const SettingsPageComponents: { [k in SettingsPageKey]: () => JSX.Element | null @@ -19,7 +23,7 @@ const SettingsPageComponents: { general: ProjectDetailsSettingsPage, // handle: () => null, //ProjectHandleSettingsPage, cycle: EditCyclePage, - // nfts: () => null, //EditNftsPage, + nfts: EditNftsPage, payouts: () => null, //PayoutsSettingsPage, // reservedtokens: () => null, //ReservedTokensSettingsPage, // transferownership: () => null, //TransferOwnershipSettingsPage, @@ -38,7 +42,7 @@ const V4SettingsPageKeyTitleMap = ( cycle: t`Cycle configuration`, payouts: t`Payouts`, // reservedtokens: t`Reserved token recipients`, - // nfts: hasExistingNfts ? t`Edit NFT collection` : t`Launch New NFT Collection`, + nfts: hasExistingNfts ? t`Edit NFT collection` : t`Launch New NFT Collection`, // transferownership: t`Transfer ownership`, archiveproject: t`Archive project`, // heldfees: t`Process held fees`, @@ -84,13 +88,15 @@ export function ProjectSettingsContent({ }: { settingsPageKey: SettingsPageKey }) { + const { rulesetMetadata } = useJBRulesetContext() + const ActiveSettingsPage = useMemo( () => SettingsPageComponents[settingsPageKey], [settingsPageKey], ) - // const hasExistingNfts = !isZeroAddress(fundingCycleMetadata?.dataSource) - const pageTitle = V4SettingsPageKeyTitleMap(false)[settingsPageKey] + const hasExistingNfts = !isZeroAddress(rulesetMetadata?.data?.dataHook) + const pageTitle = V4SettingsPageKeyTitleMap(hasExistingNfts)[settingsPageKey] return ( diff --git a/src/packages/v4/views/V4ProjectSettings/ProjectSettingsDashboard.tsx b/src/packages/v4/views/V4ProjectSettings/ProjectSettingsDashboard.tsx index 67382b8867..a87e42e946 100644 --- a/src/packages/v4/views/V4ProjectSettings/ProjectSettingsDashboard.tsx +++ b/src/packages/v4/views/V4ProjectSettings/ProjectSettingsDashboard.tsx @@ -1,22 +1,28 @@ -import { Trans } from '@lingui/macro' +import { + NativeTokenValue, + useJBContractContext, + useJBProjectMetadataContext, +} from 'juice-sdk-react' + import { Button } from 'antd' import EthereumAddress from 'components/EthereumAddress' -import Loading from 'components/Loading' -import { NativeTokenValue, useJBContractContext, useJBProjectMetadataContext } from 'juice-sdk-react' import Link from 'next/link' -import { useV4BalanceOfNativeTerminal } from 'packages/v4/hooks/useV4BalanceOfNativeTerminal' -import useProjectOwnerOf from 'packages/v4/hooks/useV4ProjectOwnerOf' -import { useV4WalletHasPermission } from 'packages/v4/hooks/useV4WalletHasPermission' -import { V4OperatorPermission } from 'packages/v4/models/v4Permissions' -import { useV4DistributableAmount } from '../V4ProjectDashboard/V4ProjectTabs/V4CyclesPayoutsPanel/hooks/useV4DistributableAmount' +import Loading from 'components/Loading' import { ProjectSettingsLayout } from './ProjectSettingsLayout' +import { Trans } from '@lingui/macro' +import { V4OperatorPermission } from 'packages/v4/models/v4Permissions' +import { useProjectHasErc20Token } from 'packages/v4/hooks/useProjectHasErc20Token' +import useProjectOwnerOf from 'packages/v4/hooks/useV4ProjectOwnerOf' import { useSettingsPagePath } from './hooks/useSettingsPagePath' +import { useV4BalanceOfNativeTerminal } from 'packages/v4/hooks/useV4BalanceOfNativeTerminal' +import { useV4DistributableAmount } from '../V4ProjectDashboard/V4ProjectTabs/V4CyclesPayoutsPanel/hooks/useV4DistributableAmount' +import { useV4WalletHasPermission } from 'packages/v4/hooks/useV4WalletHasPermission' export type SettingsPageKey = | 'general' // | 'handle' -> commenting out not necessary for v4 | 'cycle' - // | 'nfts' + | 'nfts' | 'payouts' // | 'reservedtokens' // | 'transferownership' @@ -58,7 +64,7 @@ export function ProjectSettingsDashboard() { const { metadata } = useJBProjectMetadataContext() const { distributableAmount } = useV4DistributableAmount() - const projectHasErc20Token = false // @v4TODO + const projectHasErc20Token = useProjectHasErc20Token() const hasIssueTicketsPermission = useV4WalletHasPermission( V4OperatorPermission.MINT_TOKENS, ) @@ -113,9 +119,7 @@ export function ProjectSettingsDashboard() {
{!loading ? ( - + ) : ( )} @@ -169,6 +173,18 @@ export function ProjectSettingsDashboard() { Edit next ruleset + NFTs & Rewards} + subtitle={Manage your project's NFTs and rewards} + > +
    +
  • + + NFTs + +
  • +
+
Tools} subtitle={Extended functionality for project owners} diff --git a/src/packages/v4/wagmiConfig.ts b/src/packages/v4/wagmiConfig.ts index 98f732ad02..58831225e0 100644 --- a/src/packages/v4/wagmiConfig.ts +++ b/src/packages/v4/wagmiConfig.ts @@ -13,13 +13,13 @@ export const wagmiConfig = createConfig({ `https://sepolia.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, ), [optimismSepolia.id]: http( - `https://optimism-sepolia.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, + 'https://sepolia.optimism.io' ), [baseSepolia.id]: http( `https://api.developer.coinbase.com/rpc/v1/base-sepolia/${process.env.NEXT_PUBLIC_BASE_ID}`, ), [arbitrumSepolia.id]: http( - `https://arbitrum-sepolia.infura.io/v3/${process.env.NEXT_PUBLIC_INFURA_ID}`, + `https://sepolia-rollup.arbitrum.io/rpc`, ), }, }) diff --git a/src/pages/api/juicebox/jb-721-delegate/[dataSourceAddress].ts b/src/pages/api/juicebox/jb-721-delegate/[dataSourceAddress].ts index 7fb4ede6b1..d36fe88dc8 100644 --- a/src/pages/api/juicebox/jb-721-delegate/[dataSourceAddress].ts +++ b/src/pages/api/juicebox/jb-721-delegate/[dataSourceAddress].ts @@ -1,15 +1,16 @@ +import { ForgeDeploy, addressFor } from 'forge-run-parser' +import { NextApiRequest, NextApiResponse } from 'next' +import { isEqualAddress, isZeroAddress } from 'utils/address' + import { readNetwork } from 'constants/networks' import { readProvider } from 'constants/readProvider' import { Contract } from 'ethers' -import { ForgeDeploy, addressFor } from 'forge-run-parser' import { enableCors } from 'lib/api/nextjs' import { getLogger } from 'lib/logger' -import { NextApiRequest, NextApiResponse } from 'next' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { IJB721TieredDelegate_V3_INTERFACE_ID } from 'packages/v2v3/constants/nftRewards' import { loadJB721DelegateJson } from 'packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateAbi' import { loadJB721DelegateAddress } from 'packages/v2v3/hooks/JB721Delegate/contracts/useJB721DelegateContractAddress' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' -import { isEqualAddress, isZeroAddress } from 'utils/address' import JBDelegatesRegistryJson from './IJBDelegatesRegistry.json' const logger = getLogger('api/juicebox/jb-721-delegate/[dataSourceAddress]') diff --git a/src/pages/v2/p/[projectId]/index.tsx b/src/pages/v2/p/[projectId]/index.tsx index df8cc37fbd..a56d222c7d 100644 --- a/src/pages/v2/p/[projectId]/index.tsx +++ b/src/pages/v2/p/[projectId]/index.tsx @@ -1,21 +1,17 @@ import { AppWrapper } from 'components/common/CoreAppWrapper/CoreAppWrapper' -import { SEO } from 'components/common/SEO/SEO' +import { V2V3ProjectSEO } from 'components/ProjectPageSEO' import { PV_V2 } from 'constants/pv' -import { SiteBaseUrl } from 'constants/url' import { AnnouncementsProvider } from 'contexts/Announcements/AnnouncementsProvider' import { paginateDepleteProjectsQueryCall } from 'lib/apollo/paginateDepleteProjectsQuery' import { loadCatalog } from 'locales/utils' -import { ProjectMetadata } from 'models/projectMetadata' import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next' import { ProjectDashboard } from 'packages/v2v3/components/V2V3Project/ProjectDashboard/ProjectDashboard' import { V2V3ProjectPageProvider } from 'packages/v2v3/contexts/V2V3ProjectPageProvider' import React, { PropsWithChildren } from 'react' -import { cidFromUrl, ipfsPublicGatewayUrl } from 'utils/ipfs' import { ProjectPageProps, getProjectStaticProps, } from 'utils/server/pages/props' -import { stripHtmlTags } from 'utils/string' export const getStaticPaths: GetStaticPaths = async () => { if (process.env.BUILD_CACHE_V2_PROJECTS === 'true') { @@ -58,43 +54,13 @@ export const getStaticProps: GetStaticProps< } } -const ProjectPageSEO = ({ - metadata, - projectId, -}: { - metadata?: ProjectMetadata - projectId: number -}) => ( - -) - export default function V2V3ProjectPage({ metadata, projectId, }: InferGetStaticPropsType) { return ( <> - + <_Wrapper> diff --git a/src/pages/v4/[chainName]/p/[projectId]/index.tsx b/src/pages/v4/[chainName]/p/[projectId]/index.tsx index 0bf163c12e..0c989266fd 100644 --- a/src/pages/v4/[chainName]/p/[projectId]/index.tsx +++ b/src/pages/v4/[chainName]/p/[projectId]/index.tsx @@ -1,21 +1,71 @@ -import { AppWrapper } from 'components/common/CoreAppWrapper/CoreAppWrapper' +import { V4ProjectSEO } from 'components/ProjectPageSEO' import { FEATURE_FLAGS } from 'constants/featureFlags' -import { OPEN_IPFS_GATEWAY_HOSTNAME } from 'constants/ipfs' -import { JBChainId, JBProjectProvider } from 'juice-sdk-react' -import { useRouter } from 'next/router' -import { ReduxProjectCartProvider } from 'packages/v4/components/ProjectDashboard/ReduxProjectCartProvider' -import store from 'packages/v4/components/ProjectDashboard/redux/store' -import V4ProjectMetadataProvider from 'packages/v4/contexts/V4ProjectMetadataProvider' -import { useCurrentRouteChainId } from 'packages/v4/hooks/useCurrentRouteChainId' -import { V4ProjectDashboard } from 'packages/v4/views/V4ProjectDashboard/V4ProjectDashboard' -import { wagmiConfig } from 'packages/v4/wagmiConfig' +import { PV_V4 } from 'constants/pv' +import { loadCatalog } from 'locales/utils' +import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next' +import dynamic from 'next/dynamic' import React, { PropsWithChildren } from 'react' -import { Provider } from 'react-redux' import { featureFlagEnabled } from 'utils/featureFlags' -import globalGetServerSideProps from 'utils/next-server/globalGetServerSideProps' -import { WagmiProvider } from 'wagmi' +import { + getProjectStaticProps, + ProjectPageProps, +} from 'utils/server/pages/props' -export const getServerSideProps = globalGetServerSideProps +const V4ProjectProviders = dynamic( + () => import('packages/v4/views/V4ProjectDashboard/V4ProjectProviders'), + { ssr: false }, +) +const V4ProjectDashboard = dynamic( + () => import('packages/v4/views/V4ProjectDashboard/V4ProjectDashboard'), + { ssr: false }, +) + +export const getStaticPaths: GetStaticPaths = async () => { + // TODO: static paths is convoluted with chains, needs some thought + // if (process.env.BUILD_CACHE_V4_PROJECTS === 'true') { + // const projects = await paginateDepleteProjectsQueryCall({ + // variables: { where: { pv: PV_V4 } }, + // }) + // const paths = projects.map(({ projectId }) => ({ + // params: { projectId: String(projectId) }, + // })) + // return { paths, fallback: true } + // } + + // TODO: We are switching to blocking as blocking fallback as its just not + // working. Need to investigate further + return { + paths: [], + fallback: 'blocking', + } +} + +export const getStaticProps: GetStaticProps< + ProjectPageProps & { i18n: unknown } +> = async context => { + const locale = context.locale as string + const messages = await loadCatalog(locale) + const i18n = { locale, messages } + + if (!context.params) throw new Error('params not supplied') + + const projectId = parseInt(context.params.projectId as string) + const chainName = context.params.chainName as string + const props = (await getProjectStaticProps( + projectId, + PV_V4, + chainName, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + )) as any + if (props?.props) { + props.props.i18n = i18n + } + + return { + ...props, + revalidate: 10, // 10 seconds https://nextjs.org/docs/api-reference/data-fetching/get-static-props#revalidate + } +} // This is a hack to avoid SSR for now. At the moment when this is not applied to this page, you will see a rehydration error. const _Wrapper: React.FC = ({ children }) => { @@ -39,43 +89,27 @@ const _Wrapper: React.FC = ({ children }) => { return <>{children} } -export default function V4ProjectPage() { - const router = useRouter() - const { projectId } = router.query - const chainId = useCurrentRouteChainId() - if (!chainId || !projectId) { +export default function V4ProjectPage({ + metadata, + projectId, + chainName, +}: InferGetStaticPropsType) { + if (!chainName || !projectId) { return
Invalid URL
} return ( - <_Wrapper> - - - - - ) -} - -const Providers: React.FC< - PropsWithChildren & { chainId: JBChainId; projectId: bigint } -> = ({ chainId, projectId, children }) => { - return ( - - - - - - {children} - - - - - + <> + + <_Wrapper> + + + + + ) } diff --git a/src/redux/hooks/useAppSelector.ts b/src/redux/hooks/useAppSelector.ts index 6565559f72..8ea48775be 100644 --- a/src/redux/hooks/useAppSelector.ts +++ b/src/redux/hooks/useAppSelector.ts @@ -1,74 +1,4 @@ -import { deserializeV1FundingCycle } from 'packages/v1/utils/serializers' -import { - deserializeFundAccessConstraint, - deserializeV2V3FundingCycleData, - deserializeV2V3FundingCycleMetadata, -} from 'packages/v2v3/utils/serializers' -import { useMemo } from 'react' -import { shallowEqual, TypedUseSelectorHook, useSelector } from 'react-redux' +import { TypedUseSelectorHook, useSelector } from 'react-redux' import { RootState } from 'redux/store' export const useAppSelector: TypedUseSelectorHook = useSelector - -export const useEditingV1FundingCycleSelector = () => { - const serializedFundingCycle = useAppSelector( - state => state.editingProject.fundingCycle, - shallowEqual, - ) - - const fc = useMemo( - () => deserializeV1FundingCycle(serializedFundingCycle), - [serializedFundingCycle], - ) - - return fc -} - -export const useEditingV2V3FundingCycleMetadataSelector = () => { - const serializedFundingCycleMetadata = useAppSelector( - state => state.editingV2Project.fundingCycleMetadata, - shallowEqual, - ) - - const fundingCycleMetadata = useMemo( - () => deserializeV2V3FundingCycleMetadata(serializedFundingCycleMetadata), - [serializedFundingCycleMetadata], - ) - - // force useDataSourceForPay to false, for safety. - // https://github.com/jbx-protocol/juice-interface/issues/1473 - fundingCycleMetadata.useDataSourceForPay = false - - return fundingCycleMetadata -} - -export const useEditingV2V3FundingCycleDataSelector = () => { - const serializedFundingCycleData = useAppSelector( - state => state.editingV2Project.fundingCycleData, - shallowEqual, - ) - - const fundingCycleData = useMemo( - () => deserializeV2V3FundingCycleData(serializedFundingCycleData), - [serializedFundingCycleData], - ) - - return fundingCycleData -} - -export const useEditingV2V3FundAccessConstraintsSelector = () => { - const serializedFundAccessConstraints = useAppSelector( - state => state.editingV2Project.fundAccessConstraints, - shallowEqual, - ) - - const fundAccessConstraints = useMemo( - () => - serializedFundAccessConstraints.map(d => - deserializeFundAccessConstraint(d), - ), - [serializedFundAccessConstraints], - ) - - return fundAccessConstraints -} diff --git a/src/redux/hooks/useEditingCreateFurthestPageReached.ts b/src/redux/hooks/useEditingCreateFurthestPageReached.ts index d731b95792..82f118e487 100644 --- a/src/redux/hooks/useEditingCreateFurthestPageReached.ts +++ b/src/redux/hooks/useEditingCreateFurthestPageReached.ts @@ -2,7 +2,7 @@ import { CreatePage } from 'models/createPage' import { useCallback, useEffect } from 'react' import { useDispatch } from 'react-redux' import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' const pageOrder: CreatePage[] = [ 'projectDetails', @@ -17,7 +17,7 @@ const pageOrder: CreatePage[] = [ export const useEditingCreateFurthestPageReached = () => { const dispatch = useDispatch() const furthestPageReached = useAppSelector( - state => state.editingV2Project.createFurthestPageReached, + state => state.creatingV2Project.createFurthestPageReached, ) const setFurthestPageReached = useCallback( @@ -25,13 +25,15 @@ export const useEditingCreateFurthestPageReached = () => { const currentPageIndex = pageOrder.indexOf(furthestPageReached) const newPageIndex = pageOrder.indexOf(page) if (newPageIndex > currentPageIndex) { - dispatch(editingV2ProjectActions.setCreateFurthestPageReached(page)) + dispatch(creatingV2ProjectActions.setCreateFurthestPageReached(page)) } }, [dispatch, furthestPageReached], ) const resetFurthestPageReached = useCallback(() => { - dispatch(editingV2ProjectActions.setCreateFurthestPageReached(pageOrder[0])) + dispatch( + creatingV2ProjectActions.setCreateFurthestPageReached(pageOrder[0]), + ) }, [dispatch]) return { diff --git a/src/redux/hooks/useEditingDistributionLimit.ts b/src/redux/hooks/useEditingDistributionLimit.ts deleted file mode 100644 index 8d707517c9..0000000000 --- a/src/redux/hooks/useEditingDistributionLimit.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { AddressZero } from '@ethersproject/constants' -import { ETH_TOKEN_ADDRESS } from 'constants/juiceboxTokens' -import { BigNumber } from 'ethers' -import { useDefaultJBETHPaymentTerminal } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBETHPaymentTerminal' -import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' -import { V2V3_CURRENCY_ETH } from 'packages/v2v3/utils/currency' -import { MAX_DISTRIBUTION_LIMIT } from 'packages/v2v3/utils/math' -import { useCallback, useMemo } from 'react' -import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' -import { fromWad, parseWad } from 'utils/format/formatNumber' - -export interface ReduxDistributionLimit { - amount: BigNumber - currency: V2V3CurrencyOption -} - -/** - * Hook for accessing and setting the redux editing v2 distribution limit value - * in fundingAccessConstraint. - * @returns - */ -export const useEditingDistributionLimit = (): [ - ReduxDistributionLimit | undefined, - (input: ReduxDistributionLimit | undefined) => void, - (amount: BigNumber) => void, - (currency: V2V3CurrencyOption) => void, -] => { - const defaultJBETHPaymentTerminal = useDefaultJBETHPaymentTerminal() - const dispatch = useAppDispatch() - const fundAccessConstraints = useAppSelector( - state => state.editingV2Project.fundAccessConstraints, - ) - - const distributionLimit: ReduxDistributionLimit | undefined = useMemo(() => { - if ( - !fundAccessConstraints.length || - !fundAccessConstraints?.[0].distributionLimit?.length - ) { - return undefined - } - const distributionLimit = parseWad( - fundAccessConstraints[0].distributionLimit, - ) - const distributionLimitCurrency = (parseInt( - fundAccessConstraints[0].distributionLimitCurrency, - ) ?? V2V3_CURRENCY_ETH) as V2V3CurrencyOption - - return { amount: distributionLimit, currency: distributionLimitCurrency } - }, [fundAccessConstraints]) - - const setDistributionLimit = useCallback( - (input: ReduxDistributionLimit | undefined) => { - if (!input) { - dispatch(editingV2ProjectActions.setFundAccessConstraints([])) - return - } - const distributionLimitCurrency = input.currency.toString() - dispatch( - editingV2ProjectActions.setFundAccessConstraints([ - { - terminal: defaultJBETHPaymentTerminal?.address ?? AddressZero, - token: ETH_TOKEN_ADDRESS, - distributionLimit: fromWad(input.amount), - distributionLimitCurrency, - overflowAllowance: '0', - overflowAllowanceCurrency: '0', - }, - ]), - ) - }, - [defaultJBETHPaymentTerminal, dispatch], - ) - - const setDistributionLimitAmount = useCallback( - (input: BigNumber) => { - const currentFundAccessConstraint = fundAccessConstraints?.[0] ?? { - terminal: defaultJBETHPaymentTerminal?.address ?? AddressZero, - token: ETH_TOKEN_ADDRESS, - distributionLimitCurrency: V2V3_CURRENCY_ETH.toString(), - overflowAllowance: '0', - overflowAllowanceCurrency: '0', - } - dispatch( - editingV2ProjectActions.setFundAccessConstraints([ - { - ...currentFundAccessConstraint, - distributionLimit: fromWad( - input === undefined ? MAX_DISTRIBUTION_LIMIT : input, - ), - }, - ]), - ) - }, - [defaultJBETHPaymentTerminal, dispatch, fundAccessConstraints], - ) - - const setDistributionLimitCurrency = useCallback( - (input: V2V3CurrencyOption) => { - dispatch( - editingV2ProjectActions.setDistributionLimitCurrency(input.toString()), - ) - }, - [dispatch], - ) - - return [ - distributionLimit, - setDistributionLimit, - setDistributionLimitAmount, - setDistributionLimitCurrency, - ] -} diff --git a/src/redux/hooks/useEditingPayoutSplits.ts b/src/redux/hooks/useEditingPayoutSplits.ts deleted file mode 100644 index 67efa9dfdd..0000000000 --- a/src/redux/hooks/useEditingPayoutSplits.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Split } from 'packages/v2v3/models/splits' -import { useCallback } from 'react' -import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' - -/** - * Hook for accessing and setting the redux editing v2 payout splits value. - */ -export const useEditingPayoutSplits = (): [ - Split[], - (input: Split[]) => void, -] => { - const dispatch = useAppDispatch() - const { splits } = useAppSelector( - state => state.editingV2Project.payoutGroupedSplits, - ) - - const setSplits = useCallback( - (input: Split[]) => { - if (!input || !input.length) { - dispatch(editingV2ProjectActions.setPayoutSplits([])) - return - } - dispatch(editingV2ProjectActions.setPayoutSplits(input)) - }, - [dispatch], - ) - - return [splits, setSplits] -} diff --git a/src/redux/hooks/useEditingReservedTokensSplits.ts b/src/redux/hooks/useEditingReservedTokensSplits.ts deleted file mode 100644 index 7899e7d899..0000000000 --- a/src/redux/hooks/useEditingReservedTokensSplits.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Split } from 'packages/v2v3/models/splits' -import { useCallback } from 'react' -import { useAppDispatch } from 'redux/hooks/useAppDispatch' -import { useAppSelector } from 'redux/hooks/useAppSelector' -import { editingV2ProjectActions } from 'redux/slices/editingV2Project' - -/** - * Hook for accessing and setting the redux editing v2 reserved token splits value. - */ -export const useEditingReservedTokensSplits = (): [ - Split[], - (input: Split[]) => void, -] => { - const dispatch = useAppDispatch() - const { splits } = useAppSelector( - state => state.editingV2Project.reservedTokensGroupedSplits, - ) - - const setSplits = useCallback( - (input: Split[]) => { - if (!input || !input.length) { - dispatch(editingV2ProjectActions.setReservedTokensSplits([])) - return - } - dispatch(editingV2ProjectActions.setReservedTokensSplits(input)) - }, - [dispatch], - ) - - return [splits, setSplits] -} diff --git a/src/redux/hooks/v1/index.ts b/src/redux/hooks/v1/index.ts new file mode 100644 index 0000000000..576a734ede --- /dev/null +++ b/src/redux/hooks/v1/index.ts @@ -0,0 +1,18 @@ +import { deserializeV1FundingCycle } from 'packages/v1/utils/serializers' +import { useMemo } from 'react' +import { shallowEqual } from 'react-redux' +import { useAppSelector } from '../useAppSelector' + +export const useEditingV1FundingCycleSelector = () => { + const serializedFundingCycle = useAppSelector( + state => state.editingProject.fundingCycle, + shallowEqual, + ) + + const fc = useMemo( + () => deserializeV1FundingCycle(serializedFundingCycle), + [serializedFundingCycle], + ) + + return fc +} diff --git a/src/redux/hooks/v2v3/create.ts b/src/redux/hooks/v2v3/create.ts new file mode 100644 index 0000000000..f4dcd7f5de --- /dev/null +++ b/src/redux/hooks/v2v3/create.ts @@ -0,0 +1,218 @@ +import { AddressZero } from '@ethersproject/constants' +import { ETH_TOKEN_ADDRESS } from 'constants/juiceboxTokens' +import { BigNumber } from 'ethers' +import { useDefaultJBETHPaymentTerminal } from 'packages/v2v3/hooks/defaultContracts/useDefaultJBETHPaymentTerminal' +import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' +import { Split } from 'packages/v2v3/models/splits' +import { V2V3_CURRENCY_ETH } from 'packages/v2v3/utils/currency' +import { MAX_DISTRIBUTION_LIMIT } from 'packages/v2v3/utils/math' +import { + deserializeFundAccessConstraint, + deserializeV2V3FundingCycleData, + deserializeV2V3FundingCycleMetadata, +} from 'packages/v2v3/utils/serializers' +import { useCallback, useMemo } from 'react' +import { shallowEqual } from 'react-redux' +import { useAppDispatch } from 'redux/hooks/useAppDispatch' +import { creatingV2ProjectActions } from 'redux/slices/creatingV2Project' +import { fromWad, parseWad } from 'utils/format/formatNumber' +import { useAppSelector } from '../useAppSelector' +import { ReduxDistributionLimit } from './shared' + +export const useCreatingV2V3FundingCycleMetadataSelector = () => { + const serializedFundingCycleMetadata = useAppSelector( + state => state.creatingV2Project.fundingCycleMetadata, + shallowEqual, + ) + + const fundingCycleMetadata = useMemo( + () => deserializeV2V3FundingCycleMetadata(serializedFundingCycleMetadata), + [serializedFundingCycleMetadata], + ) + + // force useDataSourceForPay to false, for safety. + // https://github.com/jbx-protocol/juice-interface/issues/1473 + fundingCycleMetadata.useDataSourceForPay = false + + return fundingCycleMetadata +} + +export const useCreatingV2V3FundingCycleDataSelector = () => { + const serializedFundingCycleData = useAppSelector( + state => state.creatingV2Project.fundingCycleData, + shallowEqual, + ) + + const fundingCycleData = useMemo( + () => deserializeV2V3FundingCycleData(serializedFundingCycleData), + [serializedFundingCycleData], + ) + + return fundingCycleData +} + +export const useCreatingV2V3FundAccessConstraintsSelector = () => { + const serializedFundAccessConstraints = useAppSelector( + state => state.creatingV2Project.fundAccessConstraints, + shallowEqual, + ) + + const fundAccessConstraints = useMemo( + () => + serializedFundAccessConstraints.map(d => + deserializeFundAccessConstraint(d), + ), + [serializedFundAccessConstraints], + ) + + return fundAccessConstraints +} + +/** + * Hook for accessing and setting the redux creating v2 distribution limit value + * in fundingAccessConstraint. + * @returns + */ +export const useCreatingDistributionLimit = (): [ + ReduxDistributionLimit | undefined, + (input: ReduxDistributionLimit | undefined) => void, + (amount: BigNumber) => void, + (currency: V2V3CurrencyOption) => void, +] => { + const defaultJBETHPaymentTerminal = useDefaultJBETHPaymentTerminal() + const dispatch = useAppDispatch() + const fundAccessConstraints = useAppSelector( + state => state.creatingV2Project.fundAccessConstraints, + ) + + const distributionLimit: ReduxDistributionLimit | undefined = useMemo(() => { + if ( + !fundAccessConstraints.length || + !fundAccessConstraints?.[0].distributionLimit?.length + ) { + return undefined + } + const distributionLimit = parseWad( + fundAccessConstraints[0].distributionLimit, + ) + const distributionLimitCurrency = (parseInt( + fundAccessConstraints[0].distributionLimitCurrency, + ) ?? V2V3_CURRENCY_ETH) as V2V3CurrencyOption + + return { amount: distributionLimit, currency: distributionLimitCurrency } + }, [fundAccessConstraints]) + + const setDistributionLimit = useCallback( + (input: ReduxDistributionLimit | undefined) => { + if (!input) { + dispatch(creatingV2ProjectActions.setFundAccessConstraints([])) + return + } + const distributionLimitCurrency = input.currency.toString() + dispatch( + creatingV2ProjectActions.setFundAccessConstraints([ + { + terminal: defaultJBETHPaymentTerminal?.address ?? AddressZero, + token: ETH_TOKEN_ADDRESS, + distributionLimit: fromWad(input.amount), + distributionLimitCurrency, + overflowAllowance: '0', + overflowAllowanceCurrency: '0', + }, + ]), + ) + }, + [defaultJBETHPaymentTerminal, dispatch], + ) + + const setDistributionLimitAmount = useCallback( + (input: BigNumber) => { + const currentFundAccessConstraint = fundAccessConstraints?.[0] ?? { + terminal: defaultJBETHPaymentTerminal?.address ?? AddressZero, + token: ETH_TOKEN_ADDRESS, + distributionLimitCurrency: V2V3_CURRENCY_ETH.toString(), + overflowAllowance: '0', + overflowAllowanceCurrency: '0', + } + dispatch( + creatingV2ProjectActions.setFundAccessConstraints([ + { + ...currentFundAccessConstraint, + distributionLimit: fromWad( + input === undefined ? MAX_DISTRIBUTION_LIMIT : input, + ), + }, + ]), + ) + }, + [defaultJBETHPaymentTerminal, dispatch, fundAccessConstraints], + ) + + const setDistributionLimitCurrency = useCallback( + (input: V2V3CurrencyOption) => { + dispatch( + creatingV2ProjectActions.setDistributionLimitCurrency(input.toString()), + ) + }, + [dispatch], + ) + + return [ + distributionLimit, + setDistributionLimit, + setDistributionLimitAmount, + setDistributionLimitCurrency, + ] +} + +/** + * Hook for accessing and setting the redux creating v2 payout splits value. + */ +export const useCreatingPayoutSplits = (): [ + Split[], + (input: Split[]) => void, +] => { + const dispatch = useAppDispatch() + const { splits } = useAppSelector( + state => state.creatingV2Project.payoutGroupedSplits, + ) + + const setSplits = useCallback( + (input: Split[]) => { + if (!input || !input.length) { + dispatch(creatingV2ProjectActions.setPayoutSplits([])) + return + } + dispatch(creatingV2ProjectActions.setPayoutSplits(input)) + }, + [dispatch], + ) + + return [splits, setSplits] +} + +/** + * Hook for accessing and setting the redux creating v2 reserved token splits value. + */ +export const useCreatingReservedTokensSplits = (): [ + Split[], + (input: Split[]) => void, +] => { + const dispatch = useAppDispatch() + const { splits } = useAppSelector( + state => state.creatingV2Project.reservedTokensGroupedSplits, + ) + + const setSplits = useCallback( + (input: Split[]) => { + if (!input || !input.length) { + dispatch(creatingV2ProjectActions.setReservedTokensSplits([])) + return + } + dispatch(creatingV2ProjectActions.setReservedTokensSplits(input)) + }, + [dispatch], + ) + + return [splits, setSplits] +} diff --git a/src/redux/hooks/v2v3/edit.ts b/src/redux/hooks/v2v3/edit.ts new file mode 100644 index 0000000000..3e5af7f694 --- /dev/null +++ b/src/redux/hooks/v2v3/edit.ts @@ -0,0 +1,57 @@ +import { + deserializeFundAccessConstraint, + deserializeV2V3FundingCycleData, + deserializeV2V3FundingCycleMetadata, +} from 'packages/v2v3/utils/serializers' +import { useMemo } from 'react' +import { shallowEqual } from 'react-redux' +import { useAppSelector } from 'redux/hooks/useAppSelector' + +export const useEditingV2V3FundingCycleMetadataSelector = () => { + const serializedFundingCycleMetadata = useAppSelector( + state => state.editingV2Project.fundingCycleMetadata, + shallowEqual, + ) + + const fundingCycleMetadata = useMemo( + () => deserializeV2V3FundingCycleMetadata(serializedFundingCycleMetadata), + [serializedFundingCycleMetadata], + ) + + // force useDataSourceForPay to false, for safety. + // https://github.com/jbx-protocol/juice-interface/issues/1473 + fundingCycleMetadata.useDataSourceForPay = false + + return fundingCycleMetadata +} + +export const useEditingV2V3FundingCycleDataSelector = () => { + const serializedFundingCycleData = useAppSelector( + state => state.editingV2Project.fundingCycleData, + shallowEqual, + ) + + const fundingCycleData = useMemo( + () => deserializeV2V3FundingCycleData(serializedFundingCycleData), + [serializedFundingCycleData], + ) + + return fundingCycleData +} + +export const useEditingV2V3FundAccessConstraintsSelector = () => { + const serializedFundAccessConstraints = useAppSelector( + state => state.editingV2Project.fundAccessConstraints, + shallowEqual, + ) + + const fundAccessConstraints = useMemo( + () => + serializedFundAccessConstraints.map(d => + deserializeFundAccessConstraint(d), + ), + [serializedFundAccessConstraints], + ) + + return fundAccessConstraints +} diff --git a/src/redux/hooks/v2v3/shared/index.ts b/src/redux/hooks/v2v3/shared/index.ts new file mode 100644 index 0000000000..c9f6f047dc --- /dev/null +++ b/src/redux/hooks/v2v3/shared/index.ts @@ -0,0 +1 @@ +export * from './types' diff --git a/src/redux/hooks/v2v3/shared/types.ts b/src/redux/hooks/v2v3/shared/types.ts new file mode 100644 index 0000000000..92b236c323 --- /dev/null +++ b/src/redux/hooks/v2v3/shared/types.ts @@ -0,0 +1,7 @@ +import { BigNumber } from 'ethers/lib/ethers' +import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' + +export interface ReduxDistributionLimit { + amount: BigNumber + currency: V2V3CurrencyOption +} diff --git a/src/redux/localStoragePreload.ts b/src/redux/localStoragePreload.ts index 287651b1f3..d3e02e815e 100644 --- a/src/redux/localStoragePreload.ts +++ b/src/redux/localStoragePreload.ts @@ -2,8 +2,8 @@ import { defaultProjectState as defaultV1ProjectState, REDUX_STORE_V1_PROJECT_VERSION, } from './slices/editingProject' -import { INITIAL_REDUX_STATE as defaultV2ProjectState } from './slices/editingV2Project' -import { REDUX_STORE_V2_PROJECT_VERSION } from './slices/editingV2Project/version' +import { INITIAL_REDUX_STATE as defaultV2ProjectState } from './slices/shared/v2ProjectInitialReduxState' +import { REDUX_STORE_V2_PROJECT_VERSION } from './slices/shared/v2ProjectVersion' import { RootState } from './store' interface PreloadedState { @@ -35,6 +35,23 @@ export function getLocalStoragePreloadedState( } } + // If theres a version mismatch, reset the creatingV2Project state + if ( + parsedState?.reduxState?.creatingV2Project?.version !== + REDUX_STORE_V2_PROJECT_VERSION + ) { + console.info( + 'redux::creatingV2Project::default redux state changed, resetting creatingV2Project state.', + ) + parsedState = { + ...parsedState, + reduxState: { + ...parsedState.reduxState, + creatingV2Project: defaultV2ProjectState, + }, + } + } + // if theres a version mismatch, reset the editingV2Project state if ( parsedState?.reduxState?.editingV2Project?.version !== diff --git a/src/redux/slices/creatingV2Project/creatingV2Project.ts b/src/redux/slices/creatingV2Project/creatingV2Project.ts new file mode 100644 index 0000000000..e01caea4e8 --- /dev/null +++ b/src/redux/slices/creatingV2Project/creatingV2Project.ts @@ -0,0 +1,325 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { CreatePage } from 'models/createPage' +import { NftPostPayModalConfig } from 'models/nftPostPayModal' +import { + JB721GovernanceType, + NftCollectionMetadata, + NftRewardTier, +} from 'models/nftRewards' +import { PayoutsSelection } from 'models/payoutsSelection' +import { ProjectTagName } from 'models/project-tags' +import { ProjectTokensSelection } from 'models/projectTokenSelection' +import { ReconfigurationStrategy } from 'models/reconfigurationStrategy' +import { TreasurySelection } from 'models/treasurySelection' +import { AmountInputValue } from 'packages/v2v3/components/Create/components/pages/ProjectDetails/ProjectDetailsPage' +import { projectTokenSettingsToReduxFormat } from 'packages/v2v3/components/Create/utils/projectTokenSettingsToReduxFormat' +import { AllocationSplit } from 'packages/v2v3/components/shared/Allocation/Allocation' +import { Split } from 'packages/v2v3/models/splits' +import { + SerializedV2V3FundAccessConstraint, + SerializedV2V3FundingCycleData, + SerializedV2V3FundingCycleMetadata, +} from 'packages/v2v3/utils/serializers' +import { + EMPTY_PAYOUT_GROUPED_SPLITS, + EMPTY_RESERVED_TOKENS_GROUPED_SPLITS, +} from '../shared/v2ProjectDefaultState' +import { INITIAL_REDUX_STATE } from '../shared/v2ProjectInitialReduxState' +import { NftRewardsData, ReduxState } from '../shared/v2ProjectTypes' + +const creatingV2ProjectSlice = createSlice({ + name: 'creatingV2Project', + initialState: INITIAL_REDUX_STATE, + reducers: { + setState: (_, action: PayloadAction) => { + return action.payload + }, + resetState: () => INITIAL_REDUX_STATE, + setName: (state, action: PayloadAction) => { + state.projectMetadata.name = action.payload + }, + setProjectTagline: (state, action: PayloadAction) => { + state.projectMetadata.projectTagline = action.payload + }, + setRequiredOFACCheck: ( + state, + action: PayloadAction, + ) => { + state.projectMetadata.projectRequiredOFACCheck = action.payload + }, + setInfoUri: (state, action: PayloadAction) => { + state.projectMetadata.infoUri = action.payload + }, + setLogoUri: (state, action: PayloadAction) => { + state.projectMetadata.logoUri = action.payload + }, + setCoverImageUri: (state, action: PayloadAction) => { + state.projectMetadata.coverImageUri = action.payload + }, + setTwitter: (state, action: PayloadAction) => { + state.projectMetadata.twitter = action.payload + }, + setDiscord: (state, action: PayloadAction) => { + state.projectMetadata.discord = action.payload + }, + setTelegram: (state, action: PayloadAction) => { + state.projectMetadata.telegram = action.payload + }, + setPayButton: (state, action: PayloadAction) => { + state.projectMetadata.payButton = action.payload + }, + setPayDisclosure: (state, action: PayloadAction) => { + state.projectMetadata.payDisclosure = action.payload + }, + setDescription: (state, action: PayloadAction) => { + state.projectMetadata.description = action.payload + }, + setTags: (state, action: PayloadAction) => { + state.projectMetadata.tags = action.payload + }, + setFundingCycleData: ( + state, + action: PayloadAction, + ) => { + state.fundingCycleData = action.payload + }, + setFundingCycleMetadata: ( + state, + action: PayloadAction, + ) => { + state.fundingCycleMetadata = action.payload + }, + setDuration: (state, action: PayloadAction) => { + state.fundingCycleData.duration = action.payload + }, + setDiscountRate: (state, action: PayloadAction) => { + state.fundingCycleData.discountRate = action.payload + }, + setReservedRate: (state, action: PayloadAction) => { + state.fundingCycleMetadata.reservedRate = action.payload + }, + setRedemptionRate: (state, action: PayloadAction) => { + state.fundingCycleMetadata.redemptionRate = action.payload + }, + setBallotRedemptionRate: (state, action: PayloadAction) => { + state.fundingCycleMetadata.ballotRedemptionRate = action.payload + }, + setWeight: (state, action: PayloadAction) => { + state.fundingCycleData.weight = action.payload + }, + setFundAccessConstraints: ( + state, + action: PayloadAction, + ) => { + state.fundAccessConstraints = action.payload + }, + setDistributionLimit: (state, action: PayloadAction) => { + if (state.fundAccessConstraints.length) { + state.fundAccessConstraints[0].distributionLimit = action.payload + } + }, + setDistributionLimitCurrency: (state, action: PayloadAction) => { + if (state.fundAccessConstraints.length) { + state.fundAccessConstraints[0].distributionLimitCurrency = + action.payload + } + }, + setTreasurySelection: ( + state, + action: PayloadAction, + ) => { + state.treasurySelection = action.payload + }, + setFundingTargetSelection: ( + state, + action: PayloadAction<'specific' | 'infinite' | undefined>, + ) => { + state.fundingTargetSelection = action.payload + }, + setPayoutSplits: (state, action: PayloadAction) => { + state.payoutGroupedSplits = { + ...EMPTY_PAYOUT_GROUPED_SPLITS, + splits: action.payload, + } + }, + setPayoutsSelection: ( + state, + action: PayloadAction, + ) => { + state.payoutsSelection = action.payload + }, + setReservedTokensSplits: (state, action: PayloadAction) => { + state.reservedTokensGroupedSplits = { + ...EMPTY_RESERVED_TOKENS_GROUPED_SPLITS, + splits: action.payload, + } + }, + setProjectTokensSelection: ( + state, + action: PayloadAction, + ) => { + state.projectTokensSelection = action.payload + }, + setPausePay: (state, action: PayloadAction) => { + state.fundingCycleMetadata.pausePay = action.payload + }, + setHoldFees: (state, action: PayloadAction) => { + state.fundingCycleMetadata.holdFees = action.payload + }, + setAllowMinting: (state, action: PayloadAction) => { + state.fundingCycleMetadata.allowMinting = action.payload + }, + setBallot: (state, action: PayloadAction) => { + state.fundingCycleData.ballot = action.payload + }, + setNftRewards: (state, action: PayloadAction) => { + state.nftRewards = action.payload + }, + setNftRewardTiers: (state, action: PayloadAction) => { + state.nftRewards.rewardTiers = action.payload + }, + setNftRewardsCIDs: (state, action: PayloadAction) => { + state.nftRewards.CIDs = action.payload + }, + setNftRewardsCollectionMetadata: ( + state, + action: PayloadAction, + ) => { + state.nftRewards.collectionMetadata = action.payload + }, + setNftRewardsCollectionMetadataUri: ( + state, + action: PayloadAction, + ) => { + state.nftRewards.collectionMetadata.uri = action.payload + }, + setNftRewardsSymbol: (state, action: PayloadAction) => { + state.nftRewards.collectionMetadata.symbol = action.payload + }, + setNftRewardsCollectionDescription: ( + state, + action: PayloadAction, + ) => { + state.nftRewards.collectionMetadata.description = action.payload + }, + setNftRewardsGovernance: ( + state, + action: PayloadAction, + ) => { + state.nftRewards.governanceType = action.payload + }, + setNftPostPayModalConfig: ( + state, + action: PayloadAction, + ) => { + state.nftRewards.postPayModal = action.payload + }, + setNftRewardsName: (state, action: PayloadAction) => { + state.nftRewards.collectionMetadata.name = action.payload + }, + setNftPreventOverspending: (state, action: PayloadAction) => { + state.nftRewards.flags.preventOverspending = action.payload + }, + setAllowSetTerminals: (state, action: PayloadAction) => { + state.fundingCycleMetadata.global.allowSetTerminals = action.payload + }, + setAllowSetController: (state, action: PayloadAction) => { + state.fundingCycleMetadata.global.allowSetController = action.payload + }, + setAllowControllerMigration: (state, action: PayloadAction) => { + state.fundingCycleMetadata.allowControllerMigration = action.payload + }, + setAllowTerminalMigration: (state, action: PayloadAction) => { + state.fundingCycleMetadata.allowTerminalMigration = action.payload + }, + setPauseTransfers: (state, action: PayloadAction) => { + state.fundingCycleMetadata.global.pauseTransfers = action.payload + }, + setFundingCyclesPageSelection: ( + state, + action: PayloadAction<'manual' | 'automated' | undefined>, + ) => { + state.fundingCyclesPageSelection = action.payload + }, + setReconfigurationRuleSelection: ( + state, + action: PayloadAction, + ) => { + state.reconfigurationRuleSelection = action.payload + }, + setCreateFurthestPageReached: ( + state, + action: PayloadAction, + ) => { + state.createFurthestPageReached = action.payload + }, + setInputProjectOwner: ( + state, + action: PayloadAction, + ) => { + state.inputProjectOwner = action.payload + }, + setMustStartAtOrAfter: (state, action: PayloadAction) => { + state.mustStartAtOrAfter = action.payload + }, + addCreateSoftLockedPage: (state, action: PayloadAction) => { + const set = new Set(state.createSoftLockPageQueue) + set.add(action.payload) + state.createSoftLockPageQueue = [...set] + }, + removeCreateSoftLockedPage: (state, action: PayloadAction) => { + if (!state.createSoftLockPageQueue) return + if (state.createSoftLockPageQueue.includes(action.payload)) { + state.createSoftLockPageQueue.splice( + state.createSoftLockPageQueue.indexOf(action.payload), + 1, + ) + } + }, + setUseDataSourceForRedeem: (state, action: PayloadAction) => { + state.fundingCycleMetadata.useDataSourceForRedeem = action.payload + }, + setTokenSettings: ( + state, + action: PayloadAction<{ + initialMintRate: string + reservedTokensPercentage: number + reservedTokenAllocation: AllocationSplit[] + discountRate: number + redemptionRate: number + tokenMinting: boolean + pauseTransfers: boolean + }>, + ) => { + const converted = projectTokenSettingsToReduxFormat(action.payload) + + state.fundingCycleData.weight = converted.weight + state.fundingCycleMetadata.reservedRate = converted.reservedRate + state.reservedTokensGroupedSplits = converted.reservedTokensGroupedSplits + state.fundingCycleData.discountRate = converted.discountRate + state.fundingCycleMetadata.redemptionRate = converted.redemptionRate + state.fundingCycleMetadata.allowMinting = converted.allowMinting + }, + setIntroVideoUrl: (state, action: PayloadAction) => { + state.projectMetadata.introVideoUrl = action.payload + }, + setIntroImageUri: (state, action: PayloadAction) => { + state.projectMetadata.introImageUri = action.payload + }, + setSoftTarget: (state, action: PayloadAction) => { + state.projectMetadata.softTargetAmount = action.payload.amount + state.projectMetadata.softTargetCurrency = + action.payload.currency.toString() + }, + setSoftTargetAmount: (state, action: PayloadAction) => { + state.projectMetadata.softTargetAmount = action.payload + }, + setSoftTargetCurrency: (state, action: PayloadAction) => { + state.projectMetadata.softTargetCurrency = action.payload + }, + }, +}) + +export const creatingV2ProjectActions = creatingV2ProjectSlice.actions + +export default creatingV2ProjectSlice.reducer diff --git a/src/redux/slices/creatingV2Project/index.ts b/src/redux/slices/creatingV2Project/index.ts new file mode 100644 index 0000000000..6cd530683b --- /dev/null +++ b/src/redux/slices/creatingV2Project/index.ts @@ -0,0 +1,3 @@ +export * from '../shared/v2ProjectDefaultState' +export * from './creatingV2Project' +export { default } from './creatingV2Project' diff --git a/src/redux/slices/editingV2Project/editingV2Project.ts b/src/redux/slices/editingV2Project/editingV2Project.ts index cc0279d0ae..dae165106e 100644 --- a/src/redux/slices/editingV2Project/editingV2Project.ts +++ b/src/redux/slices/editingV2Project/editingV2Project.ts @@ -1,9 +1,9 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { CreatePage } from 'models/createPage' +import { NftPostPayModalConfig } from 'models/nftPostPayModal' import { JB721GovernanceType, NftCollectionMetadata, - NftPostPayModalConfig, NftRewardTier, } from 'models/nftRewards' import { PayoutsSelection } from 'models/payoutsSelection' @@ -21,17 +21,11 @@ import { SerializedV2V3FundingCycleMetadata, } from 'packages/v2v3/utils/serializers' import { - DEFAULT_REDUX_STATE, EMPTY_PAYOUT_GROUPED_SPLITS, EMPTY_RESERVED_TOKENS_GROUPED_SPLITS, -} from './defaultState' -import { NftRewardsData, ReduxState } from './types' -import { REDUX_STORE_V2_PROJECT_VERSION } from './version' - -export const INITIAL_REDUX_STATE = { - version: REDUX_STORE_V2_PROJECT_VERSION, - ...DEFAULT_REDUX_STATE, -} +} from '../shared/v2ProjectDefaultState' +import { INITIAL_REDUX_STATE } from '../shared/v2ProjectInitialReduxState' +import { NftRewardsData, ReduxState } from '../shared/v2ProjectTypes' const editingV2ProjectSlice = createSlice({ name: 'editingV2Project', diff --git a/src/redux/slices/editingV2Project/index.ts b/src/redux/slices/editingV2Project/index.ts index c69218525f..c91cbd97de 100644 --- a/src/redux/slices/editingV2Project/index.ts +++ b/src/redux/slices/editingV2Project/index.ts @@ -1,3 +1,5 @@ -export * from './defaultState' +// Maintain backward compatibility +export * from '../shared/v2ProjectDefaultState' + export * from './editingV2Project' export { default } from './editingV2Project' diff --git a/src/redux/slices/editingV2Project/defaultState.ts b/src/redux/slices/shared/v2ProjectDefaultState.ts similarity index 92% rename from src/redux/slices/editingV2Project/defaultState.ts rename to src/redux/slices/shared/v2ProjectDefaultState.ts index 3467dcf5ac..aec047faca 100644 --- a/src/redux/slices/editingV2Project/defaultState.ts +++ b/src/redux/slices/shared/v2ProjectDefaultState.ts @@ -22,8 +22,9 @@ import { serializeV2V3FundingCycleData, serializeV2V3FundingCycleMetadata, } from 'packages/v2v3/utils/serializers' +import { JB721TiersHookFlags } from 'packages/v4/models/nfts' import { projectDescriptionTemplate } from 'templates/create/projectDescriptionTemplate' -import { CreateState, ProjectState } from './types' +import { CreateState, ProjectState } from './v2ProjectTypes' const DEFAULT_DOMAIN = 'juicebox' @@ -92,6 +93,13 @@ export const DEFAULT_NFT_FLAGS: JBTiered721Flags = { preventOverspending: false, } +export const DEFAULT_NFT_FLAGS_V4: JB721TiersHookFlags = { + noNewTiersWithReserves: false, + noNewTiersWithVotes: false, + noNewTiersWithOwnerMinting: false, + preventOverspending: false, +} + const DEFAULT_PROJECT_METADATA_STATE: ProjectMetadata = { name: '', infoUri: '', @@ -112,7 +120,7 @@ const DEFAULT_PROJECT_METADATA_STATE: ProjectMetadata = { } const DEFAULT_CREATE_STATE: CreateState = { - treasurySelection: undefined, + treasurySelection: 'zero', reconfigurationRuleSelection: undefined, fundingCyclesPageSelection: undefined, createFurthestPageReached: 'projectDetails', diff --git a/src/redux/slices/shared/v2ProjectInitialReduxState.ts b/src/redux/slices/shared/v2ProjectInitialReduxState.ts new file mode 100644 index 0000000000..96cb4e370c --- /dev/null +++ b/src/redux/slices/shared/v2ProjectInitialReduxState.ts @@ -0,0 +1,7 @@ +import { DEFAULT_REDUX_STATE } from './v2ProjectDefaultState' +import { REDUX_STORE_V2_PROJECT_VERSION } from './v2ProjectVersion' + +export const INITIAL_REDUX_STATE = { + version: REDUX_STORE_V2_PROJECT_VERSION, + ...DEFAULT_REDUX_STATE, +} diff --git a/src/redux/slices/editingV2Project/types.ts b/src/redux/slices/shared/v2ProjectTypes.ts similarity index 97% rename from src/redux/slices/editingV2Project/types.ts rename to src/redux/slices/shared/v2ProjectTypes.ts index f6c4e541c3..a7b558e9c8 100644 --- a/src/redux/slices/editingV2Project/types.ts +++ b/src/redux/slices/shared/v2ProjectTypes.ts @@ -1,10 +1,10 @@ import { CreatePage } from 'models/createPage' import { FundingTargetType } from 'models/fundingTargetType' +import { NftPostPayModalConfig } from 'models/nftPostPayModal' import { JB721GovernanceType, JBTiered721Flags, NftCollectionMetadata, - NftPostPayModalConfig, NftRewardTier, } from 'models/nftRewards' import { PayoutsSelection } from 'models/payoutsSelection' diff --git a/src/redux/slices/editingV2Project/version.ts b/src/redux/slices/shared/v2ProjectVersion.ts similarity index 62% rename from src/redux/slices/editingV2Project/version.ts rename to src/redux/slices/shared/v2ProjectVersion.ts index 33f4a9a78c..e3e695e3e3 100644 --- a/src/redux/slices/editingV2Project/version.ts +++ b/src/redux/slices/shared/v2ProjectVersion.ts @@ -1,4 +1,4 @@ -import { DEFAULT_REDUX_STATE } from './defaultState' import hash from 'object-hash' +import { DEFAULT_REDUX_STATE } from './v2ProjectDefaultState' export const REDUX_STORE_V2_PROJECT_VERSION = hash(DEFAULT_REDUX_STATE) diff --git a/src/redux/store.ts b/src/redux/store.ts index dc92277137..1bb691a222 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -4,6 +4,7 @@ import { EnhancedStore, } from '@reduxjs/toolkit' import { getLocalStoragePreloadedState } from './localStoragePreload' +import creatingV2ProjectReducer from './slices/creatingV2Project' import editingProjectReducer from './slices/editingProject' import editingV2ProjectReducer from './slices/editingV2Project' @@ -12,6 +13,7 @@ const REDUX_STATE_LOCALSTORAGE_KEY = 'jb_redux_preloadedState' const rootReducer = combineReducers({ editingProject: editingProjectReducer, editingV2Project: editingV2ProjectReducer, + creatingV2Project: creatingV2ProjectReducer, }) export function createStore(key?: string) { diff --git a/src/utils/delegateMetadata/encodeDelegateMetadata.ts b/src/utils/delegateMetadata/encodeDelegateMetadata.ts index c40da21501..4b6858a553 100644 --- a/src/utils/delegateMetadata/encodeDelegateMetadata.ts +++ b/src/utils/delegateMetadata/encodeDelegateMetadata.ts @@ -1,12 +1,13 @@ import { BigNumber, BigNumberish, utils } from 'ethers' +import { + JB721DelegatePayMetadata, + encodeJb721DelegatePayMetadata, +} from './encodeJb721DelegateMetadata' + import { createMetadata } from 'juicebox-metadata-helper' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { IJBBuybackDelegate_INTERFACE_ID } from 'packages/v2v3/constants/buybackDelegate' import { IJBTiered721Delegate_V3_4_PAY_ID } from 'packages/v2v3/constants/nftRewards' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' -import { - JB721DelegatePayMetadata, - encodeJb721DelegatePayMetadata, -} from './encodeJb721DelegateMetadata' /** * Encode pay metadata for project delegate contracts. diff --git a/src/utils/delegateMetadata/encodeJb721DelegateMetadata.ts b/src/utils/delegateMetadata/encodeJb721DelegateMetadata.ts index 3e4cd84944..e11f3b8cd6 100644 --- a/src/utils/delegateMetadata/encodeJb721DelegateMetadata.ts +++ b/src/utils/delegateMetadata/encodeJb721DelegateMetadata.ts @@ -1,13 +1,14 @@ -import { DEFAULT_ALLOW_OVERSPENDING } from 'constants/transactionDefaults' import { constants, utils } from 'ethers' -import { createMetadata } from 'juicebox-metadata-helper' import { - IJB721Delegate_V3_2_INTERFACE_ID, - IJB721Delegate_V3_INTERFACE_ID, - IJBTiered721Delegate_V3_2_INTERFACE_ID, - IJBTiered721Delegate_V3_4_REDEEM_ID, + IJB721Delegate_V3_2_INTERFACE_ID, + IJB721Delegate_V3_INTERFACE_ID, + IJBTiered721Delegate_V3_2_INTERFACE_ID, + IJBTiered721Delegate_V3_4_REDEEM_ID, } from 'packages/v2v3/constants/nftRewards' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' + +import { DEFAULT_ALLOW_OVERSPENDING } from 'constants/transactionDefaults' +import { createMetadata } from 'juicebox-metadata-helper' +import { JB721DelegateVersion } from 'models/JB721Delegate' interface JB721DELAGATE_V3_PAY_METADATA { tierIdsToMint: number[] diff --git a/src/utils/ipfs.ts b/src/utils/ipfs.ts index c8ea023760..f13a560715 100644 --- a/src/utils/ipfs.ts +++ b/src/utils/ipfs.ts @@ -62,8 +62,8 @@ export function pinataToGatewayUrl(url: string) { * * Hex-encoded CIDs are used to store some CIDs on-chain because they are more gas-efficient. */ -export function encodeIpfsUri(cid: string) { - return '0x' + Buffer.from(base58.decode(cid).slice(2)).toString('hex') +export function encodeIpfsUri(cid: string): `0x${string}` { + return `0x${Buffer.from(base58.decode(cid).slice(2)).toString('hex')}` } /** diff --git a/src/utils/nftRewards.ts b/src/utils/nftRewards.ts index 628d98d2ee..3480e7b7a2 100644 --- a/src/utils/nftRewards.ts +++ b/src/utils/nftRewards.ts @@ -1,10 +1,4 @@ -import { NftFileType } from 'components/inputs/UploadNoStyle' -import { VIDEO_FILE_TYPES } from 'constants/fileTypes' -import { juiceboxEmojiImageUri } from 'constants/images' -import { WAD_DECIMALS } from 'constants/numbers' -import { DEFAULT_JB_721_TIER_CATEGORY } from 'constants/transactionDefaults' import { BigNumber, constants, utils } from 'ethers' -import { pinJson } from 'lib/api/ipfs' import { IPFSNftCollectionMetadata, IPFSNftRewardTier, @@ -16,14 +10,23 @@ import { JBTiered721Flags, JB_721_TIER_PARAMS_V3_1, JB_721_TIER_PARAMS_V3_2, + JB_721_TIER_PARAMS_V4, JB_721_TIER_V3_2, JB_DEPLOY_TIERED_721_DELEGATE_DATA_V3_1, NftRewardTier, } from 'models/nftRewards' +import { decodeEncodedIpfsUri, encodeIpfsUri, ipfsUri } from 'utils/ipfs' + +import { NftFileType } from 'components/inputs/UploadNoStyle' +import { VIDEO_FILE_TYPES } from 'constants/fileTypes' +import { juiceboxEmojiImageUri } from 'constants/images' +import { WAD_DECIMALS } from 'constants/numbers' +import { DEFAULT_JB_721_TIER_CATEGORY } from 'constants/transactionDefaults' +import { pinJson } from 'lib/api/ipfs' +import { JB721DelegateVersion } from 'models/JB721Delegate' import { DEFAULT_NFT_MAX_SUPPLY } from 'packages/v2v3/constants/nftRewards' -import { JB721DelegateVersion } from 'packages/v2v3/models/contracts' import { V2V3CurrencyOption } from 'packages/v2v3/models/currencyOption' -import { decodeEncodedIpfsUri, encodeIpfsUri, ipfsUri } from 'utils/ipfs' +import { JB721TierV4 } from 'packages/v4/contexts/V4NftRewards/V4NftRewardsProvider' export function sortNftsByContributionFloor( rewardTiers: NftRewardTier[], @@ -67,7 +70,11 @@ export function getNftRewardOfFloor({ // returns an array of CIDs from a given array of RewardTier obj's export function CIDsOfNftRewardTiersResponse( - nftRewardTiersResponse: JB721TierV3[] | JB_721_TIER_V3_2[] | undefined, + nftRewardTiersResponse: + | JB721TierV3[] + | JB_721_TIER_V3_2[] + | readonly JB721TierV4[] + | undefined, ): string[] { const cids = nftRewardTiersResponse @@ -303,6 +310,38 @@ function nftRewardTierToJB721TierParamsV3_2( } } +function nftRewardTierToJB721TierParamsV4( + rewardTier: NftRewardTier, + cid: string, +): JB_721_TIER_PARAMS_V4 { + const price = utils.parseEther(rewardTier.contributionFloor.toString()).toBigInt(); + const maxSupply = rewardTier.maxSupply; + const initialSupply = maxSupply ?? DEFAULT_NFT_MAX_SUPPLY; + const encodedIPFSUri = encodeIpfsUri(cid); + + const reservedRate = rewardTier.reservedRate ?? 0; + const reservedTokenBeneficiary = rewardTier.beneficiary ?? constants.AddressZero; + const votingUnits = rewardTier.votingWeight ? BigNumber.from(rewardTier.votingWeight).toNumber() : 0; + + return { + price, + initialSupply, + votingUnits, + reserveFrequency: reservedRate, + reserveBeneficiary: reservedTokenBeneficiary, + encodedIPFSUri, + category: DEFAULT_JB_721_TIER_CATEGORY, + discountPercent: 0, + allowOwnerMint: false, + useReserveBeneficiaryAsDefault: false, + transfersPausable: false, + useVotingUnits: true, + cannotBeRemoved: false, + cannotIncreaseDiscountPercent: false, // Explicitly add all required properties + } as JB_721_TIER_PARAMS_V4; +} + + export function buildJB721TierParams({ cids, // MUST BE SORTED BY CONTRIBUTION FLOOR (TODO: not ideal) rewardTiers, @@ -310,8 +349,8 @@ export function buildJB721TierParams({ }: { cids: string[] rewardTiers: NftRewardTier[] - version: JB721DelegateVersion -}): (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2)[] { + version?: JB721DelegateVersion +}): (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2 | JB_721_TIER_PARAMS_V4)[] { const sortedRewardTiers = sortNftsByContributionFloor(rewardTiers) // `cids` are ordered the same as `rewardTiers` so can get corresponding values from same index @@ -323,7 +362,8 @@ export function buildJB721TierParams({ ): | JB721TierParams | JB_721_TIER_PARAMS_V3_1 - | JB_721_TIER_PARAMS_V3_2 => { + | JB_721_TIER_PARAMS_V3_2 + | JB_721_TIER_PARAMS_V4 => { const rewardTier = sortedRewardTiers[index] if (version === JB721DelegateVersion.JB721DELEGATE_V3) { return nftRewardTierToJB721TierParamsV3(rewardTier, cid) @@ -331,6 +371,9 @@ export function buildJB721TierParams({ if (version === JB721DelegateVersion.JB721DELEGATE_V3_1) { return nftRewardTierToJB721TierParamsV3_1(rewardTier, cid) } + if (version === JB721DelegateVersion.JB721DELEGATE_V4) { + return nftRewardTierToJB721TierParamsV4(rewardTier, cid) + } // default return v3.2 params (unchanged in 3.3, 3.4) return nftRewardTierToJB721TierParamsV3_2(rewardTier, cid) @@ -341,6 +384,18 @@ export function buildJB721TierParams({ // Tiers MUST BE in ascending order when sent to contract. // bit bongy, sorry! + if (version === JB721DelegateVersion.JB721DELEGATE_V4) { + if ((a as JB_721_TIER_PARAMS_V4).price > (b as JB_721_TIER_PARAMS_V4).price) { + return 1 + } + + if ((a as JB_721_TIER_PARAMS_V4).price < (b as JB_721_TIER_PARAMS_V4).price) { + return -1 + } + + return 0 + } + if ( version === JB721DelegateVersion.JB721DELEGATE_V3_2 || version === JB721DelegateVersion.JB721DELEGATE_V3_3 || @@ -390,7 +445,7 @@ type DeployTiered721DelegateParams = { collectionName: string collectionSymbol: string currency: V2V3CurrencyOption - tiers: (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2)[] + tiers: (JB721TierParams | JB_721_TIER_PARAMS_V3_1 | JB_721_TIER_PARAMS_V3_2 | JB_721_TIER_PARAMS_V4)[] ownerAddress: string governanceType: JB721GovernanceType contractAddresses: { diff --git a/src/utils/server/metadata.ts b/src/utils/server/metadata.ts index bec5cb5e49..68b32e7019 100644 --- a/src/utils/server/metadata.ts +++ b/src/utils/server/metadata.ts @@ -1,41 +1,30 @@ -import { CV_V3 } from 'constants/cv' -import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' -import { readNetwork } from 'constants/networks' -import { readProvider } from 'constants/readProvider' -import { V2V3ContractName } from 'packages/v2v3/models/contracts' -import { loadV2V3Contract } from 'packages/v2v3/utils/loadV2V3Contract' +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { PV_V1, PV_V2, PV_V4 } from 'constants/pv' +import { PV } from 'models/pv' import { findProjectMetadata } from './ipfs' -export const getProjectMetadata = async (projectId: string | number) => { +/** + * Server-side function. Returns the metadata for a v2v3 or v4 project. + */ +export const getProjectMetadata = async ( + projectId: string | number, + pv: PV = PV_V2, + chain?: string | undefined, +) => { if (typeof projectId === 'string') { projectId = Number(projectId) } if (isNaN(projectId)) return undefined - const metadataCid = await getMetadataCidFromContract(projectId) - return await findProjectMetadata({ metadataCid }) -} - -async function loadJBProjects() { - const contract = await loadV2V3Contract( - V2V3ContractName.JBProjects, - readNetwork.name, - readProvider, - CV_V3, // Note: v2 and v3 use the same JBProjects, so the CV doesn't matter. - ) - - return contract -} - -const getMetadataCidFromContract = async (projectId: number) => { - const JBProjects = await loadJBProjects() - if (!JBProjects) { - throw new Error(`contract not found ${V2V3ContractName.JBProjects}`) + switch (pv) { + case PV_V1: + throw new Error('V1 projects are not supported') + case PV_V2: + const { V2V3GetMetadataCidFromContract } = await import('./v2v3Metadata') + const metadataCid = await V2V3GetMetadataCidFromContract(projectId) + return findProjectMetadata({ metadataCid }) + case PV_V4: + const { getV4ProjectMetadata } = await import('./v4Metadata') + return getV4ProjectMetadata(projectId, chain) } - const metadataCid = (await JBProjects.metadataContentOf( - projectId, - JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN, - )) as string - - return metadataCid } diff --git a/src/utils/server/pages/props.ts b/src/utils/server/pages/props.ts index b798e9bd38..2091f122f1 100644 --- a/src/utils/server/pages/props.ts +++ b/src/utils/server/pages/props.ts @@ -1,17 +1,22 @@ +import { PV_V2 } from 'constants/pv' import { ProjectMetadata } from 'models/projectMetadata' +import { PV } from 'models/pv' import { GetStaticPropsResult } from 'next' import { getProjectMetadata } from '../metadata' export interface ProjectPageProps { metadata?: ProjectMetadata projectId: number + chainName?: string } export async function getProjectStaticProps( projectId: number, + pv: PV = PV_V2, + chainName?: string | undefined, ): Promise> { try { - const metadata = await getProjectMetadata(projectId) + const metadata = await getProjectMetadata(projectId, pv, chainName) if (!metadata) { return { notFound: true } } @@ -20,6 +25,7 @@ export async function getProjectStaticProps( props: { metadata, projectId, + chainName, }, } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/utils/server/v2v3Metadata.ts b/src/utils/server/v2v3Metadata.ts new file mode 100644 index 0000000000..cc76518c73 --- /dev/null +++ b/src/utils/server/v2v3Metadata.ts @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { CV_V3 } from 'constants/cv' +import { JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN } from 'constants/metadataDomain' +import { readNetwork } from 'constants/networks' +import { readProvider } from 'constants/readProvider' +import { V2V3ContractName } from 'packages/v2v3/models/contracts' +import { loadV2V3Contract } from 'packages/v2v3/utils/loadV2V3Contract' + +export const V2V3GetMetadataCidFromContract = async (projectId: number) => { + const JBProjects = await loadV2V3Contract( + V2V3ContractName.JBProjects, + readNetwork.name, + readProvider, + CV_V3, // Note: v2 and v3 use the same JBProjects, so the CV doesn't matter. + ) + if (!JBProjects) { + throw new Error(`contract not found ${V2V3ContractName.JBProjects}`) + } + const metadataCid = (await JBProjects.metadataContentOf( + projectId, + JUICEBOX_MONEY_PROJECT_METADATA_DOMAIN, + )) as string + + return metadataCid +} diff --git a/src/utils/server/v4Metadata.ts b/src/utils/server/v4Metadata.ts new file mode 100644 index 0000000000..ede66ce8ee --- /dev/null +++ b/src/utils/server/v4Metadata.ts @@ -0,0 +1,42 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { getPublicClient } from '@wagmi/core' +import { + readJbDirectoryControllerOf, + getProjectMetadata as sdkGetProjectMetadata, +} from 'juice-sdk-core' +import { chainNameMap } from 'packages/v4/utils/networks' +import { wagmiConfig } from 'packages/v4/wagmiConfig' +import { PublicClient } from 'viem' + +export const getV4ProjectMetadata = async ( + projectId: string | number, + chain?: string | undefined, +) => { + if (typeof projectId === 'string') { + projectId = Number(projectId) + } + if (isNaN(projectId)) return undefined + + if (!chain) throw new Error('Chain is required for V4 projects') + return await V4GetMetadataCidFromContract(projectId, chain) +} + +const V4GetMetadataCidFromContract = async ( + projectId: number, + chainName: string, +) => { + const chainId = chainNameMap[chainName] + const jbControllerAddress = await readJbDirectoryControllerOf(wagmiConfig, { + chainId, + args: [BigInt(projectId)], + }) + const client = getPublicClient(wagmiConfig, { + chainId, + }) as PublicClient + const metadata = await sdkGetProjectMetadata(client, { + jbControllerAddress, + projectId: BigInt(projectId), + }) + + return metadata +} diff --git a/yarn.lock b/yarn.lock index 9aae589e59..4ad453eee2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -134,7 +134,7 @@ "@babel/highlight" "^7.24.7" picocolors "^1.0.0" -"@babel/compat-data@^7.17.7", "@babel/compat-data@^7.20.5", "@babel/compat-data@^7.21.5": +"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.21.5": version "7.21.7" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.7.tgz#61caffb60776e49a57ba61a88f02bedd8714f6bc" integrity sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA== @@ -259,7 +259,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.5": +"@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz#631e6cc784c7b660417421349aac304c94115366" integrity sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w== @@ -307,18 +307,6 @@ "@babel/helper-split-export-declaration" "^7.18.6" semver "^6.3.0" -"@babel/helper-define-polyfill-provider@^0.3.3": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz#8612e55be5d51f0cd1f36b4a5a83924e89884b7a" - integrity sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww== - dependencies: - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - "@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.21.5": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz#c769afefd41d171836f7cb63e295bedf689d48ba" @@ -454,7 +442,7 @@ dependencies: "@babel/types" "^7.18.6" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.21.5", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.21.5", "@babel/helper-plugin-utils@^7.8.0": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== @@ -923,18 +911,6 @@ "@babel/plugin-syntax-jsx" "^7.21.4" "@babel/types" "^7.21.5" -"@babel/plugin-transform-runtime@^7.5.5": - version "7.21.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz#2e1da21ca597a7d01fc96b699b21d8d2023191aa" - integrity sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA== - dependencies: - "@babel/helper-module-imports" "^7.21.4" - "@babel/helper-plugin-utils" "^7.20.2" - babel-plugin-polyfill-corejs2 "^0.3.3" - babel-plugin-polyfill-corejs3 "^0.6.0" - babel-plugin-polyfill-regenerator "^0.4.1" - semver "^6.3.0" - "@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9" @@ -957,14 +933,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.9" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.16.7", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.6", "@babel/runtime@^7.16.7", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.7", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.9.2": version "7.21.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.21.5.tgz#8492dddda9644ae3bda3b45eabe87382caee7200" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== dependencies: regenerator-runtime "^0.13.11" -"@babel/runtime@^7.19.4", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.21.0", "@babel/runtime@^7.26.0": + version "7.26.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" + integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/runtime@^7.23.9", "@babel/runtime@^7.8.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== @@ -1107,17 +1090,15 @@ preact "^10.16.0" sha.js "^2.4.11" -"@coinbase/wallet-sdk@4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-4.0.4.tgz#634cd89bac93eeaf381a1f026476794e53431ed6" - integrity sha512-74c040CRnGhfRjr3ArnkAgud86erIqdkPHNt5HR1k9u97uTIZCJww9eGYT67Qf7gHPpGS/xW8Be1D4dvRm63FA== +"@coinbase/wallet-sdk@4.2.3": + version "4.2.3" + resolved "https://registry.yarnpkg.com/@coinbase/wallet-sdk/-/wallet-sdk-4.2.3.tgz#a30fa0605b24bc42c37f52a62d2442bcbb7734af" + integrity sha512-BcyHZ/Ec84z0emORzqdXDv4P0oV+tV3a0OirfA8Ko1JGBIAVvB+hzLvZzCDvnuZx7MTK+Dd8Y9Tjlo446BpCIg== dependencies: - buffer "^6.0.3" + "@noble/hashes" "^1.4.0" clsx "^1.2.1" eventemitter3 "^5.0.1" - keccak "^3.0.3" - preact "^10.16.0" - sha.js "^2.4.11" + preact "^10.24.2" "@ctrl/tinycolor@^3.4.0": version "3.6.0" @@ -1212,6 +1193,11 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@ecies/ciphers@^0.2.1": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@ecies/ciphers/-/ciphers-0.2.2.tgz#82a15b10a6e502b63fb30915d944b2eaf3ff17ff" + integrity sha512-ylfGR7PyTd+Rm2PqQowG08BCKA22QuX8NzrL+LxAAvazN10DMwdJ2fWwAzRj05FI/M8vNFGm3cv9Wq/GFWCBLg== + "@ensdomains/address-encoder@^0.1.7": version "0.1.9" resolved "https://registry.yarnpkg.com/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz#f948c485443d9ef7ed2c0c4790e931c33334d02d" @@ -3105,14 +3091,14 @@ "@lingui/core" "4.1.2" "@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9" - integrity sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ== + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz#2f3a8f1d688935c704dbc89132394a41029acbb8" + integrity sha512-wx4aBmgeGvFmOKucFKY+8VFJSYZxs9poN3SDNQFF6lT6NrQUnHiPB2PWz2sc4ieEcAaYYzN+1uWahEeTq2aRIQ== "@lit/reactive-element@^1.3.0", "@lit/reactive-element@^1.6.0": - version "1.6.2" - resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.6.2.tgz#c256690f82f2d7d0ffb0b1cdf68dcb1ec86cea28" - integrity sha512-rDfl+QnCYjuIGf5xI2sVJWdYIi56CTCwWa+nidKYX6oIuBYwUbT/vX4qbUDlHiZKJ/3FRNQ/tWJui44p6/stSA== + version "1.6.3" + resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.6.3.tgz#25b4eece2592132845d303e091bad9b04cdcfe03" + integrity sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ== dependencies: "@lit-labs/ssr-dom-shim" "^1.0.0" @@ -3170,9 +3156,9 @@ readable-stream "^2.3.3" "@metamask/object-multiplex@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-2.0.0.tgz#aa6e4aa7b4e2f457ea4bb51cd7281d931e0aa35d" - integrity sha512-+ItrieVZie3j2LfYE0QkdW3dsEMfMEp419IGx1zyeLqjRZ14iQUPRO0H6CGgfAAoC0x6k2PfCAGRwJUA9BMrqA== + version "2.1.0" + resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-2.1.0.tgz#5e2e908fc46aee581cbba809870eeee0e571cbb6" + integrity sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA== dependencies: once "^1.4.0" readable-stream "^3.6.2" @@ -3221,9 +3207,9 @@ webextension-polyfill-ts "^0.25.0" "@metamask/rpc-errors@^6.2.1": - version "6.3.1" - resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-6.3.1.tgz#d5bb4740e070c3d87e91717ff4c3c6061a081cab" - integrity sha512-ugDY7cKjF4/yH5LtBaOIKHw/AiGGSAmzptAUEiAEGr/78LwuzcXAxmzEQfSfMIfI+f9Djr8cttq1pRJJKfTuCg== + version "6.4.0" + resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-6.4.0.tgz#a7ce01c06c9a347ab853e55818ac5654a73bd006" + integrity sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg== dependencies: "@metamask/utils" "^9.0.0" fast-safe-stringify "^2.0.6" @@ -3234,14 +3220,14 @@ integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== "@metamask/safe-event-emitter@^3.0.0", "@metamask/safe-event-emitter@^3.1.1": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.1.tgz#e89b840a7af8097a8ed4953d8dc8470d1302d3ef" - integrity sha512-ihb3B0T/wJm1eUuArYP4lCTSEoZsClHhuWyfo/kMX3m/odpqNcPfsz5O2A3NT7dXCAgWPGDQGPqygCpgeniKMw== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-3.1.2.tgz#bfac8c7a1a149b5bbfe98f59fbfea512dfa3bad4" + integrity sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA== -"@metamask/sdk-communication-layer@0.27.0": - version "0.27.0" - resolved "https://registry.yarnpkg.com/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.27.0.tgz#8d618fadd39f11627d5b3ef1bc72867439e33ff4" - integrity sha512-G9LCaQzIqp5WmUmvHN6UUdjWrBh67MbRobmbbs5fcc2+9XFhj3vBgtyleUYjun91jSlPHoZeo+f/Pj4/WoPIJg== +"@metamask/sdk-communication-layer@0.31.0": + version "0.31.0" + resolved "https://registry.yarnpkg.com/@metamask/sdk-communication-layer/-/sdk-communication-layer-0.31.0.tgz#0acc063b62aa09d044c7aab65801712d760e53b2" + integrity sha512-V9CxdzabDPjQVgmKGHsyU3SYt4Af27g+4DbGCx0fLoHqN/i1RBDZqs/LYbJX3ykJCANzE+llz/MolMCMrzM2RA== dependencies: bufferutil "^4.0.8" date-fns "^2.29.3" @@ -3249,38 +3235,35 @@ utf-8-validate "^5.0.2" uuid "^8.3.2" -"@metamask/sdk-install-modal-web@0.26.5": - version "0.26.5" - resolved "https://registry.yarnpkg.com/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.26.5.tgz#b696c78818adaff85d01a4f41fecc8fd2c80bc59" - integrity sha512-qVA9Nk+NorGx5hXyODy5wskptE8R7RNYTYt49VbQpJogqbbVe1dnJ98+KaA43PBN4XYMCXmcIhULNiEHGsLynA== +"@metamask/sdk-install-modal-web@0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@metamask/sdk-install-modal-web/-/sdk-install-modal-web-0.31.1.tgz#c08ddeb6d8e5a21344477a3f395ebc66952f0bcd" + integrity sha512-J83K6jN2V3xkTb+/5eyASatlgqHdpzjkTVU6cC+Z/YA9cE32zX8vE0EQweGmExgv+kJ5zz/BiqSZZbMfuilRfQ== dependencies: - qr-code-styling "^1.6.0-rc.1" + "@paulmillr/qr" "^0.2.1" -"@metamask/sdk@0.27.0": - version "0.27.0" - resolved "https://registry.yarnpkg.com/@metamask/sdk/-/sdk-0.27.0.tgz#38617985b8305a0f5d482cdd7af8ddec87968bb7" - integrity sha512-6sMjr/0qR700X1svPGEQ4rBdtccidBLeTC27fYQc7r9ROgSixB1DUUAyu/LoySVqt3Hu/Zm7NnAHXuT228ht7A== +"@metamask/sdk@0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@metamask/sdk/-/sdk-0.31.1.tgz#111f2eeba9f40d1bc358b4bd60bdf5b423d78daf" + integrity sha512-olU3TYRAxIZP5ZXDmi5Y53zXikkPySNiTuBI4QD+2hWYomVlMV2SjOKHSRR6gPuI+fFEg/Z+ImrxDthQfMODwA== dependencies: + "@babel/runtime" "^7.26.0" "@metamask/onboarding" "^1.0.1" "@metamask/providers" "16.1.0" - "@metamask/sdk-communication-layer" "0.27.0" - "@metamask/sdk-install-modal-web" "0.26.5" - "@types/dom-screen-wake-lock" "^1.0.0" + "@metamask/sdk-communication-layer" "0.31.0" + "@metamask/sdk-install-modal-web" "0.31.1" + "@paulmillr/qr" "^0.2.1" bowser "^2.9.0" cross-fetch "^4.0.0" debug "^4.3.4" - eciesjs "^0.3.15" + eciesjs "^0.4.11" eth-rpc-errors "^4.0.3" - eventemitter2 "^6.4.7" - i18next "23.11.5" - i18next-browser-languagedetector "7.1.0" + eventemitter2 "^6.4.9" obj-multiplex "^1.0.0" pump "^3.0.0" - qrcode-terminal-nooctal "^0.12.1" - react-native-webview "^11.26.0" readable-stream "^3.6.2" - rollup-plugin-visualizer "^5.9.2" socket.io-client "^4.5.1" + tslib "^2.6.0" util "^0.12.4" uuid "^8.3.2" @@ -3316,9 +3299,9 @@ uuid "^9.0.1" "@metamask/utils@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.0.0.tgz#cbcdf90e2cfc425f67731fc50d44bdf501daae36" - integrity sha512-Q/PzQCm6rkmePxHghXgJuYEkVfSvwKLLFZwFtfmLAz4mxIPuFJSMawaJM7sfZsVybK5Bf9QaKAjgMvHk5iGGvA== + version "9.3.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-9.3.0.tgz#4726bd7f5d6a43ea8425b6d663ab9207f617c2d1" + integrity sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g== dependencies: "@ethereumjs/tx" "^4.2.0" "@metamask/superstruct" "^3.1.0" @@ -3330,73 +3313,73 @@ semver "^7.5.4" uuid "^9.0.1" -"@motionone/animation@^10.15.1": - version "10.15.1" - resolved "https://registry.yarnpkg.com/@motionone/animation/-/animation-10.15.1.tgz#4a85596c31cbc5100ae8eb8b34c459fb0ccf6807" - integrity sha512-mZcJxLjHor+bhcPuIFErMDNyrdb2vJur8lSfMCsuCB4UyV8ILZLvK+t+pg56erv8ud9xQGK/1OGPt10agPrCyQ== +"@motionone/animation@^10.15.1", "@motionone/animation@^10.18.0": + version "10.18.0" + resolved "https://registry.yarnpkg.com/@motionone/animation/-/animation-10.18.0.tgz#868d00b447191816d5d5cf24b1cafa144017922b" + integrity sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw== dependencies: - "@motionone/easing" "^10.15.1" - "@motionone/types" "^10.15.1" - "@motionone/utils" "^10.15.1" + "@motionone/easing" "^10.18.0" + "@motionone/types" "^10.17.1" + "@motionone/utils" "^10.18.0" tslib "^2.3.1" -"@motionone/dom@^10.16.2": - version "10.16.2" - resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.16.2.tgz#0c44df8ee3d1cfc50ee11d27050b27824355a61a" - integrity sha512-bnuHdNbge1FutZXv+k7xub9oPWcF0hsu8y1HTH/qg6av58YI0VufZ3ngfC7p2xhMJMnoh0LXFma2EGTgPeCkeg== +"@motionone/dom@^10.16.2", "@motionone/dom@^10.16.4": + version "10.18.0" + resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.18.0.tgz#7fd25dac04cab72def6d2b92b8e0cdc091576527" + integrity sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A== dependencies: - "@motionone/animation" "^10.15.1" - "@motionone/generators" "^10.15.1" - "@motionone/types" "^10.15.1" - "@motionone/utils" "^10.15.1" + "@motionone/animation" "^10.18.0" + "@motionone/generators" "^10.18.0" + "@motionone/types" "^10.17.1" + "@motionone/utils" "^10.18.0" hey-listen "^1.0.8" tslib "^2.3.1" -"@motionone/easing@^10.15.1": - version "10.15.1" - resolved "https://registry.yarnpkg.com/@motionone/easing/-/easing-10.15.1.tgz#95cf3adaef34da6deebb83940d8143ede3deb693" - integrity sha512-6hIHBSV+ZVehf9dcKZLT7p5PEKHGhDwky2k8RKkmOvUoYP3S+dXsKupyZpqx5apjd9f+php4vXk4LuS+ADsrWw== +"@motionone/easing@^10.18.0": + version "10.18.0" + resolved "https://registry.yarnpkg.com/@motionone/easing/-/easing-10.18.0.tgz#7b82f6010dfee3a1bb0ee83abfbaff6edae0c708" + integrity sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg== dependencies: - "@motionone/utils" "^10.15.1" + "@motionone/utils" "^10.18.0" tslib "^2.3.1" -"@motionone/generators@^10.15.1": - version "10.15.1" - resolved "https://registry.yarnpkg.com/@motionone/generators/-/generators-10.15.1.tgz#dc6abb11139d1bafe758a41c134d4c753a9b871c" - integrity sha512-67HLsvHJbw6cIbLA/o+gsm7h+6D4Sn7AUrB/GPxvujse1cGZ38F5H7DzoH7PhX+sjvtDnt2IhFYF2Zp1QTMKWQ== +"@motionone/generators@^10.18.0": + version "10.18.0" + resolved "https://registry.yarnpkg.com/@motionone/generators/-/generators-10.18.0.tgz#fe09ab5cfa0fb9a8884097feb7eb60abeb600762" + integrity sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg== dependencies: - "@motionone/types" "^10.15.1" - "@motionone/utils" "^10.15.1" + "@motionone/types" "^10.17.1" + "@motionone/utils" "^10.18.0" tslib "^2.3.1" "@motionone/svelte@^10.16.2": - version "10.16.2" - resolved "https://registry.yarnpkg.com/@motionone/svelte/-/svelte-10.16.2.tgz#0b37c3b12927814d31d24941d1ca0ff49981b444" - integrity sha512-38xsroKrfK+aHYhuQlE6eFcGy0EwrB43Q7RGjF73j/kRUTcLNu/LAaKiLLsN5lyqVzCgTBVt4TMT/ShWbTbc5Q== + version "10.16.4" + resolved "https://registry.yarnpkg.com/@motionone/svelte/-/svelte-10.16.4.tgz#5daf117cf5b2576fc6dd487c5e0500938a742470" + integrity sha512-zRVqk20lD1xqe+yEDZhMYgftsuHc25+9JSo+r0a0OWUJFocjSV9D/+UGhX4xgJsuwB9acPzXLr20w40VnY2PQA== dependencies: - "@motionone/dom" "^10.16.2" + "@motionone/dom" "^10.16.4" tslib "^2.3.1" -"@motionone/types@^10.15.1": - version "10.15.1" - resolved "https://registry.yarnpkg.com/@motionone/types/-/types-10.15.1.tgz#89441b54285012795cbba8612cbaa0fa420db3eb" - integrity sha512-iIUd/EgUsRZGrvW0jqdst8st7zKTzS9EsKkP+6c6n4MPZoQHwiHuVtTQLD6Kp0bsBLhNzKIBlHXponn/SDT4hA== +"@motionone/types@^10.15.1", "@motionone/types@^10.17.1": + version "10.17.1" + resolved "https://registry.yarnpkg.com/@motionone/types/-/types-10.17.1.tgz#cf487badbbdc9da0c2cb86ffc1e5d11147c6e6fb" + integrity sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A== -"@motionone/utils@^10.15.1": - version "10.15.1" - resolved "https://registry.yarnpkg.com/@motionone/utils/-/utils-10.15.1.tgz#6b5f51bde75be88b5411e084310299050368a438" - integrity sha512-p0YncgU+iklvYr/Dq4NobTRdAPv9PveRDUXabPEeOjBLSO/1FNB2phNTZxOxpi1/GZwYpAoECEa0Wam+nsmhSw== +"@motionone/utils@^10.15.1", "@motionone/utils@^10.18.0": + version "10.18.0" + resolved "https://registry.yarnpkg.com/@motionone/utils/-/utils-10.18.0.tgz#a59ff8932ed9009624bca07c56b28ef2bb2f885e" + integrity sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw== dependencies: - "@motionone/types" "^10.15.1" + "@motionone/types" "^10.17.1" hey-listen "^1.0.8" tslib "^2.3.1" "@motionone/vue@^10.16.2": - version "10.16.2" - resolved "https://registry.yarnpkg.com/@motionone/vue/-/vue-10.16.2.tgz#faf13afc27620a2df870c71c58a04ee8de8dea65" - integrity sha512-7/dEK/nWQXOkJ70bqb2KyNfSWbNvWqKKq1C8juj+0Mg/AorgD8O5wE3naddK0G+aXuNMqRuc4jlsYHHWHtIzVw== + version "10.16.4" + resolved "https://registry.yarnpkg.com/@motionone/vue/-/vue-10.16.4.tgz#07d09e3aa5115ca0bcc0076cb9e5322775277c09" + integrity sha512-z10PF9JV6SbjFq+/rYabM+8CVlMokgl8RFGvieSGNTmrkQanfHn+15XBrhG3BgUfvmTeSeyShfOHpG0i9zEdcg== dependencies: - "@motionone/dom" "^10.16.2" + "@motionone/dom" "^10.16.4" tslib "^2.3.1" "@next/bundle-analyzer@^14.2.0": @@ -3406,10 +3389,10 @@ dependencies: webpack-bundle-analyzer "4.10.1" -"@next/env@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.10.tgz#1d3178340028ced2d679f84140877db4f420333c" - integrity sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw== +"@next/env@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.18.tgz#ccbcf906f0123a37cff6edc1effd524d635fd395" + integrity sha512-2vWLOUwIPgoqMJKG6dt35fVXVhgM09tw4tK3/Q34GFXDrfiHlG7iS33VA4ggnjWxjiz9KV5xzfsQzJX6vGAekA== "@next/eslint-plugin-next@14.2.5": version "14.2.5" @@ -3418,56 +3401,61 @@ dependencies: glob "10.3.10" -"@next/swc-darwin-arm64@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.10.tgz#49d10ca4086fbd59ee68e204f75d7136eda2aa80" - integrity sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ== - -"@next/swc-darwin-x64@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz#0ebeae3afb8eac433882b79543295ab83624a1a8" - integrity sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA== - -"@next/swc-linux-arm64-gnu@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz#7e602916d2fb55a3c532f74bed926a0137c16f20" - integrity sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA== - -"@next/swc-linux-arm64-musl@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz#6b143f628ccee490b527562e934f8de578d4be47" - integrity sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ== - -"@next/swc-linux-x64-gnu@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz#086f2f16a0678890a1eb46518c4dda381b046082" - integrity sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg== - -"@next/swc-linux-x64-musl@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz#1befef10ed8dbcc5047b5d637a25ae3c30a0bfc3" - integrity sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA== - -"@next/swc-win32-arm64-msvc@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz#731f52c3ae3c56a26cf21d474b11ae1529531209" - integrity sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ== - -"@next/swc-win32-ia32-msvc@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz#32723ef7f04e25be12af357cc72ddfdd42fd1041" - integrity sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg== - -"@next/swc-win32-x64-msvc@14.2.10": - version "14.2.10" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz#ee1d036cb5ec871816f96baee7991035bb242455" - integrity sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ== +"@next/swc-darwin-arm64@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.18.tgz#273d490a11a271044d2c060339d24b99886a75c1" + integrity sha512-tOBlDHCjGdyLf0ube/rDUs6VtwNOajaWV+5FV/ajPgrvHeisllEdymY/oDgv2cx561+gJksfMUtqf8crug7sbA== + +"@next/swc-darwin-x64@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.18.tgz#b347cd799584ff79f7b69e5be8833b270fd6c51d" + integrity sha512-uJCEjutt5VeJ30jjrHV1VIHCsbMYnEqytQgvREx+DjURd/fmKy15NaVK4aR/u98S1LGTnjq35lRTnRyygglxoA== + +"@next/swc-linux-arm64-gnu@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.18.tgz#6d59d4d5b4b76e453512e1e2b5ad12a2b75930cd" + integrity sha512-IL6rU8vnBB+BAm6YSWZewc+qvdL1EaA+VhLQ6tlUc0xp+kkdxQrVqAnh8Zek1ccKHlTDFRyAft0e60gteYmQ4A== + +"@next/swc-linux-arm64-musl@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.18.tgz#a45624d5bc5a5abd640d97ac9c3e43562f81e258" + integrity sha512-RCaENbIZqKKqTlL8KNd+AZV/yAdCsovblOpYFp0OJ7ZxgLNbV5w23CUU1G5On+0fgafrsGcW+GdMKdFjaRwyYA== + +"@next/swc-linux-x64-gnu@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.18.tgz#04a98935cb94e301a3477bbe7754e8f86b44c0e3" + integrity sha512-3kmv8DlyhPRCEBM1Vavn8NjyXtMeQ49ID0Olr/Sut7pgzaQTo4h01S7Z8YNE0VtbowyuAL26ibcz0ka6xCTH5g== + +"@next/swc-linux-x64-musl@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.18.tgz#018415234d5f0086bdabdbd92bdc85223c35cffa" + integrity sha512-mliTfa8seVSpTbVEcKEXGjC18+TDII8ykW4a36au97spm9XMPqQTpdGPNBJ9RySSFw9/hLuaCMByluQIAnkzlw== + +"@next/swc-win32-arm64-msvc@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.18.tgz#a2e26c9858147a6438c583b37f8b7374a124fbea" + integrity sha512-J5g0UFPbAjKYmqS3Cy7l2fetFmWMY9Oao32eUsBPYohts26BdrMUyfCJnZFQkX9npYaHNDOWqZ6uV9hSDPw9NA== + +"@next/swc-win32-ia32-msvc@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.18.tgz#1694e7366df9f34925822b8bd3296c1ea94b0eb3" + integrity sha512-Ynxuk4ZgIpdcN7d16ivJdjsDG1+3hTvK24Pp8DiDmIa2+A4CfhJSEHHVndCHok6rnLUzAZD+/UOKESQgTsAZGg== + +"@next/swc-win32-x64-msvc@14.2.18": + version "14.2.18" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.18.tgz#91d56970f0e484c7e4f8a9f11635d82552e0fce1" + integrity sha512-dtRGMhiU9TN5nyhwzce+7c/4CCeykYS+ipY/4mIrGzJ71+7zNo55ZxCB7cAVuNqdwtYniFNR2c9OFQ6UdFIMcg== "@nicolo-ribaudo/semver-v6@^6.3.3": version "6.3.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz#ea6d23ade78a325f7a52750aab1526b02b628c29" integrity sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg== +"@noble/ciphers@^1.0.0": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-1.1.3.tgz#eb27085aa7ce94d8c6eaeb64299bab0589920ec1" + integrity sha512-Ygv6WnWJHLLiW4fnNDC1z+i13bud+enXOFRBlpxI+NJliPWx5wdR+oWlTjLuBPTqjUjtHXtjkU6w3kuuH6upZA== + "@noble/curves@1.2.0", "@noble/curves@~1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -3482,17 +3470,34 @@ dependencies: "@noble/hashes" "1.4.0" -"@noble/hashes@1.3.2", "@noble/hashes@~1.3.0": +"@noble/curves@^1.6.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.7.0.tgz#0512360622439256df892f21d25b388f52505e45" + integrity sha512-UTMhXK9SeDhFJVrHeUJ5uZlI6ajXg10O6Ddocf9S6GjbSBVZsJo88HzKwXznNfGpMTRDyJkqMjNDPYgf0qFWnw== + dependencies: + "@noble/hashes" "1.6.0" + +"@noble/hashes@1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== -"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.4.0": +"@noble/hashes@1.4.0", "@noble/hashes@~1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== -"@noble/hashes@~1.3.2": +"@noble/hashes@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.0.tgz#d4bfb516ad6e7b5111c216a5cc7075f4cf19e6c5" + integrity sha512-YUULf0Uk4/mAA89w+k3+yUYh6NrEvxZa5T6SY3wlMvE2chHkxFUUIDI8/XW1QSC357iA5pSnqt7XEhvFOqmDyQ== + +"@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@^1.5.0": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.6.1.tgz#df6e5943edcea504bac61395926d6fd67869a0d5" + integrity sha512-pq5D8h10hHBjyqX+cfBm0i8JUXJ0UhczFc4r74zbuT9XgewFo2E3J1cOaGtdZynILNmQ685YWGzGE1Zv6io50w== + +"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2": version "1.3.3" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== @@ -3538,97 +3543,108 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.9.3.tgz#00d7a8cf35a475b160b3f0293a6403c511099364" integrity sha512-He3LieZ1pP2TNt5JbkPA4PNT9WC3gOTOlDcFGJW4Le4QKqwmiNJCRt44APfxMxvq7OugU/cqYuPcSBzOw38DAg== -"@parcel/watcher-android-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.1.tgz#c2c19a3c442313ff007d2d7a9c2c1dd3e1c9ca84" - integrity sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg== +"@parcel/watcher-android-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a" + integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ== -"@parcel/watcher-darwin-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.1.tgz#c817c7a3b4f3a79c1535bfe54a1c2818d9ffdc34" - integrity sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA== +"@parcel/watcher-darwin-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f" + integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw== -"@parcel/watcher-darwin-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.1.tgz#1a3f69d9323eae4f1c61a5f480a59c478d2cb020" - integrity sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg== +"@parcel/watcher-darwin-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb" + integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA== -"@parcel/watcher-freebsd-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.1.tgz#0d67fef1609f90ba6a8a662bc76a55fc93706fc8" - integrity sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w== +"@parcel/watcher-freebsd-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82" + integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw== -"@parcel/watcher-linux-arm-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.1.tgz#ce5b340da5829b8e546bd00f752ae5292e1c702d" - integrity sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA== +"@parcel/watcher-linux-arm-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42" + integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA== -"@parcel/watcher-linux-arm64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.1.tgz#6d7c00dde6d40608f9554e73998db11b2b1ff7c7" - integrity sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA== +"@parcel/watcher-linux-arm-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4" + integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA== -"@parcel/watcher-linux-arm64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.1.tgz#bd39bc71015f08a4a31a47cd89c236b9d6a7f635" - integrity sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA== +"@parcel/watcher-linux-arm64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03" + integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA== -"@parcel/watcher-linux-x64-glibc@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.1.tgz#0ce29966b082fb6cdd3de44f2f74057eef2c9e39" - integrity sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg== +"@parcel/watcher-linux-arm64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732" + integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q== -"@parcel/watcher-linux-x64-musl@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.1.tgz#d2ebbf60e407170bb647cd6e447f4f2bab19ad16" - integrity sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ== +"@parcel/watcher-linux-x64-glibc@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d" + integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw== + +"@parcel/watcher-linux-x64-musl@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef" + integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA== "@parcel/watcher-wasm@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.4.1.tgz#c4353e4fdb96ee14389856f7f6f6d21b7dcef9e1" - integrity sha512-/ZR0RxqxU/xxDGzbzosMjh4W6NdYFMqq2nvo2b8SLi7rsl/4jkL8S5stIikorNkdR50oVDvqb/3JT05WM+CRRA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.5.0.tgz#81fad1e10957f08a532eb4fc0d4c353cd8901a50" + integrity sha512-Z4ouuR8Pfggk1EYYbTaIoxc+Yv4o7cGQnH0Xy8+pQ+HbiW+ZnwhcD2LPf/prfq1nIWpAxjOkQ8uSMFWMtBLiVQ== dependencies: is-glob "^4.0.3" micromatch "^4.0.5" napi-wasm "^1.1.0" -"@parcel/watcher-win32-arm64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.1.tgz#eb4deef37e80f0b5e2f215dd6d7a6d40a85f8adc" - integrity sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg== +"@parcel/watcher-win32-arm64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154" + integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig== -"@parcel/watcher-win32-ia32@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.1.tgz#94fbd4b497be39fd5c8c71ba05436927842c9df7" - integrity sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw== +"@parcel/watcher-win32-ia32@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220" + integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA== -"@parcel/watcher-win32-x64@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.1.tgz#4bf920912f67cae5f2d264f58df81abfea68dadf" - integrity sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A== +"@parcel/watcher-win32-x64@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7" + integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw== "@parcel/watcher@^2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.1.tgz#a50275151a1bb110879c6123589dba90c19f1bf8" - integrity sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA== + version "2.5.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10" + integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ== dependencies: detect-libc "^1.0.3" is-glob "^4.0.3" micromatch "^4.0.5" node-addon-api "^7.0.0" optionalDependencies: - "@parcel/watcher-android-arm64" "2.4.1" - "@parcel/watcher-darwin-arm64" "2.4.1" - "@parcel/watcher-darwin-x64" "2.4.1" - "@parcel/watcher-freebsd-x64" "2.4.1" - "@parcel/watcher-linux-arm-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-glibc" "2.4.1" - "@parcel/watcher-linux-arm64-musl" "2.4.1" - "@parcel/watcher-linux-x64-glibc" "2.4.1" - "@parcel/watcher-linux-x64-musl" "2.4.1" - "@parcel/watcher-win32-arm64" "2.4.1" - "@parcel/watcher-win32-ia32" "2.4.1" - "@parcel/watcher-win32-x64" "2.4.1" + "@parcel/watcher-android-arm64" "2.5.0" + "@parcel/watcher-darwin-arm64" "2.5.0" + "@parcel/watcher-darwin-x64" "2.5.0" + "@parcel/watcher-freebsd-x64" "2.5.0" + "@parcel/watcher-linux-arm-glibc" "2.5.0" + "@parcel/watcher-linux-arm-musl" "2.5.0" + "@parcel/watcher-linux-arm64-glibc" "2.5.0" + "@parcel/watcher-linux-arm64-musl" "2.5.0" + "@parcel/watcher-linux-x64-glibc" "2.5.0" + "@parcel/watcher-linux-x64-musl" "2.5.0" + "@parcel/watcher-win32-arm64" "2.5.0" + "@parcel/watcher-win32-ia32" "2.5.0" + "@parcel/watcher-win32-x64" "2.5.0" + +"@paulmillr/qr@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@paulmillr/qr/-/qr-0.2.1.tgz#76ade7080be4ac4824f638146fd8b6db1805eeca" + integrity sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ== "@paulrberg/contracts@^3.4.0", "@paulrberg/contracts@^3.7.0": version "3.7.0" @@ -3720,10 +3736,10 @@ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1" integrity sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA== -"@safe-global/safe-apps-provider@0.18.3", "@safe-global/safe-apps-provider@^0.18.3": - version "0.18.3" - resolved "https://registry.yarnpkg.com/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.3.tgz#805a42e24f5dde803cb96dac251a3c9e256de45b" - integrity sha512-f/0cNv3S4v7p8rowAjj0hDCg8Q8P/wBjp5twkNWeBdvd0RDr7BuRBPPk74LCqmjQ82P+1ltLlkmVFSmxTIT7XQ== +"@safe-global/safe-apps-provider@0.18.4", "@safe-global/safe-apps-provider@^0.18.3": + version "0.18.4" + resolved "https://registry.yarnpkg.com/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.4.tgz#53df912aa20d933f6b14c5bcb0737a8cd47def57" + integrity sha512-SWYeG3gyTO6wGHMSokfHakZ9isByn2mHsM0VohIorYFFEyGGmJ89btnTm+DqDUSoQtvWAatZB7XNy6CaYMvqtg== dependencies: "@safe-global/safe-apps-sdk" "^9.1.0" events "^3.3.0" @@ -3745,9 +3761,9 @@ viem "^1.0.0" "@safe-global/safe-gateway-typescript-sdk@^3.5.3": - version "3.21.8" - resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.21.8.tgz#f90eb668dd620d0c5578f02f7040169610a0eda1" - integrity sha512-n/fYgiqbuzAQuK0bgny6GBYvb585ETxKURa5Kb9hBV3fa47SvJo/dpGq275fJUn0e3Hh1YqETiLGj4HVJjHiTA== + version "3.22.4" + resolved "https://registry.yarnpkg.com/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.22.4.tgz#9109a538df40f778666a3e6776e7a08c757e893d" + integrity sha512-Z7Z8w3GEJdJ/paF+NK23VN4AwqWPadq0AeRYjYLjIBiPWpRB2UO/FKq7ONABEq0YFgNPklazIV4IExQU1gavXA== "@sapphire/async-queue@^1.5.0": version "1.5.0" @@ -3767,15 +3783,15 @@ resolved "https://registry.yarnpkg.com/@sapphire/snowflake/-/snowflake-3.5.1.tgz#254521c188b49e8b2d4cc048b475fb2b38737fec" integrity sha512-BxcYGzgEsdlG0dKAyOm0ehLGm2CafIrfQTZGWgkfKYbj+pNNsorZ7EotuZukc2MT70E0UbppVbtpBrqpzVzjNA== -"@scure/base@^1.1.3", "@scure/base@~1.1.2", "@scure/base@~1.1.6": - version "1.1.7" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30" - integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g== +"@scure/base@^1.1.3": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.1.tgz#dd0b2a533063ca612c17aa9ad26424a2ff5aa865" + integrity sha512-DGmGtC8Tt63J5GfHgfl5CuAXh96VF/LD8K9Hr/Gv0J2lAoRGlPOMpqMpMbCTOoOJMZCk2Xt+DskdDyn6dEFdzQ== -"@scure/base@~1.1.0": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.2.tgz#ff0cf51874aaf176490c9cb46e4df807a2e581d2" - integrity sha512-sSCrnIdaUZQHhBxZThMuk7Wm1TWzMD3uJNdGgx3JS23xSqevu0tAOsg8k66nL3R2NwQe65AI9GgqpPOgZys/eA== +"@scure/base@~1.1.0", "@scure/base@~1.1.2", "@scure/base@~1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" + integrity sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg== "@scure/bip32@1.3.2": version "1.3.2" @@ -3812,9 +3828,9 @@ "@scure/base" "~1.1.6" "@sideway/address@^4.1.3": - version "4.1.4" - resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" - integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw== + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== dependencies: "@hapi/hoek" "^9.0.0" @@ -4352,13 +4368,6 @@ dependencies: "@babel/types" "^7.3.0" -"@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - "@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": version "5.1.1" resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" @@ -4449,11 +4458,6 @@ dependencies: "@types/ms" "*" -"@types/dom-screen-wake-lock@^1.0.0": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/dom-screen-wake-lock/-/dom-screen-wake-lock-1.0.3.tgz#c3588a5f6f40fae957f9ce5be9bc4927a61bb9a0" - integrity sha512-3Iten7X3Zgwvk6kh6/NRdwN7WbZ760YgFCsF5AxDifltUQzW1RaW+WRmcVtgwFzLjaNu64H+0MPJ13yRa8g3Dw== - "@types/dompurify@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.2.tgz#c1cd33a475bc49c43c2a7900e41028e2136a4553" @@ -4622,9 +4626,9 @@ "@types/mjml-core" "*" "@types/ms@*": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + version "0.7.34" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.34.tgz#10964ba0dee6ac4cd462e2795b6bebd407303433" + integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== "@types/mustache@^4.2.2": version "4.2.2" @@ -4632,9 +4636,11 @@ integrity sha512-MUSpfpW0yZbTgjekDbH0shMYBUD+X/uJJJMm9LXN1d5yjl5lCY1vN/eWKD6D1tOtjA6206K0zcIPnUaFMurdNA== "@types/node@*": - version "20.2.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.2.3.tgz#b31eb300610c3835ac008d690de6f87e28f9b878" - integrity sha512-pg9d0yC4rVNWQzX8U7xb4olIOFuuVL9za3bzMT2pu2SU0SNEi66i2qrvhE2qt0HvkhuCaWJu7pLNOt/Pj8BIrw== + version "22.10.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.1.tgz#41ffeee127b8975a05f8c4f83fb89bcb2987d766" + integrity sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ== + dependencies: + undici-types "~6.20.0" "@types/node@^12.12.6": version "12.20.55" @@ -4740,13 +4746,6 @@ dependencies: "@types/node" "*" -"@types/secp256k1@^4.0.6": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" - integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== - dependencies: - "@types/node" "*" - "@types/semver@^7.3.12": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" @@ -4769,11 +4768,16 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== -"@types/trusted-types@*", "@types/trusted-types@^2.0.2": +"@types/trusted-types@*": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== +"@types/trusted-types@^2.0.2": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + "@types/unist@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a" @@ -5074,53 +5078,31 @@ resolved "https://registry.yarnpkg.com/@vladfrangu/async_event_emitter/-/async_event_emitter-2.2.2.tgz#84c5a3f8d648842cec5cc649b88df599af32ed88" integrity sha512-HIzRG7sy88UZjBJamssEczH5q7t5+axva19UbZLO6u0ySbYPrwzWiXBcC0WuHyhKKoeCyneH+FvYzKQq/zTtkQ== -"@wagmi/connectors@5.1.5": - version "5.1.5" - resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-5.1.5.tgz#14acf084809f78aac1f1104344881bd871ac33a2" - integrity sha512-z+UAfwfTqVldoNxUFffHPcc/ets3UP1ehXE6b9k9ZDaih8VdZJRGz84qLjx+GVnI/+FrHfFwPPD9C2YYd2azww== +"@wagmi/connectors@5.5.3": + version "5.5.3" + resolved "https://registry.yarnpkg.com/@wagmi/connectors/-/connectors-5.5.3.tgz#0bf4778ce66f0bd646f86b4479ef24054e409ebd" + integrity sha512-ADXcNuNtONh4PNzs5tWiYzl77P4UohXC7ozYecGvbn3Fkdk6x4tfsF9Wy3Ag5WcVbbp89MPpJ2+VK2ckBgtLAg== dependencies: - "@coinbase/wallet-sdk" "4.0.4" - "@metamask/sdk" "0.27.0" - "@safe-global/safe-apps-provider" "0.18.3" + "@coinbase/wallet-sdk" "4.2.3" + "@metamask/sdk" "0.31.1" + "@safe-global/safe-apps-provider" "0.18.4" "@safe-global/safe-apps-sdk" "9.1.0" - "@walletconnect/ethereum-provider" "2.14.0" - "@walletconnect/modal" "2.6.2" + "@walletconnect/ethereum-provider" "2.17.0" cbw-sdk "npm:@coinbase/wallet-sdk@3.9.3" -"@wagmi/core@2.13.4": - version "2.13.4" - resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.13.4.tgz#8d5da08e450171bfe34f72a079cfa2b81825410a" - integrity sha512-J6gfxHYr8SCc/BzEa712LnI+qLFs5K2nBLupwQqQl4WiAlCu8SdcpbZokqiwfCMYhIRMj0+YFEP9qe4ypcexmw== +"@wagmi/core@2.15.2": + version "2.15.2" + resolved "https://registry.yarnpkg.com/@wagmi/core/-/core-2.15.2.tgz#5bc934b4bca0d7fac1062c920a5366716f069613" + integrity sha512-4Bu1JA3HqtKvmBBsesvJ3HyqyLk69XYP0lwmG8jFqa5osfqn9iD8pvjsq5VHbIus+ZFM/UL6ydp9WWdtPNjH7w== dependencies: eventemitter3 "5.0.1" mipd "0.0.7" - zustand "4.4.1" + zustand "5.0.0" -"@walletconnect/browser-utils@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/browser-utils/-/browser-utils-1.8.0.tgz#33c10e777aa6be86c713095b5206d63d32df0951" - integrity sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A== - dependencies: - "@walletconnect/safe-json" "1.0.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/window-getters" "1.0.0" - "@walletconnect/window-metadata" "1.0.0" - detect-browser "5.2.0" - -"@walletconnect/client@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/client/-/client-1.8.0.tgz#6f46b5499c7c861c651ff1ebe5da5b66225ca696" - integrity sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ== - dependencies: - "@walletconnect/core" "^1.8.0" - "@walletconnect/iso-crypto" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - -"@walletconnect/core@2.13.3": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.3.tgz#d98fccefe36c6b365812fd0f7237a0f9634bafb6" - integrity sha512-TdF+rC6rONJGyOUtt/nLkbyQWjnkwbD3kXq3ZA0Q7+tYtmSjTDE4wbArlLbHIbtf69g+9/DpEVEQimWWcEOn2g== +"@walletconnect/core@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.17.0.tgz#bf490e85a4702eff0f7cf81ba0d3c1016dffff33" + integrity sha512-On+uSaCfWdsMIQsECwWHZBmUXfrnqmv6B8SXRRuTJgd8tUpEvBkLQH4X7XkSm3zW6ozEkQTCagZ2ox2YPn3kbw== dependencies: "@walletconnect/heartbeat" "1.2.2" "@walletconnect/jsonrpc-provider" "1.0.14" @@ -5129,70 +5111,16 @@ "@walletconnect/jsonrpc-ws-connection" "1.0.14" "@walletconnect/keyvaluestorage" "1.1.1" "@walletconnect/logger" "2.1.2" - "@walletconnect/relay-api" "1.0.10" + "@walletconnect/relay-api" "1.0.11" "@walletconnect/relay-auth" "1.0.4" "@walletconnect/safe-json" "1.0.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.3" - "@walletconnect/utils" "2.13.3" + "@walletconnect/types" "2.17.0" + "@walletconnect/utils" "2.17.0" events "3.3.0" - isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" uint8arrays "3.1.0" -"@walletconnect/core@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.14.0.tgz#e8afb01455968b02aaf26c74f3bfcc9b82678a39" - integrity sha512-E/dgBM9q3judXnTfZQ5ILvDpeSdDpabBLsXtYXa3Nyc26cfNplfLJ2nXm9FgtTdhM1nZ7yx4+zDPiXawBRZl2g== - dependencies: - "@walletconnect/heartbeat" "1.2.2" - "@walletconnect/jsonrpc-provider" "1.0.14" - "@walletconnect/jsonrpc-types" "1.0.4" - "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/jsonrpc-ws-connection" "1.0.14" - "@walletconnect/keyvaluestorage" "1.1.1" - "@walletconnect/logger" "2.1.2" - "@walletconnect/relay-api" "1.0.10" - "@walletconnect/relay-auth" "1.0.4" - "@walletconnect/safe-json" "1.0.2" - "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.14.0" - "@walletconnect/utils" "2.14.0" - events "3.3.0" - isomorphic-unfetch "3.1.0" - lodash.isequal "4.5.0" - uint8arrays "3.1.0" - -"@walletconnect/core@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-1.8.0.tgz#6b2748b90c999d9d6a70e52e26a8d5e8bfeaa81e" - integrity sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw== - dependencies: - "@walletconnect/socket-transport" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - -"@walletconnect/crypto@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/crypto/-/crypto-1.0.3.tgz#7b8dd4d7e2884fe3543c7c07aea425eef5ef9dd4" - integrity sha512-+2jdORD7XQs76I2Odgr3wwrtyuLUXD/kprNVsjWRhhhdO9Mt6WqVzOPu0/t7OHSmgal8k7SoBQzUc5hu/8zL/g== - dependencies: - "@walletconnect/encoding" "^1.0.2" - "@walletconnect/environment" "^1.0.1" - "@walletconnect/randombytes" "^1.0.3" - aes-js "^3.1.2" - hash.js "^1.1.7" - tslib "1.14.1" - -"@walletconnect/encoding@^1.0.1", "@walletconnect/encoding@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/encoding/-/encoding-1.0.2.tgz#cb3942ad038d6a6bf01158f66773062dd25724da" - integrity sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag== - dependencies: - is-typedarray "1.0.0" - tslib "1.14.1" - typedarray-to-buffer "3.1.5" - "@walletconnect/environment@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/environment/-/environment-1.0.1.tgz#1d7f82f0009ab821a2ba5ad5e5a7b8ae3b214cd7" @@ -5200,36 +5128,20 @@ dependencies: tslib "1.14.1" -"@walletconnect/ethereum-provider@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.14.0.tgz#0ed4ba9b383c889b56e0af87181756d900fc504a" - integrity sha512-Cc2/DCn85VciA10BrsNWFM//3VC1D8yjwrjfUKjGndLPDz0YIdAxTgYZViIlMjE0lzQC/DMvPYEAnGfW0O1Bwg== +"@walletconnect/ethereum-provider@2.17.0", "@walletconnect/ethereum-provider@^2.13.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.17.0.tgz#d74feaaed6180a6799e96760d7ee867ff3a083d2" + integrity sha512-b+KTAXOb6JjoxkwpgYQQKPUcTwENGmdEdZoIDLeRicUmZTn/IQKfkMoC2frClB4YxkyoVMtj1oMV2JAax+yu9A== dependencies: "@walletconnect/jsonrpc-http-connection" "1.0.8" "@walletconnect/jsonrpc-provider" "1.0.14" "@walletconnect/jsonrpc-types" "1.0.4" "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/modal" "2.6.2" - "@walletconnect/sign-client" "2.14.0" - "@walletconnect/types" "2.14.0" - "@walletconnect/universal-provider" "2.14.0" - "@walletconnect/utils" "2.14.0" - events "3.3.0" - -"@walletconnect/ethereum-provider@^2.13.0": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/ethereum-provider/-/ethereum-provider-2.13.3.tgz#e3cb46393403ce69fe0d07b91f8cc804862b23cb" - integrity sha512-gThsYguFJ7XZp18GP23W6TooQaS6XlF4faFDXPCQVqlWjzEatkkQ2R6Hhv4a4qk4D21qNXirCFnI59Xhbj0KJQ== - dependencies: - "@walletconnect/jsonrpc-http-connection" "1.0.8" - "@walletconnect/jsonrpc-provider" "1.0.14" - "@walletconnect/jsonrpc-types" "1.0.4" - "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/modal" "2.6.2" - "@walletconnect/sign-client" "2.13.3" - "@walletconnect/types" "2.13.3" - "@walletconnect/universal-provider" "2.13.3" - "@walletconnect/utils" "2.13.3" + "@walletconnect/modal" "2.7.0" + "@walletconnect/sign-client" "2.17.0" + "@walletconnect/types" "2.17.0" + "@walletconnect/universal-provider" "2.17.0" + "@walletconnect/utils" "2.17.0" events "3.3.0" "@walletconnect/events@1.0.1", "@walletconnect/events@^1.0.1": @@ -5249,25 +5161,6 @@ "@walletconnect/time" "^1.0.2" events "^3.3.0" -"@walletconnect/http-connection@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/http-connection/-/http-connection-1.8.0.tgz#c19fff5c179d5180d8b974faef2621bd012adb4e" - integrity sha512-IziEr3c53qsMromK7jz0EkbKDHlryRbxXdFR+xaG+S5nfxtUdAfjzlZabvczXdDCgmTij6KbNsZAjBMqCBzACw== - dependencies: - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - eventemitter3 "4.0.7" - xhr2-cookies "1.1.0" - -"@walletconnect/iso-crypto@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/iso-crypto/-/iso-crypto-1.8.0.tgz#44ddf337c4f02837c062dbe33fa7ab36789df451" - integrity sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ== - dependencies: - "@walletconnect/crypto" "^1.0.2" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - "@walletconnect/jsonrpc-http-connection@1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz#2f4c3948f074960a3edd07909560f3be13e2c7ae" @@ -5287,7 +5180,7 @@ "@walletconnect/safe-json" "^1.0.2" events "^3.3.0" -"@walletconnect/jsonrpc-types@1.0.4": +"@walletconnect/jsonrpc-types@1.0.4", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz#ce1a667d79eadf2a2d9d002c152ceb68739c230c" integrity sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ== @@ -5295,15 +5188,7 @@ events "^3.3.0" keyvaluestorage-interface "^1.0.0" -"@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz#65e3b77046f1a7fa8347ae02bc1b841abe6f290c" - integrity sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw== - dependencies: - keyvaluestorage-interface "^1.0.0" - tslib "1.14.1" - -"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.3", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": +"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": version "1.0.8" resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz#82d0cc6a5d6ff0ecc277cb35f71402c91ad48d72" integrity sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw== @@ -5339,62 +5224,35 @@ "@walletconnect/safe-json" "^1.0.2" pino "7.11.0" -"@walletconnect/mobile-registry@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@walletconnect/mobile-registry/-/mobile-registry-1.4.0.tgz#502cf8ab87330841d794819081e748ebdef7aee5" - integrity sha512-ZtKRio4uCZ1JUF7LIdecmZt7FOLnX72RPSY7aUVu7mj7CSfxDwUn6gBuK6WGtH+NZCldBqDl5DenI5fFSvkKYw== - -"@walletconnect/modal-core@2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.6.2.tgz#d73e45d96668764e0c8668ea07a45bb8b81119e9" - integrity sha512-cv8ibvdOJQv2B+nyxP9IIFdxvQznMz8OOr/oR/AaUZym4hjXNL/l1a2UlSQBXrVjo3xxbouMxLb3kBsHoYP2CA== +"@walletconnect/modal-core@2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@walletconnect/modal-core/-/modal-core-2.7.0.tgz#73c13c3b7b0abf9ccdbac9b242254a86327ce0a4" + integrity sha512-oyMIfdlNdpyKF2kTJowTixZSo0PGlCJRdssUN/EZdA6H6v03hZnf09JnwpljZNfir2M65Dvjm/15nGrDQnlxSA== dependencies: valtio "1.11.2" -"@walletconnect/modal-ui@2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.6.2.tgz#fa57c087c57b7f76aaae93deab0f84bb68b59cf9" - integrity sha512-rbdstM1HPGvr7jprQkyPggX7rP4XiCG85ZA+zWBEX0dVQg8PpAgRUqpeub4xQKDgY7pY/xLRXSiCVdWGqvG2HA== +"@walletconnect/modal-ui@2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@walletconnect/modal-ui/-/modal-ui-2.7.0.tgz#dbbb7ee46a5a25f7d39db622706f2d197b268cbb" + integrity sha512-gERYvU7D7K1ANCN/8vUgsE0d2hnRemfAFZ2novm9aZBg7TEd/4EgB+AqbJ+1dc7GhOL6dazckVq78TgccHb7mQ== dependencies: - "@walletconnect/modal-core" "2.6.2" + "@walletconnect/modal-core" "2.7.0" lit "2.8.0" motion "10.16.2" qrcode "1.5.3" -"@walletconnect/modal@2.6.2": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.6.2.tgz#4b534a836f5039eeb3268b80be7217a94dd12651" - integrity sha512-eFopgKi8AjKf/0U4SemvcYw9zlLpx9njVN8sf6DAkowC2Md0gPU/UNEbH1Wwj407pEKnEds98pKWib1NN1ACoA== - dependencies: - "@walletconnect/modal-core" "2.6.2" - "@walletconnect/modal-ui" "2.6.2" - -"@walletconnect/qrcode-modal@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/qrcode-modal/-/qrcode-modal-1.8.0.tgz#ddd6f5c9b7ee52c16adf9aacec2a3eac4994caea" - integrity sha512-BueaFefaAi8mawE45eUtztg3ZFbsAH4DDXh1UNwdUlsvFMjqcYzLUG0xZvDd6z2eOpbgDg2N3bl6gF0KONj1dg== - dependencies: - "@walletconnect/browser-utils" "^1.8.0" - "@walletconnect/mobile-registry" "^1.4.0" - "@walletconnect/types" "^1.8.0" - copy-to-clipboard "^3.3.1" - preact "10.4.1" - qrcode "1.4.4" - -"@walletconnect/randombytes@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@walletconnect/randombytes/-/randombytes-1.0.3.tgz#e795e4918367fd1e6a2215e075e64ab93e23985b" - integrity sha512-35lpzxcHFbTN3ABefC9W+uBpNZl1GC4Wpx0ed30gibfO/y9oLdy1NznbV96HARQKSBV9J9M/rrtIvf6a23jfYw== +"@walletconnect/modal@2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@walletconnect/modal/-/modal-2.7.0.tgz#55f969796d104cce1205f5f844d8f8438b79723a" + integrity sha512-RQVt58oJ+rwqnPcIvRFeMGKuXb9qkgSmwz4noF8JZGUym3gUAzVs+uW2NQ1Owm9XOJAV+sANrtJ+VoVq1ftElw== dependencies: - "@walletconnect/encoding" "^1.0.2" - "@walletconnect/environment" "^1.0.1" - randombytes "^2.1.0" - tslib "1.14.1" + "@walletconnect/modal-core" "2.7.0" + "@walletconnect/modal-ui" "2.7.0" -"@walletconnect/relay-api@1.0.10": - version "1.0.10" - resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.10.tgz#5aef3cd07c21582b968136179aa75849dcc65499" - integrity sha512-tqrdd4zU9VBNqUaXXQASaexklv6A54yEyQQEXYOCr+Jz8Ket0dmPBDyg19LVSNUN2cipAghQc45/KVmfFJ0cYw== +"@walletconnect/relay-api@1.0.11": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@walletconnect/relay-api/-/relay-api-1.0.11.tgz#80ab7ef2e83c6c173be1a59756f95e515fb63224" + integrity sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q== dependencies: "@walletconnect/jsonrpc-types" "^1.0.2" @@ -5410,11 +5268,6 @@ tslib "1.14.1" uint8arrays "^3.0.0" -"@walletconnect/safe-json@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.0.tgz#12eeb11d43795199c045fafde97e3c91646683b2" - integrity sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg== - "@walletconnect/safe-json@1.0.2", "@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" @@ -5422,45 +5275,21 @@ dependencies: tslib "1.14.1" -"@walletconnect/sign-client@2.13.3": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.13.3.tgz#9f8c826000bf3d6ea782f7325bc87e9f260e71ce" - integrity sha512-3Pcq6trHWdBZn5X0VUFQ3zJaaqyEbMW9WNVKcZ2SakIpQAwySd08Mztvq48G98jfucdgP3tjGPbBvzHX9vJX7w== - dependencies: - "@walletconnect/core" "2.13.3" - "@walletconnect/events" "1.0.1" - "@walletconnect/heartbeat" "1.2.2" - "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/logger" "2.1.2" - "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.3" - "@walletconnect/utils" "2.13.3" - events "3.3.0" - -"@walletconnect/sign-client@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.14.0.tgz#36533ef0976a869d815624217527482c90937fc8" - integrity sha512-UrB3S3eLjPYfBLCN3WJ5u7+WcZ8kFMe/QIDqLf76Jk6TaLwkSUy563LvnSw4KW/kA+/cY1KBSdUDfX1tzYJJXg== +"@walletconnect/sign-client@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.17.0.tgz#efe811b1bb10082d964e2f0378aaa1b40f424503" + integrity sha512-sErYwvSSHQolNXni47L3Bm10ptJc1s1YoJvJd34s5E9h9+d3rj7PrhbiW9X82deN+Dm5oA8X9tC4xty1yIBrVg== dependencies: - "@walletconnect/core" "2.14.0" + "@walletconnect/core" "2.17.0" "@walletconnect/events" "1.0.1" "@walletconnect/heartbeat" "1.2.2" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "2.1.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.14.0" - "@walletconnect/utils" "2.14.0" + "@walletconnect/types" "2.17.0" + "@walletconnect/utils" "2.17.0" events "3.3.0" -"@walletconnect/socket-transport@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/socket-transport/-/socket-transport-1.8.0.tgz#9a1128a249628a0be11a0979b522fe82b44afa1b" - integrity sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ== - dependencies: - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - ws "7.5.3" - "@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" @@ -5468,22 +5297,10 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.13.3": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.13.3.tgz#0280b5c64df9a2e07752c4121eeb81dc4a59b2c2" - integrity sha512-9UdtLoQqwGFfepCPprUAXeUbKg9zyDarPRmEJVco51OWXHCOpvRgroWk54fQHDhCUIfDELjObY6XNAzNrmNYUA== - dependencies: - "@walletconnect/events" "1.0.1" - "@walletconnect/heartbeat" "1.2.2" - "@walletconnect/jsonrpc-types" "1.0.4" - "@walletconnect/keyvaluestorage" "1.1.1" - "@walletconnect/logger" "2.1.2" - events "3.3.0" - -"@walletconnect/types@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.14.0.tgz#af3d4799b8ac5d166251af12bc024276f82f9b91" - integrity sha512-vevMi4jZLJ55vLuFOicQFmBBbLyb+S0sZS4IsaBdZkQflfGIq34HkN13c/KPl4Ye0aoR4/cUcUSitmGIzEQM5g== +"@walletconnect/types@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.17.0.tgz#20eda5791e3172f8ab9146caa3f317701d4b3232" + integrity sha512-i1pn9URpvt9bcjRDkabuAmpA9K7mzyKoLJlbsAujRVX7pfaG7wur7u9Jz0bk1HxvuABL5LHNncTnVKSXKQ5jZA== dependencies: "@walletconnect/events" "1.0.1" "@walletconnect/heartbeat" "1.2.2" @@ -5492,125 +5309,50 @@ "@walletconnect/logger" "2.1.2" events "3.3.0" -"@walletconnect/types@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-1.8.0.tgz#3f5e85b2d6b149337f727ab8a71b8471d8d9a195" - integrity sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg== - -"@walletconnect/universal-provider@2.13.3": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.13.3.tgz#7c2a89035168cfe1cd58a31710245e1a2e64a8aa" - integrity sha512-2tuV2d8AdB4Fg/uMs8IdNHrjYy1Tz1uT5kzaT8X1/wx5DHHa/oaheoY5kDZHI0L1oNIg/OlM0/ovonGIcI5ddw== - dependencies: - "@walletconnect/jsonrpc-http-connection" "1.0.8" - "@walletconnect/jsonrpc-provider" "1.0.14" - "@walletconnect/jsonrpc-types" "1.0.4" - "@walletconnect/jsonrpc-utils" "1.0.8" - "@walletconnect/logger" "2.1.2" - "@walletconnect/sign-client" "2.13.3" - "@walletconnect/types" "2.13.3" - "@walletconnect/utils" "2.13.3" - events "3.3.0" - -"@walletconnect/universal-provider@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.14.0.tgz#39d029be80374894b5f4249b76282dd9211d8b9f" - integrity sha512-Mr8uoTmD6H0+Hh+3gxBu4l3T2uP/nNPR02sVtwEujNum++F727mMk+ifPRIpkVo21V/bvXFEy8sHTs5hqyq5iA== +"@walletconnect/universal-provider@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/universal-provider/-/universal-provider-2.17.0.tgz#c9d4bbd9b8f0e41b500b2488ccbc207dc5f7a170" + integrity sha512-d3V5Be7AqLrvzcdMZSBS8DmGDRdqnyLk1DWmRKAGgR6ieUWykhhUKlvfeoZtvJrIXrY7rUGYpH1X41UtFkW5Pw== dependencies: "@walletconnect/jsonrpc-http-connection" "1.0.8" "@walletconnect/jsonrpc-provider" "1.0.14" "@walletconnect/jsonrpc-types" "1.0.4" "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "2.1.2" - "@walletconnect/sign-client" "2.14.0" - "@walletconnect/types" "2.14.0" - "@walletconnect/utils" "2.14.0" + "@walletconnect/sign-client" "2.17.0" + "@walletconnect/types" "2.17.0" + "@walletconnect/utils" "2.17.0" events "3.3.0" -"@walletconnect/utils@2.13.3": - version "2.13.3" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.13.3.tgz#500d88342c193ce92ab9d2fae3bd343be71821b2" - integrity sha512-hjyyNhnhTCezGNr6OCfKRzqRsiak+p+YP57iRo1Tsf222fsj/9JD++MP97YiDwc4e4xXaZp/boiLB+8hJHsCog== - dependencies: - "@stablelib/chacha20poly1305" "1.0.1" - "@stablelib/hkdf" "1.0.1" - "@stablelib/random" "1.0.2" - "@stablelib/sha256" "1.0.1" - "@stablelib/x25519" "1.0.3" - "@walletconnect/relay-api" "1.0.10" - "@walletconnect/safe-json" "1.0.2" - "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.13.3" - "@walletconnect/window-getters" "1.0.1" - "@walletconnect/window-metadata" "1.0.1" - detect-browser "5.3.0" - query-string "7.1.3" - uint8arrays "3.1.0" - -"@walletconnect/utils@2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.14.0.tgz#48493ffe1e902815fda3cbd5cc5409288a066d35" - integrity sha512-vRVomYQEtEAyCK2c5bzzEvtgxaGGITF8mWuIL+WYSAMyEJLY97mirP2urDucNwcUczwxUgI+no9RiNFbUHreQQ== +"@walletconnect/utils@2.17.0": + version "2.17.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.17.0.tgz#02b3af0b80d0c1a994d692d829d066271b04d071" + integrity sha512-1aeQvjwsXy4Yh9G6g2eGmXrEl+BzkNjHRdCrGdMYqFTFa8ROEJfTGsSH3pLsNDlOY94CoBUvJvM55q/PMoN/FQ== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" "@stablelib/random" "1.0.2" "@stablelib/sha256" "1.0.1" "@stablelib/x25519" "1.0.3" - "@walletconnect/relay-api" "1.0.10" + "@walletconnect/relay-api" "1.0.11" + "@walletconnect/relay-auth" "1.0.4" "@walletconnect/safe-json" "1.0.2" "@walletconnect/time" "1.0.2" - "@walletconnect/types" "2.14.0" + "@walletconnect/types" "2.17.0" "@walletconnect/window-getters" "1.0.1" "@walletconnect/window-metadata" "1.0.1" detect-browser "5.3.0" + elliptic "^6.5.7" query-string "7.1.3" uint8arrays "3.1.0" -"@walletconnect/utils@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-1.8.0.tgz#2591a197c1fa7429941fe428876088fda6632060" - integrity sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA== - dependencies: - "@walletconnect/browser-utils" "^1.8.0" - "@walletconnect/encoding" "^1.0.1" - "@walletconnect/jsonrpc-utils" "^1.0.3" - "@walletconnect/types" "^1.8.0" - bn.js "4.11.8" - js-sha3 "0.8.0" - query-string "6.13.5" - -"@walletconnect/web3-provider@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@walletconnect/web3-provider/-/web3-provider-1.8.0.tgz#e90d903f4c609b7158ecb5f0f41df121e93b56b5" - integrity sha512-lqqEO0oRmCehH+c8ZPk3iH7I7YtbzmkWd58/Or2AgWAl869JamzndKCD3sTlNsPRQLxxPpraHQqzur7uclLWvg== - dependencies: - "@walletconnect/client" "^1.8.0" - "@walletconnect/http-connection" "^1.8.0" - "@walletconnect/qrcode-modal" "^1.8.0" - "@walletconnect/types" "^1.8.0" - "@walletconnect/utils" "^1.8.0" - web3-provider-engine "16.0.1" - -"@walletconnect/window-getters@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.0.tgz#1053224f77e725dfd611c83931b5f6c98c32bfc8" - integrity sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA== - -"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.0", "@walletconnect/window-getters@^1.0.1": +"@walletconnect/window-getters@1.0.1", "@walletconnect/window-getters@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-getters/-/window-getters-1.0.1.tgz#f36d1c72558a7f6b87ecc4451fc8bd44f63cbbdc" integrity sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q== dependencies: tslib "1.14.1" -"@walletconnect/window-metadata@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.0.tgz#93b1cc685e6b9b202f29c26be550fde97800c4e5" - integrity sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA== - dependencies: - "@walletconnect/window-getters" "^1.0.0" - "@walletconnect/window-metadata@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz#2124f75447b7e989e4e4e1581d55d25bc75f7be5" @@ -5806,20 +5548,6 @@ abortcontroller-polyfill@^1.7.3: resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== -abstract-leveldown@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" - integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== - dependencies: - xtend "~4.0.0" - -abstract-leveldown@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" - integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== - dependencies: - xtend "~4.0.0" - accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" @@ -5870,21 +5598,16 @@ acorn@^8.0.4, acorn@^8.1.0, acorn@^8.8.0, acorn@^8.8.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -acorn@^8.11.3: - version "8.12.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c" - integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw== +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -aes-js@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" - integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== - agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -5970,11 +5693,6 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -5985,7 +5703,7 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -6276,13 +5994,6 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== -async-eventemitter@^0.2.2: - version "0.2.4" - resolved "https://registry.yarnpkg.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" - integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== - dependencies: - async "^2.4.0" - async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" @@ -6300,18 +6011,6 @@ async-validator@^4.1.0: resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== -async@^1.4.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== - -async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -6346,12 +6045,7 @@ autoprefixer@10.4.13: picocolors "^1.0.0" postcss-value-parser "^4.2.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -available-typed-arrays@^1.0.7: +available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== @@ -6463,30 +6157,6 @@ babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0: cosmiconfig "^7.0.0" resolve "^1.19.0" -babel-plugin-polyfill-corejs2@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" - integrity sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-define-polyfill-provider" "^0.3.3" - semver "^6.1.1" - -babel-plugin-polyfill-corejs3@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz#56ad88237137eade485a71b52f72dbed57c6230a" - integrity sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - core-js-compat "^3.25.1" - -babel-plugin-polyfill-regenerator@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz#390f91c38d90473592ed43351e801a9d3e0fd747" - integrity sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.3" - babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" @@ -6564,13 +6234,6 @@ babel-preset-jest@^29.5.0: babel-plugin-jest-hoist "^29.5.0" babel-preset-current-node-syntax "^1.0.0" -backoff@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" - integrity sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA== - dependencies: - precond "0.2" - bail@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" @@ -6661,9 +6324,9 @@ bin-links@^4.0.3: write-file-atomic "^5.0.0" binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bl@^4.1.0: version "4.1.0" @@ -6689,16 +6352,16 @@ bn.js@4.11.6: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== -bn.js@4.11.8: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.11.6, bn.js@^4.11.8: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +bn.js@^4.11.9: + version "4.12.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.1.tgz#215741fe3c9dba2d7e12c001d0cfdbae43975ba7" + integrity sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg== + bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" @@ -6769,7 +6432,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.1, braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: +braces@^3.0.1, braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== @@ -6793,7 +6456,7 @@ browserify-aes@^1.2.0: inherits "^2.0.1" safe-buffer "^5.0.1" -browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5: +browserslist@^4.21.3, browserslist@^4.21.4: version "4.21.5" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== @@ -6853,35 +6516,12 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -btoa@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/btoa/-/btoa-1.2.1.tgz#01a9909f8b2c93f6bf680ba26131eb30f7fa3d73" - integrity sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g== - -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== - -buffer-from@^1.0.0, buffer-from@^1.1.1: +buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -6904,7 +6544,7 @@ buffer@6.0.3, buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -buffer@^5.0.5, buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.0.5, buffer@^5.5.0, buffer@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -6968,7 +6608,7 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" -call-bind@^1.0.0, call-bind@^1.0.2: +call-bind@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== @@ -6976,7 +6616,7 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== @@ -7033,11 +6673,16 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001629: +caniuse-lite@^1.0.30001426, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001629: version "1.0.30001651" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz#52de59529e8b02b1aedcaaf5c05d9e23c0c28138" integrity sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg== +caniuse-lite@^1.0.30001579: + version "1.0.30001685" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz#2d10d36c540a9a5d47ad6ab9e1ed5f61fdeadd8c" + integrity sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA== + capital-case@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" @@ -7214,13 +6859,6 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -checkpoint-store@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" - integrity sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg== - dependencies: - functional-red-black-tree "^1.0.1" - cheerio-select@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4" @@ -7433,15 +7071,6 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -7472,7 +7101,7 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clone@^2.0.0, clone@^2.1.1: +clone@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== @@ -7633,10 +7262,10 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -confbox@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" - integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== config-chain@^1.1.13: version "1.1.13" @@ -7699,10 +7328,10 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-es@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.1.0.tgz#68f8d9f48aeb5a534f3896f80e792760d3d20def" - integrity sha512-L2rLOcK0wzWSfSDA33YR+PUHDG10a8px7rUHKWbGLP4YfbsMed2KFUw5fczvDPbT98DDe3LEzviswl810apTEw== +cookie-es@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.2.2.tgz#18ceef9eb513cac1cb6c14bcbf8bdb2679b34821" + integrity sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg== cookie-signature@1.0.6: version "1.0.6" @@ -7714,11 +7343,6 @@ cookie@0.6.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== -cookiejar@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" - integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== - copy-anything@^2.0.1: version "2.0.6" resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480" @@ -7726,20 +7350,13 @@ copy-anything@^2.0.1: dependencies: is-what "^3.14.1" -copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.2.0: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== dependencies: toggle-selection "^1.0.6" -core-js-compat@^3.25.1: - version "3.30.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.30.2.tgz#83f136e375babdb8c80ad3c22d67c69098c1dd8b" - integrity sha512-nriW1nuJjUgvkEjIot1Spwakz52V9YkYHZAQG6A1eCgC8AA1p0zngrQEP9R0+V6hji5XilWKG1Bd0YRppmGimA== - dependencies: - browserslist "^4.21.5" - core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -7817,22 +7434,14 @@ create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-fetch@^2.1.0: - version "2.2.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" - integrity sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA== - dependencies: - node-fetch "^2.6.7" - whatwg-fetch "^2.0.4" - -cross-fetch@^3.0.4: +cross-fetch@^3.0.4, cross-fetch@^3.1.4: version "3.1.8" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== dependencies: node-fetch "^2.6.12" -cross-fetch@^3.1.4, cross-fetch@^3.1.5: +cross-fetch@^3.1.5: version "3.1.6" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.6.tgz#bae05aa31a4da760969756318feeee6e70f15d6c" integrity sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g== @@ -7853,7 +7462,7 @@ cross-inspect@1.0.0: dependencies: tslib "^2.4.0" -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -7862,10 +7471,21 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -crossws@^0.2.0, crossws@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.2.4.tgz#82a8b518bff1018ab1d21ced9e35ffbe1681ad03" - integrity sha512-DAxroI2uSOgUKLz00NX6A8U/8EE3SZHmIND+10jkVSaypvyt57J5JEOxAQOL6lQxyzi/wZbTIwssU1uy69h5Vg== +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +"crossws@>=0.2.0 <0.4.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.1.tgz#7980e0b6688fe23286661c3ab8deeccbaa05ca86" + integrity sha512-HsZgeVYaG+b5zA+9PbIPGq4+J/CJynJuearykPsXx4V/eMhyQ5EDVg3Ak2FBZtVXCiOLu/U7IiwDHTr9MA+IKw== + dependencies: + uncrypto "^0.1.3" crypto-addr-codec@^0.1.7: version "0.1.7" @@ -8119,11 +7739,11 @@ debug@^3.2.6, debug@^3.2.7: ms "^2.1.1" debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: - version "4.3.5" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" - integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" decamelize@^1.1.1, decamelize@^1.2.0: version "1.2.0" @@ -8257,13 +7877,6 @@ defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -deferred-leveldown@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" - integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== - dependencies: - abstract-leveldown "~2.6.0" - define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -8273,11 +7886,6 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - define-lazy-prop@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" @@ -8305,7 +7913,7 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== -defu@^6.1.3, defu@^6.1.4: +defu@^6.1.4: version "6.1.4" resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== @@ -8340,11 +7948,6 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== -detect-browser@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97" - integrity sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA== - detect-browser@5.3.0, detect-browser@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" @@ -8602,14 +8205,14 @@ duplexer@^0.1.2: integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== duplexify@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" - integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== + version "4.1.3" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.3.tgz#a07e1c0d0a2c001158563d32592ba58bddb0236f" + integrity sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA== dependencies: end-of-stream "^1.4.1" inherits "^2.0.3" readable-stream "^3.1.1" - stream-shift "^1.0.0" + stream-shift "^1.0.2" eastasianwidth@^0.2.0: version "0.2.0" @@ -8631,14 +8234,15 @@ ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer "^5.0.1" -eciesjs@^0.3.15: - version "0.3.19" - resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.3.19.tgz#a22e9e1efe3fdedec02c828e2632ae0d4a073676" - integrity sha512-b+PkRDZ3ym7HEcnbxc22CMVCpgsnr8+gGgST3U5PtgeX1luvINgfXW7efOyUtmn/jFtA/lg5ywBi/Uazf4oeaA== +eciesjs@^0.4.11: + version "0.4.12" + resolved "https://registry.yarnpkg.com/eciesjs/-/eciesjs-0.4.12.tgz#0ce482454953592e07b79b4824751f3b5c508b56" + integrity sha512-DGejvMCihsRAmKRFQiL6KZDE34vWVd0gvXlykFq1aEzJy/rD65AVyAIUZKZOvgvaP9ATQRcHGEZV5DfgrgjA4w== dependencies: - "@types/secp256k1" "^4.0.6" - futoin-hkdf "^1.5.3" - secp256k1 "^5.0.0" + "@ecies/ciphers" "^0.2.1" + "@noble/ciphers" "^1.0.0" + "@noble/curves" "^1.6.0" + "@noble/hashes" "^1.5.0" editorconfig@^0.15.3: version "0.15.3" @@ -8670,7 +8274,7 @@ electron-to-chromium@^1.4.796: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.816.tgz#3624649d1e7fde5cdbadf59d31a524245d8ee85f" integrity sha512-EKH5X5oqC6hLmiS7/vYtZHZFTNdhsYG5NVPRN6Yn0kQHNBlT59+xSM8HBy66P5fxWpKgZbPqb+diC64ng295Jw== -elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.4: +elliptic@6.5.4, elliptic@^6.4.0: version "6.5.4" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -8683,16 +8287,24 @@ elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +elliptic@^6.5.4, elliptic@^6.5.7: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + emittery@^0.10.2: version "0.10.2" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -8720,21 +8332,21 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.0, end-of-stream@^1.4.1, end-of-stream@ dependencies: once "^1.4.0" -engine.io-client@~6.5.2: - version "6.5.4" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.4.tgz#b8bc71ed3f25d0d51d587729262486b4b33bd0d0" - integrity sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ== +engine.io-client@~6.6.1: + version "6.6.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.2.tgz#e0a09e1c90effe5d6264da1c56d7281998f1e50b" + integrity sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" engine.io-parser "~5.2.1" ws "~8.17.1" - xmlhttprequest-ssl "~2.0.0" + xmlhttprequest-ssl "~2.1.1" engine.io-parser@~5.2.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.2.tgz#37b48e2d23116919a3453738c5720455e64e1c49" - integrity sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw== + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== enhanced-resolve@^5.12.0: version "5.14.1" @@ -8754,7 +8366,7 @@ entities@^4.2.0, entities@^4.4.0, entities@^4.5.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== -errno@^0.1.1, errno@~0.1.1: +errno@^0.1.1: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== @@ -9025,9 +8637,9 @@ esbuild@^0.17.10: "@esbuild/win32-x64" "0.17.19" escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escalade@^3.1.2: version "3.1.2" @@ -9049,16 +8661,16 @@ escape-latex@^1.2.0: resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1" integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw== -escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" - integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -9340,18 +8952,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eth-block-tracker@^4.4.2: - version "4.4.3" - resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz#766a0a0eb4a52c867a28328e9ae21353812cf626" - integrity sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw== - dependencies: - "@babel/plugin-transform-runtime" "^7.5.5" - "@babel/runtime" "^7.5.5" - eth-query "^2.1.0" - json-rpc-random-id "^1.0.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - eth-block-tracker@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-7.1.0.tgz#dfc16085c6817cc30caabba381deb8d204c1c766" @@ -9371,18 +8971,6 @@ eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: idna-uts46-hx "^2.3.1" js-sha3 "^0.5.7" -eth-json-rpc-filters@^4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.2.tgz#eb35e1dfe9357ace8a8908e7daee80b2cd60a10d" - integrity sha512-DGtqpLU7bBg63wPMWg1sCpkKCf57dJ+hj/k3zF26anXMzkmtSBDExL8IhUu7LUd34f0Zsce3PYNO2vV2GaTzaw== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - async-mutex "^0.2.6" - eth-json-rpc-middleware "^6.0.0" - eth-query "^2.1.2" - json-rpc-engine "^6.1.0" - pify "^5.0.0" - eth-json-rpc-filters@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/eth-json-rpc-filters/-/eth-json-rpc-filters-6.0.1.tgz#0b3e370f017f5c6f58d3e7bd0756d8099ed85c56" @@ -9394,33 +8982,6 @@ eth-json-rpc-filters@^6.0.0: json-rpc-engine "^6.1.0" pify "^5.0.0" -eth-json-rpc-infura@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-5.1.0.tgz#e6da7dc47402ce64c54e7018170d89433c4e8fb6" - integrity sha512-THzLye3PHUSGn1EXMhg6WTLW9uim7LQZKeKaeYsS9+wOBcamRiCQVGHa6D2/4P0oS0vSaxsBnU/J6qvn0MPdow== - dependencies: - eth-json-rpc-middleware "^6.0.0" - eth-rpc-errors "^3.0.0" - json-rpc-engine "^5.3.0" - node-fetch "^2.6.0" - -eth-json-rpc-middleware@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-6.0.0.tgz#4fe16928b34231a2537856f08a5ebbc3d0c31175" - integrity sha512-qqBfLU2Uq1Ou15Wox1s+NX05S9OcAEL4JZ04VZox2NS0U+RtCMjSxzXhLFWekdShUPZ+P8ax3zCO2xcPrp6XJQ== - dependencies: - btoa "^1.2.1" - clone "^2.1.1" - eth-query "^2.1.2" - eth-rpc-errors "^3.0.0" - eth-sig-util "^1.4.2" - ethereumjs-util "^5.1.2" - json-rpc-engine "^5.3.0" - json-stable-stringify "^1.0.1" - node-fetch "^2.6.1" - pify "^3.0.0" - safe-event-emitter "^1.0.1" - eth-lib@0.2.8: version "0.2.8" resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" @@ -9442,7 +9003,7 @@ eth-lib@^0.1.26: ws "^3.0.0" xhr-request-promise "^0.1.2" -eth-query@^2.1.0, eth-query@^2.1.2: +eth-query@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" integrity sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA== @@ -9450,13 +9011,6 @@ eth-query@^2.1.0, eth-query@^2.1.2: json-rpc-random-id "^1.0.0" xtend "^4.0.1" -eth-rpc-errors@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz#d7b22653c70dbf9defd4ef490fd08fe70608ca10" - integrity sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg== - dependencies: - fast-safe-stringify "^2.0.6" - eth-rpc-errors@^4.0.2, eth-rpc-errors@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" @@ -9464,14 +9018,6 @@ eth-rpc-errors@^4.0.2, eth-rpc-errors@^4.0.3: dependencies: fast-safe-stringify "^2.0.6" -eth-sig-util@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" - integrity sha512-iNZ576iTOGcfllftB73cPB5AN+XUQAT/T8xzsILsghXC1o8gJUqe3RHlcDqagu+biFpYQ61KQrZZJza8eRSYqw== - dependencies: - ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" - ethereumjs-util "^5.1.1" - ethereum-block-by-date@1.4.6: version "1.4.6" resolved "https://registry.yarnpkg.com/ethereum-block-by-date/-/ethereum-block-by-date-1.4.6.tgz#80227834ab8a5ebd3318ba58b985b07d47731ba8" @@ -9486,16 +9032,6 @@ ethereum-bloom-filters@^1.0.6: dependencies: js-sha3 "^0.8.0" -ethereum-common@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" - integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== - -ethereum-common@^0.0.18: - version "0.0.18" - resolved "https://registry.yarnpkg.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" - integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== - ethereum-cryptography@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" @@ -9527,91 +9063,6 @@ ethereum-cryptography@^2.0.0: "@scure/bip32" "1.4.0" "@scure/bip39" "1.3.0" -"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": - version "0.6.8" - resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0" - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-account@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" - integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== - dependencies: - ethereumjs-util "^5.0.0" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-block@^1.2.2: - version "1.7.1" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" - integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== - dependencies: - async "^2.0.1" - ethereum-common "0.2.0" - ethereumjs-tx "^1.2.2" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-block@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" - integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== - dependencies: - async "^2.0.1" - ethereumjs-common "^1.5.0" - ethereumjs-tx "^2.1.1" - ethereumjs-util "^5.0.0" - merkle-patricia-tree "^2.1.2" - -ethereumjs-common@^1.1.0, ethereumjs-common@^1.5.0: - version "1.5.2" - resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" - integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== - -ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2: - version "1.3.7" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" - integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== - dependencies: - ethereum-common "^0.0.18" - ethereumjs-util "^5.0.0" - -ethereumjs-tx@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" - integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== - dependencies: - ethereumjs-common "^1.5.0" - ethereumjs-util "^6.0.0" - -ethereumjs-util@^5.0.0, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.5: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" - integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== - dependencies: - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "^0.1.3" - rlp "^2.0.0" - safe-buffer "^5.1.1" - -ethereumjs-util@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" @@ -9623,23 +9074,6 @@ ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereum ethereum-cryptography "^0.1.3" rlp "^2.2.4" -ethereumjs-vm@^2.3.4: - version "2.6.0" - resolved "https://registry.yarnpkg.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" - integrity sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw== - dependencies: - async "^2.1.2" - async-eventemitter "^0.2.2" - ethereumjs-account "^2.0.3" - ethereumjs-block "~2.2.0" - ethereumjs-common "^1.1.0" - ethereumjs-util "^6.0.0" - fake-merkle-patricia-tree "^1.0.1" - functional-red-black-tree "^1.0.1" - merkle-patricia-tree "^2.3.2" - rustbn.js "~0.2.0" - safe-buffer "^5.1.1" - ethers@^4.0.32, ethers@^4.0.45: version "4.0.49" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" @@ -9699,14 +9133,6 @@ ethjs-unit@0.1.6: bn.js "4.11.6" number-to-bn "1.7.0" -ethjs-util@0.1.6, ethjs-util@^0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - event-emitter@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" @@ -9720,7 +9146,7 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter2@^6.4.7: +eventemitter2@^6.4.9: version "6.4.9" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== @@ -9730,11 +9156,6 @@ eventemitter3@4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== -eventemitter3@4.0.7, eventemitter3@^4.0.1, eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - eventemitter3@5.0.1, eventemitter3@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" @@ -9745,7 +9166,12 @@ eventemitter3@^2.0.3: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" integrity sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg== -events@3.3.0, events@^3.0.0, events@^3.3.0: +eventemitter3@^4.0.1, eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@3.3.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -9926,13 +9352,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fake-merkle-patricia-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" - integrity sha512-Tgq37lkc9pUIgIKw5uitNUKcgcYL3R6JvXtKQbOf/ZSavXbidsksgp/pAY6p//uhw0I4yoMsvTSovvVIsk/qxA== - dependencies: - checkpoint-store "^1.1.0" - fast-check@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.1.1.tgz#72c5ae7022a4e86504762e773adfb8a5b0b01252" @@ -10009,7 +9428,12 @@ fast-querystring@^1.1.1: dependencies: fast-decode-uri-component "^1.0.1" -fast-redact@^3.0.0, fast-redact@^3.1.1: +fast-redact@^3.0.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.5.0.tgz#e9ea02f7e57d0cd8438180083e93077e496285e4" + integrity sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A== + +fast-redact@^3.1.1: version "3.2.0" resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.2.0.tgz#b1e2d39bc731376d28bde844454fa23e26919987" integrity sha512-zaTadChr+NekyzallAMXATXLOR8MNx3zqpZ0MUF2aGf4EathnG0f32VLODNlY8IuGY3HoRO2L6/6fSzNsLaHIw== @@ -10339,17 +9763,17 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.1, fsevents@~2.3.2: +fsevents@^2.3.2, fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.2: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -10374,21 +9798,11 @@ function.prototype.name@^1.1.6: es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -futoin-hkdf@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/futoin-hkdf/-/futoin-hkdf-1.5.3.tgz#6c8024f2e1429da086d4e18289ef2239ad33ee35" - integrity sha512-SewY5KdMpaoCeh7jachEWFsh1nNlaDjNHZXWqL5IGwtpEYHTgkr2+AMCgNwKWkcc0wpSYrZfR7he4WdmHFtDxQ== - gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -10404,17 +9818,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" - integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - -get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -10425,6 +9829,16 @@ get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.1.1, get-intrinsic@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -10624,11 +10038,11 @@ globrex@^0.1.2: integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.1.0.tgz#df8f0839c2d48caefc32a025a49294d39606c912" + integrity sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA== dependencies: - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.4" got@12.1.0: version "12.1.0" @@ -10725,21 +10139,21 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" -h3@^1.10.2, h3@^1.11.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.12.0.tgz#9d7f05f08a997d263e484b02436cb027df3026d8" - integrity sha512-Zi/CcNeWBXDrFNlV0hUBJQR9F7a96RjMeAZweW/ZWkR9fuXrMcvKnSA63f/zZ9l0GgQOZDVHGvXivNN9PWOwhA== +h3@^1.12.0, h3@^1.13.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.13.0.tgz#b5347a8936529794b6754b440e26c0ab8a60dceb" + integrity sha512-vFEAu/yf8UMUcB4s43OaDaigcqpQd14yanmOsn+NcRX3/guSKncyE2rOYhq8RIchgJrPSs/QiIddnTTR1ddiAg== dependencies: - cookie-es "^1.1.0" - crossws "^0.2.4" + cookie-es "^1.2.2" + crossws ">=0.2.0 <0.4.0" defu "^6.1.4" destr "^2.0.3" - iron-webcrypto "^1.1.1" - ohash "^1.1.3" + iron-webcrypto "^1.2.1" + ohash "^1.1.4" radix3 "^1.1.2" - ufo "^1.5.3" + ufo "^1.5.4" uncrypto "^0.1.3" - unenv "^1.9.0" + unenv "^1.10.0" har-schema@^2.0.0: version "2.0.0" @@ -10784,9 +10198,11 @@ has-property-descriptors@^1.0.2: es-define-property "^1.0.0" has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.1.0.tgz#deb10494cbbe8809bce168a3b961f42969f5ed43" + integrity sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q== + dependencies: + call-bind "^1.0.7" has-proto@^1.0.3: version "1.0.3" @@ -10798,14 +10214,7 @@ has-symbols@^1.0.2, has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - -has-tostringtag@^1.0.2: +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== @@ -10813,11 +10222,9 @@ has-tostringtag@^1.0.2: has-symbols "^1.0.3" has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== hash-base@^3.0.0: version "3.1.0" @@ -11225,20 +10632,6 @@ husky@^7.0.0: resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== -i18next-browser-languagedetector@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.1.0.tgz#01876fac51f86b78975e79b48ccb62e2313a2d7d" - integrity sha512-cr2k7u1XJJ4HTOjM9GyOMtbOA47RtUoWRAtt52z43r3AoMs2StYKyjS3URPhzHaf+mn10hY9dZWamga5WPQjhA== - dependencies: - "@babel/runtime" "^7.19.4" - -i18next@23.11.5: - version "23.11.5" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-23.11.5.tgz#d71eb717a7e65498d87d0594f2664237f9e361ef" - integrity sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA== - dependencies: - "@babel/runtime" "^7.23.2" - iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -11280,11 +10673,6 @@ image-size@~0.5.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== -immediate@^3.2.3: - version "3.3.0" - resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" - integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== - immer@^9.0.21: version "9.0.21" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176" @@ -11339,7 +10727,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -11427,7 +10815,7 @@ intl-messageformat@^9.13.0: "@formatjs/icu-messageformat-parser" "2.1.0" tslib "^2.1.0" -invariant@2.2.4, invariant@^2.2.4: +invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -11444,7 +10832,7 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -iron-webcrypto@^1.1.1: +iron-webcrypto@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f" integrity sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg== @@ -11572,7 +10960,7 @@ is-decimal@^2.0.0: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== -is-docker@^2.0.0, is-docker@^2.1.1: +is-docker@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -11594,11 +10982,6 @@ is-finalizationregistry@^1.0.2: dependencies: call-bind "^1.0.2" -is-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" - integrity sha512-XoFPJQmsAShb3jEQRfzf2rqXavq7fIqF/jOekp308JlThqrODnMpweVSGilKTCXELfLhltGP2AGgbQGVP8F1dg== - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -11606,11 +10989,6 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -11801,7 +11179,14 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.13, is-typed-array@^1.1.3: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + +is-typed-array@^1.1.9: version "1.1.10" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== @@ -11812,14 +11197,7 @@ is-typed-array@^1.1.10, is-typed-array@^1.1.3, is-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.0" -is-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-typedarray@1.0.0, is-typedarray@^1.0.0, is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== @@ -11919,12 +11297,7 @@ is64bit@^2.0.0: dependencies: system-architecture "^0.1.0" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isarray@^2.0.1, isarray@^2.0.5: +isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== @@ -11939,14 +11312,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isomorphic-unfetch@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" - integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== - dependencies: - node-fetch "^2.6.1" - unfetch "^4.2.0" - isomorphic-ws@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" @@ -12555,11 +11920,16 @@ jiti@^1.17.1: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.18.2.tgz#80c3ef3d486ebf2450d9335122b32d121f2a83cd" integrity sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg== -jiti@^1.18.2, jiti@^1.21.0: +jiti@^1.18.2: version "1.21.6" resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.6.tgz#6c7f7398dd4b3142767f9a168af2f317a428d268" integrity sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w== +jiti@^2.1.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.1.tgz#4de9766ccbfa941d9b6390d2b159a4b295a52e6b" + integrity sha512-yPBThwecp1wS9DmoA4x4KR2h3QoslacnDR8ypuFM962kI4/456Iy1oHx2RAgh4jfZNdn0bctsdadceiBUgpU1g== + joi@17.9.1: version "17.9.1" resolved "https://registry.yarnpkg.com/joi/-/joi-17.9.1.tgz#74899b9fa3646904afa984a11df648eca66c9018" @@ -12683,14 +12053,6 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json-rpc-engine@^5.3.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz#75758609d849e1dba1e09021ae473f3ab63161e5" - integrity sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g== - dependencies: - eth-rpc-errors "^3.0.0" - safe-event-emitter "^1.0.1" - json-rpc-engine@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" @@ -12732,13 +12094,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" - integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== - dependencies: - jsonify "^0.0.1" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -12794,11 +12149,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jsonwebtoken@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d" @@ -12837,18 +12187,18 @@ jsx-ast-utils@^3.3.5: object.assign "^4.1.4" object.values "^1.1.6" -juice-sdk-core@^11.0.0-alpha: - version "11.0.0-alpha" - resolved "https://registry.yarnpkg.com/juice-sdk-core/-/juice-sdk-core-11.0.0-alpha.tgz#dd0228158de3c3a2799ea6ba3b1f22c8c0635d60" - integrity sha512-wqKAb9f88579CiTZP6MNb08TOStQ4OqgLQYh7cwmONcpon09+A9tyHPCxhgKjGHGevzF80Wv2Z0dPjgujMRI2Q== +juice-sdk-core@^11.5.0-alpha: + version "11.5.0-alpha" + resolved "https://registry.yarnpkg.com/juice-sdk-core/-/juice-sdk-core-11.5.0-alpha.tgz#40ae9e4a44a86dc74777842bb18b30ae36373344" + integrity sha512-0T/v1OHsG99tO/Zo5pY1tbJzKjh0KB4bEMLAnJSRNOeb6hAKiS77xgcth22uYRRpZc4OLZWFjszR+FC2dAKQUg== dependencies: bs58 "^5.0.0" fpnum "^1.0.0" -juice-sdk-react@^11.0.0-alpha: - version "11.0.0-alpha" - resolved "https://registry.yarnpkg.com/juice-sdk-react/-/juice-sdk-react-11.0.0-alpha.tgz#15b93be75d80e9e83a0f45b4cc8c81d3f1828e49" - integrity sha512-G0zCPMCozfAK0Y9mxGMtMOYW8Bm3ml5bEEr/pKFbrrxIs+sEUnK4f5CZWiaA6fZlN8QnUbXbIRteFjv+RB2Yzg== +juice-sdk-react@^11.6.0-alpha: + version "11.6.0-alpha" + resolved "https://registry.yarnpkg.com/juice-sdk-react/-/juice-sdk-react-11.6.0-alpha.tgz#5ddc6a42f2586ed3b694bde5b8ad76b9ad788b9c" + integrity sha512-9ji5COnA0aaqXQOnqbqpohaOXPE7tTNz9J9FlA2d4jG9wlXjYDJrpCAB42g1p1Ojvel6zsLLzuY7aT25UrYFjg== juice@^10.0.0: version "10.0.0" @@ -12971,56 +12321,6 @@ less@4.1.2: needle "^2.5.2" source-map "~0.6.0" -level-codec@~7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" - integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== - -level-errors@^1.0.3: - version "1.1.2" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" - integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== - dependencies: - errno "~0.1.1" - -level-errors@~1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" - integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== - dependencies: - errno "~0.1.1" - -level-iterator-stream@~1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" - integrity sha512-1qua0RHNtr4nrZBgYlpV0qHHeHpcRRWTxEZJ8xsemoHAXNL5tbooh4tPEEqIqsbWCAJBmUmkwYK/sW5OrFjWWw== - dependencies: - inherits "^2.0.1" - level-errors "^1.0.3" - readable-stream "^1.0.33" - xtend "^4.0.0" - -level-ws@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" - integrity sha512-XUTaO/+Db51Uiyp/t7fCMGVFOTdtLS/NIACxE/GHsij15mKzxksZifKVjlXDF41JMUP/oM1Oc4YNGdKnc3dVLw== - dependencies: - readable-stream "~1.0.15" - xtend "~2.1.1" - -levelup@^1.2.1: - version "1.3.9" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" - integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== - dependencies: - deferred-leveldown "~1.2.1" - level-codec "~7.0.0" - level-errors "~1.0.3" - level-iterator-stream "~1.3.0" - prr "~1.0.1" - semver "~5.4.1" - xtend "~4.0.0" - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -13071,27 +12371,27 @@ lint-staged@^13.0.3: string-argv "^0.3.1" yaml "^2.2.2" -listhen@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.7.2.tgz#66b81740692269d5d8cafdc475020f2fc51afbae" - integrity sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g== +listhen@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.9.0.tgz#59355f7e4fc1eefda6bc494ae7e9ed13aa7658ef" + integrity sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg== dependencies: "@parcel/watcher" "^2.4.1" "@parcel/watcher-wasm" "^2.4.1" citty "^0.1.6" clipboardy "^4.0.0" consola "^3.2.3" - crossws "^0.2.0" + crossws ">=0.2.0 <0.4.0" defu "^6.1.4" get-port-please "^3.1.2" - h3 "^1.10.2" + h3 "^1.12.0" http-shutdown "^1.2.2" - jiti "^1.21.0" - mlly "^1.6.1" + jiti "^2.1.2" + mlly "^1.7.1" node-forge "^1.3.1" pathe "^1.1.2" std-env "^3.7.0" - ufo "^1.4.0" + ufo "^1.5.4" untun "^0.1.3" uqr "^0.1.2" @@ -13124,20 +12424,13 @@ listr2@^5.0.7: wrap-ansi "^7.0.0" lit-element@^3.3.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.2.tgz#9913bf220b85065f0e5f1bb8878cc44f36b50cfa" - integrity sha512-xXAeVWKGr4/njq0rGC9dethMnYCq5hpKYrgQZYTzawt9YQhMiXfD+T1RgrdY3NamOxwq2aXlb0vOI6e29CKgVQ== + version "3.3.3" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209" + integrity sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA== dependencies: "@lit-labs/ssr-dom-shim" "^1.1.0" "@lit/reactive-element" "^1.3.0" - lit-html "^2.7.0" - -lit-html@^2.7.0: - version "2.7.4" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.7.4.tgz#6d75001977c206683685b9d76594a516afda2954" - integrity sha512-/Jw+FBpeEN+z8X6PJva5n7+0MzCVAH2yypN99qHYYkq8bI+j7I39GH+68Z/MZD6rGKDK9RpzBw7CocfmHfq6+g== - dependencies: - "@types/trusted-types" "^2.0.2" + lit-html "^2.8.0" lit-html@^2.8.0: version "2.8.0" @@ -13210,11 +12503,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== - lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -13255,7 +12543,7 @@ lodash.uniqby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.0: +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@~4.17.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -13338,10 +12626,10 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== -lru-cache@^10.2.0: - version "10.3.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.3.0.tgz#4a4aaf10c84658ab70f79a85a9a3f1e1fb11196b" - integrity sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ== +lru-cache@^10.2.0, lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^4.1.5: version "4.1.5" @@ -13372,11 +12660,6 @@ lru-queue@^0.1.0: dependencies: es5-ext "~0.10.2" -ltgt@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== - lz-string@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" @@ -13581,18 +12864,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -memdown@^1.0.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" - integrity sha512-iVrGHZB8i4OQfM155xx8akvG9FIj+ht14DX5CQkCTG4EHzZ3d3sgckIf/Lm9ivZalEsFuEVnWv2B2WZvbrro2w== - dependencies: - abstract-leveldown "~2.7.1" - functional-red-black-tree "^1.0.1" - immediate "^3.2.3" - inherits "~2.0.1" - ltgt "~2.2.0" - safe-buffer "~5.1.1" - memoizee@^0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" @@ -13632,20 +12903,6 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" - integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== - dependencies: - async "^1.4.2" - ethereumjs-util "^5.0.0" - level-ws "0.0.0" - levelup "^1.2.1" - memdown "^1.0.0" - readable-stream "^2.0.0" - rlp "^2.0.0" - semaphore ">=1.0.1" - meros@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/meros/-/meros-1.2.1.tgz#056f7a76e8571d0aaf3c7afcbe7eb6407ff7329e" @@ -13951,11 +13208,11 @@ micromatch@^4.0.4: picomatch "^2.3.1" micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -14457,15 +13714,15 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.6.1, mlly@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f" - integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA== +mlly@^1.7.1, mlly@^1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.3.tgz#d86c0fcd8ad8e16395eb764a5f4b831590cee48c" + integrity sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A== dependencies: - acorn "^8.11.3" + acorn "^8.14.0" pathe "^1.1.2" - pkg-types "^1.1.1" - ufo "^1.5.3" + pkg-types "^1.2.1" + ufo "^1.5.4" mock-fs@^4.1.0: version "4.14.0" @@ -14494,7 +13751,7 @@ motion@10.16.2: "@motionone/utils" "^10.15.1" "@motionone/vue" "^10.16.2" -mri@^1.1.0, mri@^1.2.0: +mri@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== @@ -14514,7 +13771,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -14584,20 +13841,25 @@ nano-json-stream-parser@^0.1.2: resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== -nanoid@^3.3.1, nanoid@^3.3.6: +nanoid@^3.3.1: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.6: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== + nanoid@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== napi-wasm@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" - integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.3.tgz#7bb95c88e6561f84880bb67195437b1cfbe99224" + integrity sha512-h/4nMGsHjZDCYmQVNODIrYACVJ+I9KItbG+0si6W/jSjdA9JbWDoU4LLeMXVcEQGHjttI2tuXqDrbGF7qkUHHg== natural-compare-lite@^1.4.0: version "1.4.0" @@ -14638,11 +13900,11 @@ next-tick@1, next-tick@^1.1.0: integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== next@^14.2.10: - version "14.2.10" - resolved "https://registry.yarnpkg.com/next/-/next-14.2.10.tgz#331981a4fecb1ae8af1817d4db98fc9687ee1cb6" - integrity sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww== + version "14.2.18" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.18.tgz#1750bc0c3dda644d48be530d1b0e71ad92025cf8" + integrity sha512-H9qbjDuGivUDEnK6wa+p2XKO+iMzgVgyr9Zp/4Iv29lKa+DYaxJGjOeEA+5VOvJh/M7HLiskehInSa0cWxVXUw== dependencies: - "@next/env" "14.2.10" + "@next/env" "14.2.18" "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" @@ -14650,15 +13912,15 @@ next@^14.2.10: postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.2.10" - "@next/swc-darwin-x64" "14.2.10" - "@next/swc-linux-arm64-gnu" "14.2.10" - "@next/swc-linux-arm64-musl" "14.2.10" - "@next/swc-linux-x64-gnu" "14.2.10" - "@next/swc-linux-x64-musl" "14.2.10" - "@next/swc-win32-arm64-msvc" "14.2.10" - "@next/swc-win32-ia32-msvc" "14.2.10" - "@next/swc-win32-x64-msvc" "14.2.10" + "@next/swc-darwin-arm64" "14.2.18" + "@next/swc-darwin-x64" "14.2.18" + "@next/swc-linux-arm64-gnu" "14.2.18" + "@next/swc-linux-arm64-musl" "14.2.18" + "@next/swc-linux-x64-gnu" "14.2.18" + "@next/swc-linux-x64-musl" "14.2.18" + "@next/swc-win32-arm64-msvc" "14.2.18" + "@next/swc-win32-ia32-msvc" "14.2.18" + "@next/swc-win32-x64-msvc" "14.2.18" no-case@^2.2.0, no-case@^2.3.2: version "2.3.2" @@ -14680,34 +13942,29 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-addon-api@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" - integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== - node-addon-api@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" - integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch-native@^1.6.1, node-fetch-native@^1.6.2, node-fetch-native@^1.6.3: +node-fetch-native@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e" integrity sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ== -node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.11, node-fetch@^2.6.7: +node-fetch@^2.6.0: version "2.6.11" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.12: +node-fetch@^2.6.1, node-fetch@^2.6.11, node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -14729,9 +13986,9 @@ node-forge@^1.3.1: integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" - integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + version "4.8.4" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== node-int64@^0.4.0: version "0.4.0" @@ -14815,9 +14072,9 @@ npm-run-path@^4.0.1: path-key "^3.0.0" npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + version "5.3.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" + integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== dependencies: path-key "^4.0.0" @@ -14898,11 +14155,6 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw== - object.assign@^4.1.3, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" @@ -14976,19 +14228,19 @@ oboe@2.1.5: dependencies: http-https "^1.0.0" -ofetch@^1.3.3: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.4.tgz#7ea65ced3c592ec2b9906975ae3fe1d26a56f635" - integrity sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw== +ofetch@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.4.1.tgz#b6bf6b0d75ba616cef6519dd8b6385a8bae480ec" + integrity sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw== dependencies: destr "^2.0.3" - node-fetch-native "^1.6.3" - ufo "^1.5.3" + node-fetch-native "^1.6.4" + ufo "^1.5.4" -ohash@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.3.tgz#f12c3c50bfe7271ce3fd1097d42568122ccdcf07" - integrity sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw== +ohash@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.4.tgz#ae8d83014ab81157d2c285abf7792e2995fadd72" + integrity sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g== on-exit-leak-free@^0.2.0: version "0.2.0" @@ -15028,15 +14280,6 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" -open@^8.4.0: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - open@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" @@ -15444,7 +14687,12 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== -picocolors@^1.0.0, picocolors@^1.0.1: +picocolors@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picocolors@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== @@ -15590,13 +14838,13 @@ pkg-dir@^7.0.0: dependencies: find-up "^6.3.0" -pkg-types@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.2.tgz#3e211ecec23516f59323ba058ec21cbc533ff81a" - integrity sha512-VEGf1he2DR5yowYRl0XJhWJq5ktm9gYIsH+y8sNJpHlxch7JPDaufgrsl4vYjd9hMUY8QVjoNncKbow9I7exyA== +pkg-types@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.2.1.tgz#6ac4e455a5bb4b9a6185c1c79abd544c901db2e5" + integrity sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw== dependencies: - confbox "^0.1.7" - mlly "^1.7.1" + confbox "^0.1.8" + mlly "^1.7.2" pathe "^1.1.2" pkg-up@^3.1.0: @@ -15606,11 +14854,6 @@ pkg-up@^3.1.0: dependencies: find-up "^3.0.0" -pngjs@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - pngjs@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" @@ -15735,20 +14978,10 @@ prb-math@^2.4.1, prb-math@^2.4.3: evm-bn "^1.1.1" mathjs "^10.1.1" -preact@10.4.1: - version "10.4.1" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.4.1.tgz#9b3ba020547673a231c6cf16f0fbaef0e8863431" - integrity sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q== - -preact@^10.16.0: - version "10.22.1" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.22.1.tgz#6a3589973fe0c6e53211091607d31f4b7b27334d" - integrity sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A== - -precond@0.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" - integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== +preact@^10.16.0, preact@^10.24.2: + version "10.25.1" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.25.1.tgz#1c4b84253c42dee874bfbf6a92bdce45e3662665" + integrity sha512-frxeZV2vhQSohQwJ7FvlqC40ze89+8friponWUFeVEkaCfhC6Eu4V0iND5C9CXz8JLndV07QRDeXzH1+Anz5Og== prelude-ls@^1.2.1: version "1.2.1" @@ -15843,14 +15076,6 @@ promise-polyfill@^8.1.3: resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.3.0.tgz#9284810268138d103807b11f4e23d5e945a4db63" integrity sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg== -promise-to-callback@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" - integrity sha512-uhMIZmKM5ZteDMfLgJnoSq9GCwsNKrYau73Awf1jIy6/eUcuuZ3P+CD9zUv0kJsIUbU+x6uLNIhXhLHDs1pNPA== - dependencies: - is-fn "^1.0.0" - set-immediate-shim "^1.0.1" - promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -15931,9 +15156,9 @@ psl@^1.1.28, psl@^1.1.33: integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -15970,36 +15195,6 @@ pvutils@^1.1.3: resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== -qr-code-styling@^1.6.0-rc.1: - version "1.6.0-rc.1" - resolved "https://registry.yarnpkg.com/qr-code-styling/-/qr-code-styling-1.6.0-rc.1.tgz#6c89e185fa50cc9135101085c12ae95b06f1b290" - integrity sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q== - dependencies: - qrcode-generator "^1.4.3" - -qrcode-generator@^1.4.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/qrcode-generator/-/qrcode-generator-1.4.4.tgz#63f771224854759329a99048806a53ed278740e7" - integrity sha512-HM7yY8O2ilqhmULxGMpcHSF1EhJJ9yBj8gvDEuZ6M+KGJ0YY2hKpnXvRD+hZPLrDVck3ExIGhmPtSdcjC+guuw== - -qrcode-terminal-nooctal@^0.12.1: - version "0.12.1" - resolved "https://registry.yarnpkg.com/qrcode-terminal-nooctal/-/qrcode-terminal-nooctal-0.12.1.tgz#45016aca0d82b2818de7af0a06d072ad671fbe2e" - integrity sha512-jy/kkD0iIMDjTucB+5T6KBsnirlhegDH47vHgrj5MejchSQmi/EAMM0xMFeePgV9CJkkAapNakpVUWYgHvtdKg== - -qrcode@1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.4.4.tgz#f0c43568a7e7510a55efc3b88d9602f71963ea83" - integrity sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q== - dependencies: - buffer "^5.4.3" - buffer-alloc "^1.2.0" - buffer-from "^1.1.1" - dijkstrajs "^1.0.1" - isarray "^2.0.1" - pngjs "^3.3.0" - yargs "^13.2.4" - qrcode@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170" @@ -16029,15 +15224,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -query-string@6.13.5: - version "6.13.5" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.5.tgz#99e95e2fb7021db90a6f373f990c0c814b3812d8" - integrity sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q== - dependencies: - decode-uri-component "^0.2.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - query-string@7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" @@ -16565,14 +15751,6 @@ react-markdown@~8.0.0: unist-util-visit "^4.0.0" vfile "^5.0.0" -react-native-webview@^11.26.0: - version "11.26.1" - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.26.1.tgz#658c09ed5162dc170b361e48c2dd26c9712879da" - integrity sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw== - dependencies: - escape-string-regexp "2.0.0" - invariant "2.2.4" - react-quill@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/react-quill/-/react-quill-2.0.0.tgz#67a0100f58f96a246af240c9fa6841b363b3e017" @@ -16671,17 +15849,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@^1.0.33: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@^2.0.0, readable-stream@^2.2.9, readable-stream@^2.3.3: +readable-stream@^2.3.3: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -16724,16 +15892,6 @@ readable-stream@^4.0.0: events "^3.3.0" process "^0.11.10" -readable-stream@~1.0.15: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - readable-web-to-node-stream@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz#5d52bb5df7b54861fd48d015e93a2cb87b3ee0bb" @@ -17037,7 +16195,7 @@ remove-trailing-spaces@^1.0.6: resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7" integrity sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA== -request@^2.79.0, request@^2.85.0: +request@^2.79.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -17130,7 +16288,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== -resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -17221,23 +16379,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1, ripemd160@^2.0.2: hash-base "^3.0.0" inherits "^2.0.1" -rlp@^2.0.0, rlp@^2.2.3, rlp@^2.2.4: +rlp@^2.2.4: version "2.2.7" resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== dependencies: bn.js "^5.2.0" -rollup-plugin-visualizer@^5.9.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.12.0.tgz#661542191ce78ee4f378995297260d0c1efb1302" - integrity sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ== - dependencies: - open "^8.4.0" - picomatch "^2.3.1" - source-map "^0.7.4" - yargs "^17.5.1" - run-applescript@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" @@ -17257,11 +16405,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rustbn.js@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" - integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== - rxjs@^6.6.0, rxjs@^6.6.3: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -17303,13 +16446,6 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-event-emitter@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" - integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== - dependencies: - events "^3.0.0" - safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -17328,7 +16464,12 @@ safe-regex-test@^1.0.3: es-errors "^1.3.0" is-regex "^1.1.4" -safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1: +safe-stable-stringify@^2.1.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +safe-stable-stringify@^2.3.1: version "2.4.3" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== @@ -17414,15 +16555,6 @@ secp256k1@^4.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -secp256k1@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-5.0.0.tgz#be6f0c8c7722e2481e9773336d351de8cddd12f7" - integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^5.0.0" - node-gyp-build "^4.2.0" - secure-json-parse@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" @@ -17433,11 +16565,6 @@ seedrandom@^3.0.5: resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7" integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== -semaphore@>=1.0.1, semaphore@^1.0.3: - version "1.1.0" - resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" - integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== - "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -17450,7 +16577,7 @@ semver@7.3.7: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -17460,22 +16587,22 @@ semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.8: +semver@^7.3.5: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -semver@^7.3.7, semver@^7.5.4: +semver@^7.3.7: version "7.6.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== -semver@~5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== +semver@^7.3.8, semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== send@0.18.0: version "0.18.0" @@ -17561,11 +16688,6 @@ set-function-name@^2.0.1, set-function-name@^2.0.2: functions-have-names "^1.2.3" has-property-descriptors "^1.0.2" -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ== - setimmediate@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" @@ -17747,13 +16869,13 @@ snake-case@^3.0.4: tslib "^2.0.3" socket.io-client@^4.5.1: - version "4.7.5" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" - integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== + version "4.8.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.8.1.tgz#1941eca135a5490b94281d0323fe2a35f6f291cb" + integrity sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.2" - engine.io-client "~6.5.2" + engine.io-client "~6.6.1" socket.io-parser "~4.2.4" socket.io-parser@~4.2.4: @@ -17795,9 +16917,9 @@ sonic-boom@^3.0.0, sonic-boom@^3.1.0: integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== source-map-js@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== source-map-support@0.5.13: version "0.5.13" @@ -17812,11 +16934,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - source-map@^0.8.0-beta.0: version "0.8.0-beta.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" @@ -17910,9 +17027,9 @@ statuses@2.0.1: integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== std-env@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" - integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + version "3.8.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" + integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== stop-iteration-iterator@^1.0.0: version "1.0.0" @@ -17921,10 +17038,10 @@ stop-iteration-iterator@^1.0.0: dependencies: internal-slot "^1.0.4" -stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== +stream-shift@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== streamsearch@^1.1.0: version "1.1.0" @@ -17987,15 +17104,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -18110,11 +17218,6 @@ string_decoder@^1.1.1, string_decoder@^1.3.0: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -18151,13 +17254,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -18773,21 +17869,26 @@ tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.5.0: +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tslib@^2.0.3, tslib@^2.3.0, tslib@^2.5.0: version "2.5.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.2.tgz#1b6f07185c881557b0ffa84b111a0106989e8338" integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== -tslib@^2.4.0, tslib@~2.6.0: - version "2.6.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" - integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== - tslib@~2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== +tslib@~2.6.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" @@ -18933,7 +18034,7 @@ typed-function@^2.1.0: resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-2.1.0.tgz#ded6f8a442ba8749ff3fe75bc41419c8d46ccc3f" integrity sha512-bctQIOqx2iVbWGDGPWwIm18QScpu2XRmkC19D8rQGFsjKSgteq/o1hTZvIG/wuDq8fanpBDrLkLq+aEN/6y5XQ== -typedarray-to-buffer@3.1.5, typedarray-to-buffer@^3.1.5: +typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== @@ -18960,10 +18061,10 @@ ua-parser-js@^0.7.30: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.35.tgz#8bda4827be4f0b1dda91699a29499575a1f1d307" integrity sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g== -ufo@^1.4.0, ufo@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" - integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== +ufo@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.4.tgz#16d6949674ca0c9e0fbbae1fa20a71d7b1ded754" + integrity sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ== uglify-js@^3.5.1: version "3.17.4" @@ -19009,6 +18110,11 @@ uncrypto@^0.1.3: resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + undici@^5.22.0: version "5.28.3" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" @@ -19016,21 +18122,16 @@ undici@^5.22.0: dependencies: "@fastify/busboy" "^2.0.0" -unenv@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" - integrity sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g== +unenv@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.10.0.tgz#c3394a6c6e4cfe68d699f87af456fe3f0db39571" + integrity sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ== dependencies: consola "^3.2.3" - defu "^6.1.3" + defu "^6.1.4" mime "^3.0.0" - node-fetch-native "^1.6.1" - pathe "^1.1.1" - -unfetch@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" - integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + node-fetch-native "^1.6.4" + pathe "^1.1.2" unified@^10.0.0, unified@^10.1.2, unified@~10.1.1: version "10.1.2" @@ -19130,20 +18231,20 @@ unraw@^2.0.1: integrity sha512-tdOvLfRzHolwYcHS6HIX860MkK9LQ4+oLuNwFYL7bpgTEO64PZrcQxkisgwJYCfF8sKiWLwwu1c83DvMkbefIQ== unstorage@^1.9.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.2.tgz#fb7590ada8b30e83be9318f85100158b02a76dae" - integrity sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ== + version "1.13.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.13.1.tgz#090b30de978ee8755b3ad7bbc00acfade124ac13" + integrity sha512-ELexQHUrG05QVIM/iUeQNdl9FXDZhqLJ4yP59fnmn2jGUh0TEulwOgov1ubOb3Gt2ZGK/VMchJwPDNVEGWQpRg== dependencies: anymatch "^3.1.3" chokidar "^3.6.0" + citty "^0.1.6" destr "^2.0.3" - h3 "^1.11.1" - listhen "^1.7.2" - lru-cache "^10.2.0" - mri "^1.2.0" - node-fetch-native "^1.6.2" - ofetch "^1.3.3" - ufo "^1.4.0" + h3 "^1.13.0" + listhen "^1.9.0" + lru-cache "^10.4.3" + node-fetch-native "^1.6.4" + ofetch "^1.4.1" + ufo "^1.5.4" untildify@^4.0.0: version "4.0.0" @@ -19458,12 +18559,12 @@ w3c-xmlserializer@^4.0.0: xml-name-validator "^4.0.0" wagmi@^2.12.5: - version "2.12.5" - resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.12.5.tgz#8480d363ce8e03492dcb547e71a21f0ea2853252" - integrity sha512-+fpSUsVKyGOumguQirtpyMb7dmDP4/ZdwrTqrBc+WZVTwR9S8WdFPParw/BKXVZjF9euJxu1zKsWQSLBeCROfQ== + version "2.13.3" + resolved "https://registry.yarnpkg.com/wagmi/-/wagmi-2.13.3.tgz#faf4d2d2d91b0f63c12937a71943fea277fe8de1" + integrity sha512-EBtrWUtmSpr7YYkPE1aokXiMn8EF+8kaNJAXtQ0UUSKlOLEbrsDtaiO3mEOOpFQtRXd2UUI2teMnIThCOk71kQ== dependencies: - "@wagmi/connectors" "5.1.5" - "@wagmi/core" "2.13.4" + "@wagmi/connectors" "5.5.3" + "@wagmi/core" "2.15.2" use-sync-external-store "1.2.0" walker@^1.0.8: @@ -19668,34 +18769,6 @@ web3-net@1.10.0: web3-core-method "1.10.0" web3-utils "1.10.0" -web3-provider-engine@16.0.1: - version "16.0.1" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-16.0.1.tgz#2600a39ede364cdc0a1fc773bf40a94f2177e605" - integrity sha512-/Eglt2aocXMBiDj7Se/lyZnNDaHBaoJlaUfbP5HkLJQC/HlGbR+3/W+dINirlJDhh7b54DzgykqY7ksaU5QgTg== - dependencies: - async "^2.5.0" - backoff "^2.5.0" - clone "^2.0.0" - cross-fetch "^2.1.0" - eth-block-tracker "^4.4.2" - eth-json-rpc-filters "^4.2.1" - eth-json-rpc-infura "^5.1.0" - eth-json-rpc-middleware "^6.0.0" - eth-rpc-errors "^3.0.0" - eth-sig-util "^1.4.2" - ethereumjs-block "^1.2.2" - ethereumjs-tx "^1.2.0" - ethereumjs-util "^5.1.5" - ethereumjs-vm "^2.3.4" - json-stable-stringify "^1.0.1" - promise-to-callback "^1.0.0" - readable-stream "^2.2.9" - request "^2.85.0" - semaphore "^1.0.3" - ws "^5.1.1" - xhr "^2.2.0" - xtend "^4.0.1" - web3-providers-http@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.0.tgz#864fa48675e7918c9a4374e5f664b32c09d0151b" @@ -19852,11 +18925,6 @@ whatwg-encoding@^2.0.0: dependencies: iconv-lite "0.6.3" -whatwg-fetch@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" - integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== - whatwg-mimetype@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" @@ -19957,7 +19025,18 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15: gopd "^1.0.1" has-tostringtag "^1.0.2" -which-typed-array@^1.1.2, which-typed-array@^1.1.9: +which-typed-array@^1.1.2: + version "1.1.16" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.16.tgz#db4db429c4706feca2f01677a144278e4a8c216b" + integrity sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.2" + +which-typed-array@^1.1.9: version "1.1.9" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== @@ -20011,15 +19090,6 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -20073,11 +19143,6 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@7.5.3: - version "7.5.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" - integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== - ws@8.13.0, ws@^8.11.0, ws@^8.12.0, ws@^8.13.0: version "8.13.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" @@ -20092,18 +19157,16 @@ ws@^3.0.0: safe-buffer "~5.1.0" ultron "~1.1.0" -ws@^5.1.1: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - -ws@^7.3.1, ws@^7.5.1: +ws@^7.3.1: version "7.5.9" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^7.5.1: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + ws@^8.15.0, ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" @@ -20129,14 +19192,7 @@ xhr-request@^1.0.1, xhr-request@^1.1.0: url-set-query "^1.0.0" xhr "^2.0.4" -xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - integrity sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g== - dependencies: - cookiejar "^2.1.1" - -xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: +xhr@^2.0.4, xhr@^2.3.3: version "2.6.0" resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== @@ -20156,28 +19212,21 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xmlhttprequest-ssl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" - integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== +xmlhttprequest-ssl@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz#e9e8023b3f29ef34b97a859f584c5e6c61418e23" + integrity sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ== xmlhttprequest@1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0: +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ== - dependencies: - object-keys "~0.4.0" - y18n@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" @@ -20238,14 +19287,6 @@ yaml@^2.3.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.5.tgz#60630b206dd6d84df97003d33fc1ddf6296cca5e" integrity sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg== -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -20267,22 +19308,6 @@ yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^13.2.4: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - yargs@^15.3.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -20300,7 +19325,7 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^17.0.0, yargs@^17.3.1, yargs@^17.5.1, yargs@^17.7.2: +yargs@^17.0.0, yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -20383,12 +19408,10 @@ zod@^3.11.5: resolved "https://registry.yarnpkg.com/zod/-/zod-3.22.2.tgz#3add8c682b7077c05ac6f979fea6998b573e157b" integrity sha512-wvWkphh5WQsJbVk1tbx1l1Ly4yg+XecD+Mq280uBGt9wa5BKSWf4Mhp6GmrkPixhMxmabYY7RbzlwVP32pbGCg== -zustand@4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.1.tgz#0cd3a3e4756f21811bd956418fdc686877e8b3b0" - integrity sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw== - dependencies: - use-sync-external-store "1.2.0" +zustand@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.0.tgz#71f8aaecf185592a3ba2743d7516607361899da9" + integrity sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ== zwitch@^2.0.0, zwitch@^2.0.4: version "2.0.4"