feat(xc-admin-frontend): instructions summary in proposal page + improve ui in proposal row + refactor the code (#1478)
* refactor: move proposals to a folder * refactor: use @images instead of relative paths * refactor: split proposals into multiple files * refactor: add type for proposal status * refactor: add eslint and fix errors * refactor: fix eslint errors * refactor: fix eslint * refactor: fix prettier * refactor: remove any * refactor: Proposals.tsx * feat: add basic instructions summary * feat: add unknown instruction * fix: revert package-lock.json * fix: update package-lock.json * fix: pre-commit * fix: ts error * fix: remove message buffer dependency * fix: revert back the cluster default * feat: add support for different types of instructions * feat: add transaction index to proposal row * feat: improve the proposal row ui * fix: display bigint properly (#1499) --------- Co-authored-by: guibescos <59208140+guibescos@users.noreply.github.com>
This commit is contained in:
parent
d05df508a8
commit
b110bbca5c
|
@ -1 +1,3 @@
|
|||
node_modules
|
||||
tailwind.config.js
|
||||
next.config.js
|
||||
|
|
|
@ -1,3 +1,14 @@
|
|||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"next/core-web-vitals",
|
||||
"prettier"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{ "argsIgnorePattern": "^_" }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@ import { Menu, Transition } from '@headlessui/react'
|
|||
import { useRouter } from 'next/router'
|
||||
import { Fragment, useCallback, useContext, useEffect } from 'react'
|
||||
import { ClusterContext, DEFAULT_CLUSTER } from '../contexts/ClusterContext'
|
||||
import Arrow from '../images/icons/down.inline.svg'
|
||||
import Arrow from '@images/icons/down.inline.svg'
|
||||
import { PythCluster } from '@pythnetwork/client'
|
||||
|
||||
const ClusterSwitch = ({ light }: { light?: boolean | null }) => {
|
||||
const router = useRouter()
|
||||
|
@ -27,8 +28,8 @@ const ClusterSwitch = ({ light }: { light?: boolean | null }) => {
|
|||
)
|
||||
|
||||
useEffect(() => {
|
||||
router.query && router.query.cluster
|
||||
? setCluster(router.query.cluster)
|
||||
router?.query?.cluster
|
||||
? setCluster(router.query.cluster as PythCluster)
|
||||
: setCluster(DEFAULT_CLUSTER)
|
||||
}, [setCluster, router])
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { PythOracle } from '@pythnetwork/client/lib/anchor'
|
|||
import * as Label from '@radix-ui/react-label'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
|
||||
import { Cluster, PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import SquadsMesh from '@sqds/mesh'
|
||||
import axios from 'axios'
|
||||
import { Fragment, useContext, useEffect, useState } from 'react'
|
||||
|
@ -15,12 +15,11 @@ import {
|
|||
isRemoteCluster,
|
||||
mapKey,
|
||||
PRICE_FEED_MULTISIG,
|
||||
WORMHOLE_ADDRESS,
|
||||
} from 'xc_admin_common'
|
||||
import { ClusterContext } from '../contexts/ClusterContext'
|
||||
import { usePythContext } from '../contexts/PythContext'
|
||||
import { ProductRawConfig } from '../hooks/usePyth'
|
||||
import Arrow from '../images/icons/down.inline.svg'
|
||||
import Arrow from '@images/icons/down.inline.svg'
|
||||
import { capitalizeFirstLetter } from '../utils/capitalizeFirstLetter'
|
||||
import Spinner from './common/Spinner'
|
||||
import CloseIcon from './icons/CloseIcon'
|
||||
|
@ -83,8 +82,6 @@ const PermissionDepermissionKey = ({
|
|||
1
|
||||
)
|
||||
const isRemote: boolean = isRemoteCluster(cluster)
|
||||
const multisigCluster: Cluster | 'localnet' = getMultisigCluster(cluster)
|
||||
const wormholeAddress = WORMHOLE_ADDRESS[multisigCluster]
|
||||
const fundingAccount = isRemote
|
||||
? mapKey(multisigAuthority)
|
||||
: multisigAuthority
|
||||
|
|
|
@ -3,9 +3,10 @@ import { useRouter } from 'next/router'
|
|||
import { Fragment, useCallback, useContext, useEffect } from 'react'
|
||||
import {
|
||||
DEFAULT_STATUS_FILTER,
|
||||
type ProposalStatusFilter,
|
||||
StatusFilterContext,
|
||||
} from '../contexts/StatusFilterContext'
|
||||
import Arrow from '../images/icons/down.inline.svg'
|
||||
import Arrow from '@images/icons/down.inline.svg'
|
||||
|
||||
const ProposalStatusFilter = () => {
|
||||
const router = useRouter()
|
||||
|
@ -31,11 +32,11 @@ const ProposalStatusFilter = () => {
|
|||
|
||||
useEffect(() => {
|
||||
router.query && router.query.status
|
||||
? setStatusFilter(router.query.status as string)
|
||||
? setStatusFilter(router.query.status as ProposalStatusFilter)
|
||||
: setStatusFilter(DEFAULT_STATUS_FILTER)
|
||||
}, [setStatusFilter, router])
|
||||
|
||||
const statuses = [
|
||||
const statuses: ProposalStatusFilter[] = [
|
||||
'all',
|
||||
'active',
|
||||
'executed',
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import copy from 'copy-to-clipboard'
|
||||
import CopyIcon from '../../images/icons/copy.inline.svg'
|
||||
import CopyIcon from '@images/icons/copy.inline.svg'
|
||||
|
||||
const CopyText: React.FC<{
|
||||
text: string
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import Link from 'next/link'
|
||||
import Discord from '../../images/icons/discord.inline.svg'
|
||||
import Github from '../../images/icons/github.inline.svg'
|
||||
import LinkedIn from '../../images/icons/linkedin.inline.svg'
|
||||
import Telegram from '../../images/icons/telegram.inline.svg'
|
||||
import Twitter from '../../images/icons/twitter.inline.svg'
|
||||
import Youtube from '../../images/icons/youtube.inline.svg'
|
||||
import Discord from '@images/icons/discord.inline.svg'
|
||||
import Github from '@images/icons/github.inline.svg'
|
||||
import LinkedIn from '@images/icons/linkedin.inline.svg'
|
||||
import Telegram from '@images/icons/telegram.inline.svg'
|
||||
import Twitter from '@images/icons/twitter.inline.svg'
|
||||
import Youtube from '@images/icons/youtube.inline.svg'
|
||||
|
||||
const SocialLinks = () => {
|
||||
return (
|
||||
|
|
|
@ -3,7 +3,7 @@ import Link from 'next/link'
|
|||
import { useRouter } from 'next/router'
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { ClusterContext, DEFAULT_CLUSTER } from '../../contexts/ClusterContext'
|
||||
import Pyth from '../../images/logomark.inline.svg'
|
||||
import Pyth from '@images/logomark.inline.svg'
|
||||
import MobileMenu from './MobileMenu'
|
||||
|
||||
const WalletMultiButtonDynamic = dynamic(
|
||||
|
@ -156,7 +156,7 @@ const Header = () => {
|
|||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<MobileMenu headerState={headerState} setHeaderState={setHeaderState} />
|
||||
<MobileMenu headerState={headerState} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import Header from './Header'
|
|||
|
||||
const Layout = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<div className="flex flex-col min-h-screen relative overflow-hidden">
|
||||
<div className="relative flex min-h-screen flex-col overflow-hidden">
|
||||
<Header />
|
||||
<main className="flex-grow">{children}</main>
|
||||
<Footer />
|
||||
|
|
|
@ -6,15 +6,14 @@ import { useContext, useEffect, useRef } from 'react'
|
|||
import { ClusterContext, DEFAULT_CLUSTER } from '../../contexts/ClusterContext'
|
||||
import { BurgerState } from './Header'
|
||||
|
||||
import orb from '../../images/burger.png'
|
||||
import orb from '@images/burger.png'
|
||||
|
||||
interface MenuProps {
|
||||
headerState: BurgerState
|
||||
setHeaderState: Function
|
||||
}
|
||||
|
||||
const MobileMenu = ({ headerState, setHeaderState }: MenuProps) => {
|
||||
let burgerMenu = useRef(null)
|
||||
const MobileMenu = ({ headerState }: MenuProps) => {
|
||||
const burgerMenu = useRef(null)
|
||||
const router = useRouter()
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { AnchorProvider, Idl, Program } from '@coral-xyz/anchor'
|
|||
import { AccountType, getPythProgramKeyForCluster } from '@pythnetwork/client'
|
||||
import { PythOracle, pythOracleProgram } from '@pythnetwork/client/lib/anchor'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { Cluster, PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
|
||||
import messageBuffer from 'message_buffer/idl/message_buffer.json'
|
||||
import { MessageBuffer } from 'message_buffer/idl/message_buffer'
|
||||
import axios from 'axios'
|
||||
|
@ -18,7 +18,6 @@ import {
|
|||
MESSAGE_BUFFER_PROGRAM_ID,
|
||||
MESSAGE_BUFFER_BUFFER_SIZE,
|
||||
PRICE_FEED_MULTISIG,
|
||||
WORMHOLE_ADDRESS,
|
||||
PRICE_FEED_OPS_KEY,
|
||||
getMessageBufferAddressForPrice,
|
||||
getMaximumNumberOfPublishers,
|
||||
|
@ -44,8 +43,6 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
useState(false)
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const isRemote: boolean = isRemoteCluster(cluster) // Move to multisig context
|
||||
const multisigCluster: Cluster | 'localnet' = getMultisigCluster(cluster) // Move to multisig context
|
||||
const wormholeAddress = WORMHOLE_ADDRESS[multisigCluster] // Move to multisig context
|
||||
const { isLoading: isMultisigLoading, squads } = useMultisigContext()
|
||||
const { rawConfig, dataIsLoading, connection } = usePythContext()
|
||||
const { connected } = useWallet()
|
||||
|
@ -370,7 +367,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
}
|
||||
|
||||
// create add publisher instruction if there are any publishers
|
||||
for (let publisherKey of newChanges.priceAccounts[0].publishers) {
|
||||
for (const publisherKey of newChanges.priceAccounts[0].publishers) {
|
||||
instructions.push(
|
||||
await pythProgramClient.methods
|
||||
.addPublisher(new PublicKey(publisherKey))
|
||||
|
@ -525,7 +522,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
|
||||
// add instructions to remove publishers
|
||||
|
||||
for (let publisherKey of publisherKeysToRemove) {
|
||||
for (const publisherKey of publisherKeysToRemove) {
|
||||
instructions.push(
|
||||
await pythProgramClient.methods
|
||||
.delPublisher(new PublicKey(publisherKey))
|
||||
|
@ -538,7 +535,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
}
|
||||
|
||||
// add instructions to add new publishers
|
||||
for (let publisherKey of publisherKeysToAdd) {
|
||||
for (const publisherKey of publisherKeysToAdd) {
|
||||
instructions.push(
|
||||
await pythProgramClient.methods
|
||||
.addPublisher(new PublicKey(publisherKey))
|
||||
|
@ -823,7 +820,7 @@ const General = ({ proposerServerUrl }: { proposerServerUrl: string }) => {
|
|||
|
||||
// create anchor wallet when connected
|
||||
useEffect(() => {
|
||||
if (connected && squads) {
|
||||
if (connected && squads && connection) {
|
||||
const provider = new AnchorProvider(
|
||||
connection,
|
||||
squads.wallet as Wallet,
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import { PythCluster } from '@pythnetwork/client'
|
||||
import { MultisigInstruction } from 'xc_admin_common'
|
||||
import { getInstructionsSummary } from './utils'
|
||||
|
||||
export const InstructionsSummary = ({
|
||||
instructions,
|
||||
cluster,
|
||||
}: {
|
||||
instructions: MultisigInstruction[]
|
||||
cluster: PythCluster
|
||||
}) => {
|
||||
const instructionsCount = getInstructionsSummary({ instructions, cluster })
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{Object.entries(instructionsCount).map(([name, count]) => {
|
||||
return (
|
||||
<div key={name}>
|
||||
{name}: {count}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import {
|
||||
AccountMeta,
|
||||
|
@ -7,147 +7,47 @@ import {
|
|||
SystemProgram,
|
||||
TransactionInstruction,
|
||||
} from '@solana/web3.js'
|
||||
import SquadsMesh from '@sqds/mesh'
|
||||
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Fragment, useCallback, useContext, useEffect, useState } from 'react'
|
||||
import { Fragment, useContext, useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
AnchorMultisigInstruction,
|
||||
ExecutePostedVaa,
|
||||
getMultisigCluster,
|
||||
MultisigInstruction,
|
||||
MultisigParser,
|
||||
PythMultisigInstruction,
|
||||
AnchorMultisigInstruction,
|
||||
WormholeMultisigInstruction,
|
||||
getManyProposalsInstructions,
|
||||
getMultisigCluster,
|
||||
getProgramName,
|
||||
} from 'xc_admin_common'
|
||||
import { ClusterContext } from '../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../contexts/MultisigContext'
|
||||
import { usePythContext } from '../../contexts/PythContext'
|
||||
import { StatusFilterContext } from '../../contexts/StatusFilterContext'
|
||||
import VerifiedIcon from '../../images/icons/verified.inline.svg'
|
||||
import WarningIcon from '../../images/icons/warning.inline.svg'
|
||||
import VotedIcon from '../../images/icons/voted.inline.svg'
|
||||
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
|
||||
import ClusterSwitch from '../ClusterSwitch'
|
||||
import CopyText from '../common/CopyText'
|
||||
import Spinner from '../common/Spinner'
|
||||
import Loadbar from '../loaders/Loadbar'
|
||||
import ProposalStatusFilter from '../ProposalStatusFilter'
|
||||
import SquadsMesh from '@sqds/mesh'
|
||||
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'
|
||||
import { WormholeInstructionView } from '../InstructionViews/WormholeInstructionView'
|
||||
import { ClusterContext } from '../../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../../contexts/MultisigContext'
|
||||
import { usePythContext } from '../../../contexts/PythContext'
|
||||
import { capitalizeFirstLetter } from '../../../utils/capitalizeFirstLetter'
|
||||
import {
|
||||
ParsedAccountPubkeyRow,
|
||||
SignerTag,
|
||||
WritableTag,
|
||||
} from '../InstructionViews/AccountUtils'
|
||||
} from '../../InstructionViews/AccountUtils'
|
||||
import { WormholeInstructionView } from '../../InstructionViews/WormholeInstructionView'
|
||||
import CopyText from '../../common/CopyText'
|
||||
import Spinner from '../../common/Spinner'
|
||||
import Loadbar from '../../loaders/Loadbar'
|
||||
|
||||
import { getMappingCluster, isPubkey } from '../InstructionViews/utils'
|
||||
import { getPythProgramKeyForCluster, PythCluster } from '@pythnetwork/client'
|
||||
import {
|
||||
DEFAULT_PRIORITY_FEE_CONFIG,
|
||||
TransactionBuilder,
|
||||
sendTransactions,
|
||||
} from '@pythnetwork/solana-utils'
|
||||
import { Wallet } from '@coral-xyz/anchor'
|
||||
const ProposalRow = ({
|
||||
proposal,
|
||||
multisig,
|
||||
}: {
|
||||
proposal: TransactionAccount
|
||||
multisig: MultisigAccount | undefined
|
||||
}) => {
|
||||
const status = getProposalStatus(proposal, multisig)
|
||||
import { PythCluster, getPythProgramKeyForCluster } from '@pythnetwork/client'
|
||||
import { TransactionBuilder, sendTransactions } from '@pythnetwork/solana-utils'
|
||||
import { getMappingCluster, isPubkey } from '../../InstructionViews/utils'
|
||||
import { StatusTag } from './StatusTag'
|
||||
import { getProposalStatus } from './utils'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const handleClickIndividualProposal = useCallback(
|
||||
(proposalPubkey: string) => {
|
||||
router.query.proposal = proposalPubkey
|
||||
router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
query: router.query,
|
||||
},
|
||||
undefined,
|
||||
{ scroll: true }
|
||||
)
|
||||
},
|
||||
[router]
|
||||
)
|
||||
return (
|
||||
<div
|
||||
className="my-2 max-h-[58px] cursor-pointer bg-[#1E1B2F] hover:bg-darkGray2"
|
||||
onClick={() =>
|
||||
handleClickIndividualProposal(proposal.publicKey.toBase58())
|
||||
}
|
||||
>
|
||||
<div className="flex justify-between p-4">
|
||||
<div className="flex">
|
||||
<span className="mr-2 hidden sm:block">
|
||||
{proposal.publicKey.toBase58()}
|
||||
</span>
|
||||
<span className="mr-2 sm:hidden">
|
||||
{proposal.publicKey.toBase58().slice(0, 6) +
|
||||
'...' +
|
||||
proposal.publicKey.toBase58().slice(-6)}
|
||||
</span>{' '}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
{proposal.approved.length > 0 && status === 'active' && (
|
||||
<div>
|
||||
<StatusTag
|
||||
proposalStatus="executed"
|
||||
text={`Approved: ${proposal.approved.length}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{proposal.rejected.length > 0 && status === 'active' && (
|
||||
<div>
|
||||
<StatusTag
|
||||
proposalStatus="rejected"
|
||||
text={`Rejected: ${proposal.rejected.length}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<StatusTag proposalStatus={status} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const StatusTag = ({
|
||||
proposalStatus,
|
||||
text,
|
||||
}: {
|
||||
proposalStatus: string
|
||||
text?: string
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center justify-center rounded-full ${
|
||||
proposalStatus === 'active'
|
||||
? 'bg-[#3C3299]'
|
||||
: proposalStatus === 'executed'
|
||||
? 'bg-[#1B730E]'
|
||||
: proposalStatus === 'cancelled'
|
||||
? 'bg-[#C4428F]'
|
||||
: proposalStatus === 'rejected'
|
||||
? 'bg-[#CF6E42]'
|
||||
: proposalStatus === 'expired'
|
||||
? 'bg-[#A52A2A]'
|
||||
: 'bg-pythPurple'
|
||||
} py-1 px-2 text-xs`}
|
||||
>
|
||||
{text || proposalStatus}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
import VerifiedIcon from '@images/icons/verified.inline.svg'
|
||||
import VotedIcon from '@images/icons/voted.inline.svg'
|
||||
import WarningIcon from '@images/icons/warning.inline.svg'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { InstructionsSummary } from './InstructionsSummary'
|
||||
|
||||
const IconWithTooltip = ({
|
||||
icon,
|
||||
|
@ -194,26 +94,11 @@ const VotedIconWithTooltip = () => {
|
|||
return (
|
||||
<IconWithTooltip
|
||||
icon={<VotedIcon />}
|
||||
tooltipText=" You have voted on this proposal."
|
||||
tooltipText="You have voted on this proposal."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const getProposalStatus = (
|
||||
proposal: TransactionAccount | undefined,
|
||||
multisig: MultisigAccount | undefined
|
||||
): string => {
|
||||
if (multisig && proposal) {
|
||||
const onChainStatus = Object.keys(proposal.status)[0]
|
||||
return proposal.transactionIndex <= multisig.msChangeIndex &&
|
||||
(onChainStatus == 'active' || onChainStatus == 'draft')
|
||||
? 'expired'
|
||||
: onChainStatus
|
||||
} else {
|
||||
return 'unkwown'
|
||||
}
|
||||
}
|
||||
|
||||
const AccountList = ({
|
||||
listName,
|
||||
accounts,
|
||||
|
@ -244,14 +129,12 @@ const AccountList = ({
|
|||
)
|
||||
}
|
||||
|
||||
type ProposalType = 'priceFeed' | 'governance'
|
||||
|
||||
const Proposal = ({
|
||||
export const Proposal = ({
|
||||
proposal,
|
||||
multisig,
|
||||
}: {
|
||||
proposal: TransactionAccount | undefined
|
||||
multisig: MultisigAccount | undefined
|
||||
proposal?: TransactionAccount
|
||||
multisig?: MultisigAccount
|
||||
}) => {
|
||||
const [instructions, setInstructions] = useState<MultisigInstruction[]>([])
|
||||
const [isTransactionLoading, setIsTransactionLoading] = useState(false)
|
||||
|
@ -477,9 +360,14 @@ const Proposal = ({
|
|||
)
|
||||
}
|
||||
|
||||
return proposal !== undefined &&
|
||||
multisig !== undefined &&
|
||||
!isMultisigLoading ? (
|
||||
if (!proposal || !multisig || isMultisigLoading)
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="col-span-3 my-2 space-y-4 bg-[#1E1B2F] p-4">
|
||||
<h4 className="h4 font-semibold">
|
||||
|
@ -599,6 +487,9 @@ const Proposal = ({
|
|||
Total Instructions: {instructions.length}
|
||||
</h4>
|
||||
<hr className="border-gray-700" />
|
||||
<h4 className="h4 text-[20px] font-semibold">Summary</h4>
|
||||
<InstructionsSummary instructions={instructions} cluster={cluster} />
|
||||
<hr className="border-gray-700" />
|
||||
{instructions?.map((instruction, index) => (
|
||||
<Fragment key={index}>
|
||||
<h4 className="h4 text-[20px] font-semibold">
|
||||
|
@ -659,6 +550,8 @@ const Proposal = ({
|
|||
? instruction.args[key]
|
||||
: instruction.args[key] instanceof Uint8Array
|
||||
? instruction.args[key].toString('hex')
|
||||
: typeof instruction.args[key] === 'bigint'
|
||||
? instruction.args[key].toString()
|
||||
: JSON.stringify(instruction.args[key])}
|
||||
</div>
|
||||
)}
|
||||
|
@ -764,213 +657,5 @@ const Proposal = ({
|
|||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-6">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Proposals = () => {
|
||||
const router = useRouter()
|
||||
const { connected, publicKey: signerPublicKey } = useWallet()
|
||||
const [currentProposal, setCurrentProposal] = useState<TransactionAccount>()
|
||||
const [currentProposalPubkey, setCurrentProposalPubkey] = useState<string>()
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const { statusFilter } = useContext(StatusFilterContext)
|
||||
|
||||
const {
|
||||
upgradeMultisigAccount,
|
||||
priceFeedMultisigAccount,
|
||||
priceFeedMultisigProposals,
|
||||
upgradeMultisigProposals,
|
||||
isLoading: isMultisigLoading,
|
||||
refreshData,
|
||||
} = useMultisigContext()
|
||||
|
||||
const [proposalType, setProposalType] = useState<ProposalType>('priceFeed')
|
||||
|
||||
const multisigAccount =
|
||||
proposalType === 'priceFeed'
|
||||
? priceFeedMultisigAccount
|
||||
: upgradeMultisigAccount
|
||||
const multisigProposals =
|
||||
proposalType === 'priceFeed'
|
||||
? priceFeedMultisigProposals
|
||||
: upgradeMultisigProposals
|
||||
const [filteredProposals, setFilteredProposals] = useState<
|
||||
TransactionAccount[]
|
||||
>([])
|
||||
|
||||
const handleClickBackToProposals = () => {
|
||||
delete router.query.proposal
|
||||
router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
query: router.query,
|
||||
},
|
||||
undefined,
|
||||
{ scroll: false }
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (router.query.proposal) {
|
||||
setCurrentProposalPubkey(router.query.proposal as string)
|
||||
} else {
|
||||
setCurrentProposalPubkey(undefined)
|
||||
}
|
||||
}, [router.query.proposal])
|
||||
|
||||
const switchProposalType = useCallback(() => {
|
||||
if (proposalType === 'priceFeed') {
|
||||
setProposalType('governance')
|
||||
} else {
|
||||
setProposalType('priceFeed')
|
||||
}
|
||||
}, [proposalType])
|
||||
|
||||
useEffect(() => {
|
||||
if (currentProposalPubkey) {
|
||||
const currProposal = multisigProposals.find(
|
||||
(proposal) => proposal.publicKey.toBase58() === currentProposalPubkey
|
||||
)
|
||||
setCurrentProposal(currProposal)
|
||||
if (currProposal === undefined) {
|
||||
const otherProposals =
|
||||
proposalType !== 'priceFeed'
|
||||
? priceFeedMultisigProposals
|
||||
: upgradeMultisigProposals
|
||||
if (
|
||||
otherProposals.findIndex(
|
||||
(proposal) =>
|
||||
proposal.publicKey.toBase58() === currentProposalPubkey
|
||||
) !== -1
|
||||
) {
|
||||
switchProposalType()
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
switchProposalType,
|
||||
priceFeedMultisigProposals,
|
||||
proposalType,
|
||||
upgradeMultisigProposals,
|
||||
currentProposalPubkey,
|
||||
multisigProposals,
|
||||
cluster,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
// filter price feed multisig proposals by status
|
||||
if (statusFilter === 'all') {
|
||||
setFilteredProposals(multisigProposals)
|
||||
} else {
|
||||
setFilteredProposals(
|
||||
multisigProposals.filter(
|
||||
(proposal) =>
|
||||
getProposalStatus(proposal, multisigAccount) === statusFilter
|
||||
)
|
||||
)
|
||||
}
|
||||
}, [statusFilter, multisigAccount, multisigProposals])
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="container flex flex-col items-center justify-between lg:flex-row">
|
||||
<div className="mb-4 w-full text-left lg:mb-0">
|
||||
<h1 className="h1 mb-4">
|
||||
{proposalType === 'priceFeed' ? 'Price Feed ' : 'Governance '}{' '}
|
||||
{router.query.proposal === undefined ? 'Proposals' : 'Proposal'}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container min-h-[50vh]">
|
||||
{router.query.proposal === undefined ? (
|
||||
<>
|
||||
<div className="flex flex-col justify-between md:flex-row">
|
||||
<div className="mb-4 flex items-center md:mb-0">
|
||||
<ClusterSwitch />
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
{refreshData && (
|
||||
<button
|
||||
disabled={isMultisigLoading}
|
||||
className="sub-action-btn text-base"
|
||||
onClick={() => {
|
||||
const { fetchData } = refreshData()
|
||||
fetchData()
|
||||
}}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
disabled={isMultisigLoading}
|
||||
className="action-btn text-base"
|
||||
onClick={switchProposalType}
|
||||
>
|
||||
Show
|
||||
{proposalType !== 'priceFeed'
|
||||
? ' Price Feed '
|
||||
: ' Governance '}
|
||||
Proposals
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative mt-6">
|
||||
{isMultisigLoading ? (
|
||||
<div className="mt-3">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center justify-between pb-4">
|
||||
<h4 className="h4">
|
||||
Total Proposals: {filteredProposals.length}
|
||||
</h4>
|
||||
<ProposalStatusFilter />
|
||||
</div>
|
||||
{filteredProposals.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
{filteredProposals.map((proposal, idx) => (
|
||||
<ProposalRow
|
||||
key={proposal.publicKey.toBase58()}
|
||||
proposal={proposal}
|
||||
multisig={multisigAccount}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4">
|
||||
No proposals found. If you're a member of the
|
||||
multisig, you can create a proposal.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : !isMultisigLoading && currentProposal !== undefined ? (
|
||||
<>
|
||||
<div
|
||||
className="max-w-fit cursor-pointer bg-darkGray2 p-3 text-xs font-semibold outline-none transition-colors hover:bg-darkGray3 md:text-base"
|
||||
onClick={handleClickBackToProposals}
|
||||
>
|
||||
← back to proposals
|
||||
</div>
|
||||
<div className="relative mt-6">
|
||||
<Proposal proposal={currentProposal} multisig={multisigAccount} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="mt-3">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Proposals
|
|
@ -0,0 +1,191 @@
|
|||
import SquadsMesh from '@sqds/mesh'
|
||||
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||
import { getMultisigCluster } from 'xc_admin_common'
|
||||
import { ClusterContext } from '../../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../../contexts/MultisigContext'
|
||||
import { StatusTag } from './StatusTag'
|
||||
import { getInstructionsSummary, getProposalStatus } from './utils'
|
||||
|
||||
import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet'
|
||||
import { AccountMeta, Keypair } from '@solana/web3.js'
|
||||
import { MultisigParser, getManyProposalsInstructions } from 'xc_admin_common'
|
||||
|
||||
export const ProposalRow = ({
|
||||
proposal,
|
||||
multisig,
|
||||
}: {
|
||||
proposal: TransactionAccount
|
||||
multisig: MultisigAccount | undefined
|
||||
}) => {
|
||||
const [time, setTime] = useState<Date>()
|
||||
const [instructions, setInstructions] = useState<[string, number][]>()
|
||||
const status = getProposalStatus(proposal, multisig)
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const { isLoading: isMultisigLoading, connection } = useMultisigContext()
|
||||
const router = useRouter()
|
||||
const elementRef = useRef(null)
|
||||
const formattedTime = time?.toLocaleString(undefined, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
hour12: false,
|
||||
})
|
||||
|
||||
/**
|
||||
* Fetch the block time of the first transaction of the proposal
|
||||
* and calculates the instructions summary of the proposal
|
||||
* when the proposal is in view
|
||||
*/
|
||||
useEffect(() => {
|
||||
let isCancelled = false
|
||||
const element = elementRef.current
|
||||
const observer = new IntersectionObserver(async (entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
if (isMultisigLoading || !connection) {
|
||||
return
|
||||
}
|
||||
|
||||
// set proposal time
|
||||
if (!time) {
|
||||
connection
|
||||
.getConfirmedSignaturesForAddress2(proposal.publicKey)
|
||||
.then((txs) => {
|
||||
if (isCancelled) return
|
||||
const firstBlockTime = txs?.[txs.length - 1]?.blockTime
|
||||
if (firstBlockTime) {
|
||||
setTime(new Date(firstBlockTime * 1000))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// calculate instructions summary
|
||||
if (!instructions) {
|
||||
const readOnlySquads = new SquadsMesh({
|
||||
connection,
|
||||
wallet: new NodeWallet(new Keypair()),
|
||||
})
|
||||
const proposalInstructions = (
|
||||
await getManyProposalsInstructions(readOnlySquads, [proposal])
|
||||
)[0]
|
||||
const multisigParser = MultisigParser.fromCluster(
|
||||
getMultisigCluster(cluster)
|
||||
)
|
||||
const parsedInstructions = proposalInstructions.map((ix) =>
|
||||
multisigParser.parseInstruction({
|
||||
programId: ix.programId,
|
||||
data: ix.data as Buffer,
|
||||
keys: ix.keys as AccountMeta[],
|
||||
})
|
||||
)
|
||||
|
||||
const summary = getInstructionsSummary({
|
||||
instructions: parsedInstructions,
|
||||
cluster,
|
||||
})
|
||||
|
||||
// show only the first two instructions
|
||||
// and group the rest under 'other'
|
||||
const shortSummary = Object.entries(summary).slice(0, 2)
|
||||
const otherValue = Object.values(summary)
|
||||
.slice(2)
|
||||
.reduce((acc, curr) => acc + curr, 0)
|
||||
const updatedSummary = [
|
||||
...shortSummary,
|
||||
...(otherValue > 0
|
||||
? ([['other', otherValue]] as [string, number][])
|
||||
: []),
|
||||
]
|
||||
|
||||
if (!isCancelled) {
|
||||
setInstructions(updatedSummary)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (element) {
|
||||
observer.observe(element)
|
||||
}
|
||||
|
||||
// Clean up function
|
||||
return () => {
|
||||
isCancelled = true
|
||||
if (element) {
|
||||
observer.unobserve(element)
|
||||
}
|
||||
}
|
||||
}, [time, cluster, proposal, connection, isMultisigLoading, instructions])
|
||||
|
||||
const handleClickIndividualProposal = useCallback(
|
||||
(proposalPubkey: string) => {
|
||||
router.query.proposal = proposalPubkey
|
||||
router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
query: router.query,
|
||||
},
|
||||
undefined,
|
||||
{ scroll: true }
|
||||
)
|
||||
},
|
||||
[router]
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={elementRef}
|
||||
className="my-2 cursor-pointer bg-[#1E1B2F] hover:bg-darkGray2"
|
||||
onClick={() =>
|
||||
handleClickIndividualProposal(proposal.publicKey.toBase58())
|
||||
}
|
||||
>
|
||||
<div className="flex flex-wrap gap-4 p-4">
|
||||
<div className="font-bold">{proposal.transactionIndex}</div>
|
||||
<div className="flex items-center">
|
||||
{formattedTime ?? (
|
||||
<div className="h-5 w-48 animate-pulse rounded bg-beige-300" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="mr-2">
|
||||
{proposal.publicKey.toBase58().slice(0, 6) +
|
||||
'...' +
|
||||
proposal.publicKey.toBase58().slice(-6)}
|
||||
</span>{' '}
|
||||
</div>
|
||||
<div className="flex flex-grow gap-4">
|
||||
{instructions?.map(([name, count]) => (
|
||||
<div key={name}>
|
||||
{name}: {count}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
{proposal.approved.length > 0 && status === 'active' && (
|
||||
<div>
|
||||
<StatusTag
|
||||
proposalStatus="executed"
|
||||
text={`Approved: ${proposal.approved.length}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{proposal.rejected.length > 0 && status === 'active' && (
|
||||
<div>
|
||||
<StatusTag
|
||||
proposalStatus="rejected"
|
||||
text={`Rejected: ${proposal.rejected.length}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<StatusTag proposalStatus={status} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
import { TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useCallback, useContext, useEffect, useState } from 'react'
|
||||
import { ClusterContext } from '../../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../../contexts/MultisigContext'
|
||||
import { StatusFilterContext } from '../../../contexts/StatusFilterContext'
|
||||
import ClusterSwitch from '../../ClusterSwitch'
|
||||
import ProposalStatusFilter from '../../ProposalStatusFilter'
|
||||
import Loadbar from '../../loaders/Loadbar'
|
||||
|
||||
import { ProposalRow } from './ProposalRow'
|
||||
import { getProposalStatus } from './utils'
|
||||
import { Proposal } from './Proposal'
|
||||
|
||||
type ProposalType = 'priceFeed' | 'governance'
|
||||
|
||||
const Proposals = () => {
|
||||
const router = useRouter()
|
||||
const [currentProposal, setCurrentProposal] = useState<TransactionAccount>()
|
||||
const [currentProposalPubkey, setCurrentProposalPubkey] = useState<string>()
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const { statusFilter } = useContext(StatusFilterContext)
|
||||
|
||||
const {
|
||||
upgradeMultisigAccount,
|
||||
priceFeedMultisigAccount,
|
||||
priceFeedMultisigProposals,
|
||||
upgradeMultisigProposals,
|
||||
isLoading: isMultisigLoading,
|
||||
refreshData,
|
||||
} = useMultisigContext()
|
||||
|
||||
const [proposalType, setProposalType] = useState<ProposalType>('priceFeed')
|
||||
|
||||
const multisigAccount =
|
||||
proposalType === 'priceFeed'
|
||||
? priceFeedMultisigAccount
|
||||
: upgradeMultisigAccount
|
||||
const multisigProposals =
|
||||
proposalType === 'priceFeed'
|
||||
? priceFeedMultisigProposals
|
||||
: upgradeMultisigProposals
|
||||
const [filteredProposals, setFilteredProposals] = useState<
|
||||
TransactionAccount[]
|
||||
>([])
|
||||
|
||||
const handleClickBackToProposals = () => {
|
||||
delete router.query.proposal
|
||||
router.push(
|
||||
{
|
||||
pathname: router.pathname,
|
||||
query: router.query,
|
||||
},
|
||||
undefined,
|
||||
{ scroll: false }
|
||||
)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (router.query.proposal) {
|
||||
setCurrentProposalPubkey(router.query.proposal as string)
|
||||
} else {
|
||||
setCurrentProposalPubkey(undefined)
|
||||
}
|
||||
}, [router.query.proposal])
|
||||
|
||||
const switchProposalType = useCallback(() => {
|
||||
if (proposalType === 'priceFeed') {
|
||||
setProposalType('governance')
|
||||
} else {
|
||||
setProposalType('priceFeed')
|
||||
}
|
||||
}, [proposalType])
|
||||
|
||||
useEffect(() => {
|
||||
if (currentProposalPubkey) {
|
||||
const currProposal = multisigProposals.find(
|
||||
(proposal) => proposal.publicKey.toBase58() === currentProposalPubkey
|
||||
)
|
||||
setCurrentProposal(currProposal)
|
||||
if (currProposal === undefined) {
|
||||
const otherProposals =
|
||||
proposalType !== 'priceFeed'
|
||||
? priceFeedMultisigProposals
|
||||
: upgradeMultisigProposals
|
||||
if (
|
||||
otherProposals.findIndex(
|
||||
(proposal) =>
|
||||
proposal.publicKey.toBase58() === currentProposalPubkey
|
||||
) !== -1
|
||||
) {
|
||||
switchProposalType()
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [
|
||||
switchProposalType,
|
||||
priceFeedMultisigProposals,
|
||||
proposalType,
|
||||
upgradeMultisigProposals,
|
||||
currentProposalPubkey,
|
||||
multisigProposals,
|
||||
cluster,
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
// filter price feed multisig proposals by status
|
||||
if (statusFilter === 'all') {
|
||||
setFilteredProposals(multisigProposals)
|
||||
} else {
|
||||
setFilteredProposals(
|
||||
multisigProposals.filter(
|
||||
(proposal) =>
|
||||
getProposalStatus(proposal, multisigAccount) === statusFilter
|
||||
)
|
||||
)
|
||||
}
|
||||
}, [statusFilter, multisigAccount, multisigProposals])
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div className="container flex flex-col items-center justify-between lg:flex-row">
|
||||
<div className="mb-4 w-full text-left lg:mb-0">
|
||||
<h1 className="h1 mb-4">
|
||||
{proposalType === 'priceFeed' ? 'Price Feed ' : 'Governance '}{' '}
|
||||
{router.query.proposal === undefined ? 'Proposals' : 'Proposal'}
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div className="container min-h-[50vh]">
|
||||
{router.query.proposal === undefined ? (
|
||||
<>
|
||||
<div className="flex flex-col justify-between md:flex-row">
|
||||
<div className="mb-4 flex items-center md:mb-0">
|
||||
<ClusterSwitch />
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
{refreshData && (
|
||||
<button
|
||||
disabled={isMultisigLoading}
|
||||
className="sub-action-btn text-base"
|
||||
onClick={() => {
|
||||
const { fetchData } = refreshData()
|
||||
fetchData()
|
||||
}}
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
disabled={isMultisigLoading}
|
||||
className="action-btn text-base"
|
||||
onClick={switchProposalType}
|
||||
>
|
||||
Show
|
||||
{proposalType !== 'priceFeed'
|
||||
? ' Price Feed '
|
||||
: ' Governance '}
|
||||
Proposals
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative mt-6">
|
||||
{isMultisigLoading ? (
|
||||
<div className="mt-3">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center justify-between pb-4">
|
||||
<h4 className="h4">
|
||||
Total Proposals: {filteredProposals.length}
|
||||
</h4>
|
||||
<ProposalStatusFilter />
|
||||
</div>
|
||||
{filteredProposals.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
{filteredProposals.map((proposal, _idx) => (
|
||||
<ProposalRow
|
||||
key={proposal.publicKey.toBase58()}
|
||||
proposal={proposal}
|
||||
multisig={multisigAccount}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="mt-4">
|
||||
No proposals found. If you're a member of the
|
||||
multisig, you can create a proposal.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : !isMultisigLoading && currentProposal !== undefined ? (
|
||||
<>
|
||||
<div
|
||||
className="max-w-fit cursor-pointer bg-darkGray2 p-3 text-xs font-semibold outline-none transition-colors hover:bg-darkGray3 md:text-base"
|
||||
onClick={handleClickBackToProposals}
|
||||
>
|
||||
← back to proposals
|
||||
</div>
|
||||
<div className="relative mt-6">
|
||||
<Proposal proposal={currentProposal} multisig={multisigAccount} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="mt-3">
|
||||
<Loadbar theme="light" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Proposals
|
|
@ -0,0 +1,37 @@
|
|||
import { ProposalStatus } from './utils'
|
||||
|
||||
const getProposalBackgroundColorClassName = (
|
||||
proposalStatus: ProposalStatus
|
||||
) => {
|
||||
if (proposalStatus === 'active') {
|
||||
return 'bg-[#3C3299]'
|
||||
} else if (proposalStatus === 'executed') {
|
||||
return 'bg-[#1B730E]'
|
||||
} else if (proposalStatus === 'cancelled') {
|
||||
return 'bg-[#C4428F]'
|
||||
} else if (proposalStatus === 'rejected') {
|
||||
return 'bg-[#CF6E42]'
|
||||
} else if (proposalStatus === 'expired') {
|
||||
return 'bg-[#A52A2A]'
|
||||
} else {
|
||||
return 'bg-pythPurple'
|
||||
}
|
||||
}
|
||||
|
||||
export const StatusTag = ({
|
||||
proposalStatus,
|
||||
text,
|
||||
}: {
|
||||
proposalStatus: ProposalStatus
|
||||
text?: string
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center justify-center rounded-full ${getProposalBackgroundColorClassName(
|
||||
proposalStatus
|
||||
)} py-1 px-2 text-xs`}
|
||||
>
|
||||
{text || proposalStatus}
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
import { PythCluster } from '@pythnetwork/client'
|
||||
import { AccountMeta } from '@solana/web3.js'
|
||||
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import {
|
||||
ExecutePostedVaa,
|
||||
MultisigInstruction,
|
||||
MultisigParser,
|
||||
PythGovernanceActionImpl,
|
||||
SetDataSources,
|
||||
WormholeMultisigInstruction,
|
||||
} from 'xc_admin_common'
|
||||
|
||||
export type ProposalStatus =
|
||||
| 'active'
|
||||
| 'executed'
|
||||
| 'cancelled'
|
||||
| 'rejected'
|
||||
| 'expired'
|
||||
| 'executeReady'
|
||||
| 'draft'
|
||||
| 'unkwown'
|
||||
|
||||
export const getProposalStatus = (
|
||||
proposal: TransactionAccount | undefined,
|
||||
multisig: MultisigAccount | undefined
|
||||
): ProposalStatus => {
|
||||
if (multisig && proposal) {
|
||||
const onChainStatus = Object.keys(proposal.status)[0]
|
||||
return proposal.transactionIndex <= multisig.msChangeIndex &&
|
||||
(onChainStatus == 'active' || onChainStatus == 'draft')
|
||||
? 'expired'
|
||||
: (onChainStatus as ProposalStatus)
|
||||
} else {
|
||||
return 'unkwown'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the properties of an object by their values in ascending order.
|
||||
*
|
||||
* @param {Record<string, number>} obj - The object to sort. All property values should be numbers.
|
||||
* @returns {Record<string, number>} A new object with the same properties as the input, but ordered such that the property with the largest numerical value comes first.
|
||||
*
|
||||
* @example
|
||||
* const obj = { a: 2, b: 3, c: 1 };
|
||||
* const sortedObj = sortObjectByValues(obj);
|
||||
* console.log(sortedObj); // Outputs: { b: 3, a: 2, c: 1 }
|
||||
*/
|
||||
const sortObjectByValues = (obj: Record<string, number>) => {
|
||||
const sortedEntries = Object.entries(obj).sort(([, a], [, b]) => b - a)
|
||||
const sortedObj: Record<string, number> = {}
|
||||
for (const [key, value] of sortedEntries) {
|
||||
sortedObj[key] = value
|
||||
}
|
||||
return sortedObj
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a summary of the instructions in a list of multisig instructions.
|
||||
*
|
||||
* @param {MultisigInstruction[]} options.instructions - The list of multisig instructions to summarize.
|
||||
* @param {PythCluster} options.cluster - The Pyth cluster to use for parsing instructions.
|
||||
* @returns {Record<string, number>} A summary of the instructions, where the keys are the names of the instructions and the values are the number of times each instruction appears in the list.
|
||||
*/
|
||||
export const getInstructionsSummary = (options: {
|
||||
instructions: MultisigInstruction[]
|
||||
cluster: PythCluster
|
||||
}) => {
|
||||
const { instructions, cluster } = options
|
||||
|
||||
return sortObjectByValues(
|
||||
instructions.reduce((acc, instruction) => {
|
||||
if (instruction instanceof WormholeMultisigInstruction) {
|
||||
const governanceAction = instruction.governanceAction
|
||||
if (governanceAction instanceof ExecutePostedVaa) {
|
||||
const innerInstructions = governanceAction.instructions
|
||||
innerInstructions.forEach((innerInstruction) => {
|
||||
const multisigParser = MultisigParser.fromCluster(cluster)
|
||||
const parsedInstruction = multisigParser.parseInstruction({
|
||||
programId: innerInstruction.programId,
|
||||
data: innerInstruction.data as Buffer,
|
||||
keys: innerInstruction.keys as AccountMeta[],
|
||||
})
|
||||
acc[parsedInstruction.name] = (acc[parsedInstruction.name] ?? 0) + 1
|
||||
})
|
||||
} else if (governanceAction instanceof PythGovernanceActionImpl) {
|
||||
acc[governanceAction.action] = (acc[governanceAction.action] ?? 0) + 1
|
||||
} else if (governanceAction instanceof SetDataSources) {
|
||||
acc[governanceAction.actionName] =
|
||||
(acc[governanceAction.actionName] ?? 0) + 1
|
||||
} else {
|
||||
acc['unknown'] = (acc['unknown'] ?? 0) + 1
|
||||
}
|
||||
} else {
|
||||
acc[instruction.name] = (acc[instruction.name] ?? 0) + 1
|
||||
}
|
||||
return acc
|
||||
}, {} as Record<string, number>)
|
||||
)
|
||||
}
|
|
@ -21,14 +21,13 @@ import {
|
|||
getMultisigCluster,
|
||||
isRemoteCluster,
|
||||
mapKey,
|
||||
WORMHOLE_ADDRESS,
|
||||
UPGRADE_MULTISIG,
|
||||
MultisigVault,
|
||||
} from 'xc_admin_common'
|
||||
import { ClusterContext } from '../../contexts/ClusterContext'
|
||||
import { useMultisigContext } from '../../contexts/MultisigContext'
|
||||
import { usePythContext } from '../../contexts/PythContext'
|
||||
import CopyIcon from '../../images/icons/copy.inline.svg'
|
||||
import CopyIcon from '@images/icons/copy.inline.svg'
|
||||
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
|
||||
import ClusterSwitch from '../ClusterSwitch'
|
||||
import Modal from '../common/Modal'
|
||||
|
@ -336,7 +335,7 @@ const UpdatePermissions = () => {
|
|||
|
||||
// create anchor wallet when connected
|
||||
useEffect(() => {
|
||||
if (connected && squads) {
|
||||
if (connected && squads && connection) {
|
||||
const provider = new AnchorProvider(
|
||||
connection,
|
||||
squads.wallet as Wallet,
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { PythCluster } from '@pythnetwork/client/lib/cluster'
|
||||
import { createContext, useMemo, useState } from 'react'
|
||||
import { ReactNode, createContext, useMemo, useState } from 'react'
|
||||
|
||||
export const DEFAULT_CLUSTER: PythCluster = 'mainnet-beta'
|
||||
|
||||
export const ClusterContext = createContext<{
|
||||
cluster: PythCluster
|
||||
setCluster: any
|
||||
setCluster: (_cluster: PythCluster) => void
|
||||
}>({
|
||||
cluster: DEFAULT_CLUSTER,
|
||||
setCluster: {},
|
||||
setCluster: () => {},
|
||||
})
|
||||
|
||||
export const ClusterProvider = (props: any) => {
|
||||
export const ClusterProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [cluster, setCluster] = useState<PythCluster>(DEFAULT_CLUSTER)
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
|
@ -22,5 +22,9 @@ export const ClusterProvider = (props: any) => {
|
|||
}),
|
||||
[cluster]
|
||||
)
|
||||
return <ClusterContext.Provider {...props} value={contextValue} />
|
||||
return (
|
||||
<ClusterContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ClusterContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
import SquadsMesh from '@sqds/mesh'
|
||||
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import React, { createContext, useContext, useMemo } from 'react'
|
||||
import { MultisigInstruction } from 'xc_admin_common'
|
||||
import { useMultisig, MultisigHookData } from '../hooks/useMultisig'
|
||||
import { MultisigHookData, useMultisig } from '../hooks/useMultisig'
|
||||
|
||||
const MultisigContext = createContext<MultisigHookData>({
|
||||
upgradeMultisigAccount: undefined,
|
||||
priceFeedMultisigAccount: undefined,
|
||||
upgradeMultisigProposals: [],
|
||||
priceFeedMultisigProposals: [],
|
||||
allProposalsIxsParsed: [],
|
||||
isLoading: true,
|
||||
error: null,
|
||||
squads: undefined,
|
||||
refreshData: undefined,
|
||||
connection: undefined,
|
||||
|
@ -28,13 +23,11 @@ export const MultisigContextProvider: React.FC<
|
|||
> = ({ children }) => {
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
squads,
|
||||
upgradeMultisigAccount,
|
||||
priceFeedMultisigAccount,
|
||||
upgradeMultisigProposals,
|
||||
priceFeedMultisigProposals,
|
||||
allProposalsIxsParsed,
|
||||
refreshData,
|
||||
connection,
|
||||
} = useMultisig()
|
||||
|
@ -45,9 +38,7 @@ export const MultisigContextProvider: React.FC<
|
|||
priceFeedMultisigAccount,
|
||||
upgradeMultisigProposals,
|
||||
priceFeedMultisigProposals,
|
||||
allProposalsIxsParsed,
|
||||
isLoading,
|
||||
error,
|
||||
squads,
|
||||
refreshData,
|
||||
connection,
|
||||
|
@ -55,12 +46,10 @@ export const MultisigContextProvider: React.FC<
|
|||
[
|
||||
squads,
|
||||
isLoading,
|
||||
error,
|
||||
upgradeMultisigAccount,
|
||||
priceFeedMultisigAccount,
|
||||
upgradeMultisigProposals,
|
||||
priceFeedMultisigProposals,
|
||||
allProposalsIxsParsed,
|
||||
refreshData,
|
||||
connection,
|
||||
]
|
||||
|
|
|
@ -5,16 +5,15 @@ import React, {
|
|||
useMemo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import usePyth from '../hooks/usePyth'
|
||||
import { usePyth } from '../hooks/usePyth'
|
||||
import { RawConfig } from '../hooks/usePyth'
|
||||
import { Connection } from '@solana/web3.js'
|
||||
|
||||
// TODO: fix any
|
||||
type AccountKeyToSymbol = { [key: string]: string }
|
||||
interface PythContextProps {
|
||||
rawConfig: RawConfig
|
||||
dataIsLoading: boolean
|
||||
error: any
|
||||
connection: any
|
||||
connection?: Connection
|
||||
priceAccountKeyToSymbolMapping: AccountKeyToSymbol
|
||||
productAccountKeyToSymbolMapping: AccountKeyToSymbol
|
||||
publisherKeyToNameMapping: Record<string, Record<string, string>>
|
||||
|
@ -24,8 +23,6 @@ interface PythContextProps {
|
|||
const PythContext = createContext<PythContextProps>({
|
||||
rawConfig: { mappingAccounts: [] },
|
||||
dataIsLoading: true,
|
||||
error: null,
|
||||
connection: null,
|
||||
priceAccountKeyToSymbolMapping: {},
|
||||
productAccountKeyToSymbolMapping: {},
|
||||
publisherKeyToNameMapping: {},
|
||||
|
@ -44,7 +41,7 @@ export const PythContextProvider: React.FC<PythContextProviderProps> = ({
|
|||
publisherKeyToNameMapping,
|
||||
multisigSignerKeyToNameMapping,
|
||||
}) => {
|
||||
const { isLoading, error, connection, rawConfig } = usePyth()
|
||||
const { isLoading, connection, rawConfig } = usePyth()
|
||||
const [
|
||||
productAccountKeyToSymbolMapping,
|
||||
setProductAccountKeyToSymbolMapping,
|
||||
|
@ -72,7 +69,6 @@ export const PythContextProvider: React.FC<PythContextProviderProps> = ({
|
|||
() => ({
|
||||
rawConfig,
|
||||
dataIsLoading: isLoading,
|
||||
error,
|
||||
connection,
|
||||
priceAccountKeyToSymbolMapping,
|
||||
productAccountKeyToSymbolMapping,
|
||||
|
@ -82,7 +78,6 @@ export const PythContextProvider: React.FC<PythContextProviderProps> = ({
|
|||
[
|
||||
rawConfig,
|
||||
isLoading,
|
||||
error,
|
||||
connection,
|
||||
publisherKeyToNameMapping,
|
||||
multisigSignerKeyToNameMapping,
|
||||
|
|
|
@ -1,27 +1,34 @@
|
|||
import { createContext, useMemo, useState } from 'react'
|
||||
import { ReactNode, createContext, useMemo, useState } from 'react'
|
||||
import { ProposalStatus } from '../components/tabs/Proposals/utils'
|
||||
|
||||
export const DEFAULT_STATUS_FILTER = 'all'
|
||||
|
||||
export type ProposalStatusFilter = 'all' | ProposalStatus
|
||||
|
||||
export const StatusFilterContext = createContext<{
|
||||
statusFilter: string
|
||||
setStatusFilter: any
|
||||
statusFilter: ProposalStatusFilter
|
||||
setStatusFilter: (_statusFilter: ProposalStatusFilter) => void
|
||||
}>({
|
||||
statusFilter: DEFAULT_STATUS_FILTER,
|
||||
setStatusFilter: {},
|
||||
setStatusFilter: () => {},
|
||||
})
|
||||
|
||||
export const StatusFilterProvider = (props: any) => {
|
||||
const [statusFilter, setStatusFilter] = useState<string>(
|
||||
export const StatusFilterProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [statusFilter, setStatusFilter] = useState<ProposalStatusFilter>(
|
||||
DEFAULT_STATUS_FILTER
|
||||
)
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
statusFilter,
|
||||
setStatusFilter: (statusFilter: string) => {
|
||||
setStatusFilter: (statusFilter: ProposalStatusFilter) => {
|
||||
setStatusFilter(statusFilter)
|
||||
},
|
||||
}),
|
||||
[statusFilter]
|
||||
)
|
||||
return <StatusFilterContext.Provider {...props} value={contextValue} />
|
||||
return (
|
||||
<StatusFilterContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</StatusFilterContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,24 +5,21 @@ import SquadsMesh from '@sqds/mesh'
|
|||
import { MultisigAccount, TransactionAccount } from '@sqds/mesh/lib/types'
|
||||
import { useCallback, useContext, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
getMultisigCluster,
|
||||
getProposals,
|
||||
MultisigInstruction,
|
||||
PRICE_FEED_MULTISIG,
|
||||
UPGRADE_MULTISIG,
|
||||
getMultisigCluster,
|
||||
getProposals,
|
||||
} from 'xc_admin_common'
|
||||
import { ClusterContext } from '../contexts/ClusterContext'
|
||||
import { deriveWsUrl, pythClusterApiUrls } from '../utils/pythClusterApiUrl'
|
||||
|
||||
export interface MultisigHookData {
|
||||
isLoading: boolean
|
||||
error: any // TODO: fix any
|
||||
squads: SquadsMesh | undefined
|
||||
upgradeMultisigAccount: MultisigAccount | undefined
|
||||
priceFeedMultisigAccount: MultisigAccount | undefined
|
||||
upgradeMultisigProposals: TransactionAccount[]
|
||||
priceFeedMultisigProposals: TransactionAccount[]
|
||||
allProposalsIxsParsed: MultisigInstruction[][]
|
||||
connection?: Connection
|
||||
refreshData?: () => { fetchData: () => Promise<void>; cancel: () => void }
|
||||
}
|
||||
|
@ -39,7 +36,6 @@ export const useMultisig = (): MultisigHookData => {
|
|||
const wallet = useAnchorWallet()
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
const [upgradeMultisigAccount, setUpgradeMultisigAccount] =
|
||||
useState<MultisigAccount>()
|
||||
const [priceFeedMultisigAccount, setPriceFeedMultisigAccount] =
|
||||
|
@ -50,17 +46,10 @@ export const useMultisig = (): MultisigHookData => {
|
|||
const [priceFeedMultisigProposals, setPriceFeedMultisigProposals] = useState<
|
||||
TransactionAccount[]
|
||||
>([])
|
||||
const [allProposalsIxsParsed, setAllProposalsIxsParsed] = useState<
|
||||
MultisigInstruction[][]
|
||||
>([])
|
||||
const [squads, setSquads] = useState<SquadsMesh | undefined>()
|
||||
|
||||
const [urlsIndex, setUrlsIndex] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
setError(null)
|
||||
}, [urlsIndex, cluster])
|
||||
|
||||
useEffect(() => {
|
||||
setUrlsIndex(0)
|
||||
}, [cluster])
|
||||
|
@ -132,8 +121,6 @@ export const useMultisig = (): MultisigHookData => {
|
|||
if (cancelled) return
|
||||
const urls = pythClusterApiUrls(multisigCluster)
|
||||
if (urlsIndex === urls.length - 1) {
|
||||
// @ts-ignore
|
||||
setError(e)
|
||||
setIsLoading(false)
|
||||
console.warn(`Failed to fetch accounts`)
|
||||
} else if (urlsIndex < urls.length - 1) {
|
||||
|
@ -159,13 +146,11 @@ export const useMultisig = (): MultisigHookData => {
|
|||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
squads,
|
||||
upgradeMultisigAccount,
|
||||
priceFeedMultisigAccount,
|
||||
upgradeMultisigProposals,
|
||||
priceFeedMultisigProposals,
|
||||
allProposalsIxsParsed,
|
||||
refreshData,
|
||||
connection,
|
||||
}
|
||||
|
|
|
@ -15,11 +15,8 @@ import { useContext, useEffect, useRef, useState } from 'react'
|
|||
import { ClusterContext } from '../contexts/ClusterContext'
|
||||
import { deriveWsUrl, pythClusterApiUrls } from '../utils/pythClusterApiUrl'
|
||||
|
||||
const ONES = '11111111111111111111111111111111'
|
||||
|
||||
interface PythHookData {
|
||||
isLoading: boolean
|
||||
error: any // TODO: fix any
|
||||
rawConfig: RawConfig
|
||||
connection?: Connection
|
||||
}
|
||||
|
@ -47,17 +44,15 @@ export type PriceRawConfig = {
|
|||
publishers: PublicKey[]
|
||||
}
|
||||
|
||||
const usePyth = (): PythHookData => {
|
||||
export const usePyth = (): PythHookData => {
|
||||
const connectionRef = useRef<Connection>()
|
||||
const { cluster } = useContext(ClusterContext)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
const [rawConfig, setRawConfig] = useState<RawConfig>({ mappingAccounts: [] })
|
||||
const [urlsIndex, setUrlsIndex] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
setError(null)
|
||||
}, [urlsIndex, cluster])
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -127,7 +122,7 @@ const usePyth = (): PythHookData => {
|
|||
} else {
|
||||
let priceAccountKey: string | undefined =
|
||||
parsed.priceAccountKey.toBase58()
|
||||
let priceAccounts = []
|
||||
const priceAccounts = []
|
||||
while (priceAccountKey) {
|
||||
const toAdd: PriceRawConfig = priceRawConfigs[priceAccountKey]
|
||||
priceAccounts.push(toAdd)
|
||||
|
@ -196,8 +191,6 @@ const usePyth = (): PythHookData => {
|
|||
} catch (e) {
|
||||
if (cancelled) return
|
||||
if (urlsIndex === urls.length - 1) {
|
||||
// @ts-ignore
|
||||
setError(e)
|
||||
setIsLoading(false)
|
||||
console.warn(`Failed to fetch accounts`)
|
||||
} else if (urlsIndex < urls.length - 1) {
|
||||
|
@ -213,10 +206,7 @@ const usePyth = (): PythHookData => {
|
|||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
connection: connectionRef.current,
|
||||
rawConfig,
|
||||
}
|
||||
}
|
||||
|
||||
export default usePyth
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
const path = require('path')
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
|
@ -16,6 +18,11 @@ const nextConfig = {
|
|||
loader: require.resolve('@svgr/webpack'),
|
||||
})
|
||||
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
'@images': path.resolve(__dirname, 'images/'),
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
}
|
||||
|
|
|
@ -40,8 +40,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^6.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"eslint": "8.22.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-next": "12.2.5",
|
||||
"postcss": "^8.4.16",
|
||||
"prettier": "^2.7.1",
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
|||
import { useEffect, useState } from 'react'
|
||||
import Layout from '../components/layout/Layout'
|
||||
import General from '../components/tabs/General'
|
||||
import Proposals from '../components/tabs/Proposals'
|
||||
import Proposals from '../components/tabs/Proposals/Proposals'
|
||||
import UpdatePermissions from '../components/tabs/UpdatePermissions'
|
||||
import { MultisigContextProvider } from '../contexts/MultisigContext'
|
||||
import { PythContextProvider } from '../contexts/PythContext'
|
||||
|
|
|
@ -13,7 +13,11 @@
|
|||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"@images/*": ["./images/*"],
|
||||
"xc-admin-common": ["../xc_admin_common/src"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
|
|
|
@ -1459,26 +1459,6 @@
|
|||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"express_relay/examples/easy_lend/node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"express_relay/examples/easy_lend/node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"express_relay/examples/easy_lend/node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
|
@ -1817,26 +1797,6 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"express_relay/sdk/js/node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"express_relay/sdk/js/node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"express_relay/sdk/js/node_modules/@jest/console": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz",
|
||||
|
@ -5069,8 +5029,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "^6.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"eslint": "8.22.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-next": "12.2.5",
|
||||
"postcss": "^8.4.16",
|
||||
"prettier": "^2.7.1",
|
||||
|
@ -5133,6 +5094,257 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz",
|
||||
"integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/type-utils": "7.7.1",
|
||||
"@typescript-eslint/utils": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/eslint-plugin/node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/parser": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz",
|
||||
"integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz",
|
||||
"integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz",
|
||||
"integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"@typescript-eslint/utils": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/type-utils/node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/types": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz",
|
||||
"integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz",
|
||||
"integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/typescript-estree/node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/utils": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz",
|
||||
"integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.56.0"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz",
|
||||
"integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || >=20.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/cross-fetch": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
|
||||
|
@ -5154,50 +5366,49 @@
|
|||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/eslint": {
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
|
||||
"integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint/eslintrc": "^1.3.0",
|
||||
"@humanwhocodes/config-array": "^0.10.4",
|
||||
"@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
|
||||
"ajv": "^6.10.0",
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/js": "8.56.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.3",
|
||||
"esquery": "^1.4.0",
|
||||
"eslint-scope": "^7.2.2",
|
||||
"eslint-visitor-keys": "^3.4.3",
|
||||
"espree": "^9.6.1",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"find-up": "^5.0.0",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^6.0.1",
|
||||
"globals": "^13.15.0",
|
||||
"globby": "^11.1.0",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"glob-parent": "^6.0.2",
|
||||
"globals": "^13.19.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
"optionator": "^0.9.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"bin": {
|
||||
"eslint": "bin/eslint.js"
|
||||
|
@ -5276,6 +5487,18 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
|
@ -5306,6 +5529,21 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"lru-cache": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"governance/xc_admin/packages/xc_admin_frontend/node_modules/web3": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/web3/-/web3-4.8.0.tgz",
|
||||
|
@ -10047,29 +10285,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.10.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
|
||||
"integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
|
||||
"dev": true,
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.4"
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/gitignore-to-minimatch": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
|
||||
"integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
|
@ -10083,9 +10310,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="
|
||||
},
|
||||
"node_modules/@hutson/parse-repository-url": {
|
||||
"version": "3.0.2",
|
||||
|
@ -22040,9 +22267,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
|
@ -22235,9 +22462,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw=="
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="
|
||||
},
|
||||
"node_modules/@types/serve-index": {
|
||||
"version": "1.9.1",
|
||||
|
@ -30391,19 +30618,6 @@
|
|||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
|
@ -35004,9 +35218,9 @@
|
|||
]
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
|
@ -64059,31 +64273,24 @@
|
|||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.10.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz",
|
||||
"integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==",
|
||||
"dev": true,
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"requires": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.4"
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/gitignore-to-minimatch": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
|
||||
"integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
|
||||
"dev": true
|
||||
},
|
||||
"@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="
|
||||
},
|
||||
"@humanwhocodes/object-schema": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="
|
||||
},
|
||||
"@hutson/parse-repository-url": {
|
||||
"version": "3.0.2",
|
||||
|
@ -68614,23 +68821,6 @@
|
|||
"strip-json-comments": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"@jest/console": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz",
|
||||
|
@ -77796,9 +77986,9 @@
|
|||
}
|
||||
},
|
||||
"@types/json-schema": {
|
||||
"version": "7.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
|
||||
"integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="
|
||||
"version": "7.0.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="
|
||||
},
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
|
@ -77990,9 +78180,9 @@
|
|||
}
|
||||
},
|
||||
"@types/semver": {
|
||||
"version": "7.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw=="
|
||||
"version": "7.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz",
|
||||
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ=="
|
||||
},
|
||||
"@types/serve-index": {
|
||||
"version": "1.9.1",
|
||||
|
@ -84064,23 +84254,6 @@
|
|||
"integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
|
||||
"dev": true
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/object-schema": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
|
@ -84797,16 +84970,6 @@
|
|||
"text-table": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||
"integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
|
||||
"requires": {
|
||||
"@humanwhocodes/object-schema": "^1.2.1",
|
||||
"debug": "^4.1.1",
|
||||
"minimatch": "^3.0.5"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
|
@ -88921,9 +89084,9 @@
|
|||
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
|
||||
},
|
||||
"ignore": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
|
||||
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ=="
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
|
||||
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw=="
|
||||
},
|
||||
"ignore-walk": {
|
||||
"version": "5.0.1",
|
||||
|
@ -107414,10 +107577,11 @@
|
|||
"@types/node": "^18.11.18",
|
||||
"@types/react": "18.0.26",
|
||||
"@types/react-dom": "18.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"autoprefixer": "^10.4.8",
|
||||
"axios": "^1.4.0",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"eslint": "8.22.0",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-next": "12.2.5",
|
||||
"gsap": "^3.11.4",
|
||||
"next": "12.2.5",
|
||||
|
@ -107475,6 +107639,153 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/eslint-plugin": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz",
|
||||
"integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/type-utils": "7.7.1",
|
||||
"@typescript-eslint/utils": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/parser": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.7.1.tgz",
|
||||
"integrity": "sha512-vmPzBOOtz48F6JAGVS/kZYk4EkXao6iGrD838sp1w3NQQC0W8ry/q641KU4PrG7AKNAf56NOcR8GOpH8l9FPCw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/scope-manager": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.7.1.tgz",
|
||||
"integrity": "sha512-PytBif2SF+9SpEUKynYn5g1RHFddJUcyynGpztX3l/ik7KmZEv19WCMhUBkHXPU9es/VWGD3/zg3wg90+Dh2rA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/type-utils": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz",
|
||||
"integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"@typescript-eslint/utils": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/types": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.7.1.tgz",
|
||||
"integrity": "sha512-AmPmnGW1ZLTpWa+/2omPrPfR7BcbUU4oha5VIbSbS1a1Tv966bklvLNXxp3mrbc+P2j4MNOTfDffNsk4o0c6/w==",
|
||||
"dev": true
|
||||
},
|
||||
"@typescript-eslint/typescript-estree": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.7.1.tgz",
|
||||
"integrity": "sha512-CXe0JHCXru8Fa36dteXqmH2YxngKJjkQLjxzoj6LYwzZ7qZvgsLSc+eqItCrqIop8Vl2UKoAi0StVWu97FQZIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/visitor-keys": "7.7.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^1.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimatch": {
|
||||
"version": "9.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
|
||||
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/utils": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz",
|
||||
"integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@typescript-eslint/scope-manager": "7.7.1",
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"@typescript-eslint/typescript-estree": "7.7.1",
|
||||
"semver": "^7.6.0"
|
||||
}
|
||||
},
|
||||
"@typescript-eslint/visitor-keys": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.7.1.tgz",
|
||||
"integrity": "sha512-gBL3Eq25uADw1LQ9kVpf3hRM+DWzs0uZknHYK3hq4jcTPqVCClHGDnB6UUUV2SFeBeA4KWHWbbLqmbGcZ4FYbw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@typescript-eslint/types": "7.7.1",
|
||||
"eslint-visitor-keys": "^3.4.3"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"cross-fetch": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
|
||||
|
@ -107490,50 +107801,49 @@
|
|||
"dev": true
|
||||
},
|
||||
"eslint": {
|
||||
"version": "8.22.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
|
||||
"integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
|
||||
"version": "8.56.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@eslint/eslintrc": "^1.3.0",
|
||||
"@humanwhocodes/config-array": "^0.10.4",
|
||||
"@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
|
||||
"ajv": "^6.10.0",
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
"@eslint/eslintrc": "^2.1.4",
|
||||
"@eslint/js": "8.56.0",
|
||||
"@humanwhocodes/config-array": "^0.11.13",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@nodelib/fs.walk": "^1.2.8",
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"ajv": "^6.12.4",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.2",
|
||||
"debug": "^4.3.2",
|
||||
"doctrine": "^3.0.0",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"eslint-scope": "^7.1.1",
|
||||
"eslint-utils": "^3.0.0",
|
||||
"eslint-visitor-keys": "^3.3.0",
|
||||
"espree": "^9.3.3",
|
||||
"esquery": "^1.4.0",
|
||||
"eslint-scope": "^7.2.2",
|
||||
"eslint-visitor-keys": "^3.4.3",
|
||||
"espree": "^9.6.1",
|
||||
"esquery": "^1.4.2",
|
||||
"esutils": "^2.0.2",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"file-entry-cache": "^6.0.1",
|
||||
"find-up": "^5.0.0",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob-parent": "^6.0.1",
|
||||
"globals": "^13.15.0",
|
||||
"globby": "^11.1.0",
|
||||
"grapheme-splitter": "^1.0.4",
|
||||
"glob-parent": "^6.0.2",
|
||||
"globals": "^13.19.0",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.0.0",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"is-path-inside": "^3.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.4.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.1",
|
||||
"regexpp": "^3.2.0",
|
||||
"optionator": "^0.9.3",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"strip-json-comments": "^3.1.0",
|
||||
"text-table": "^0.2.0",
|
||||
"v8-compile-cache": "^2.0.3"
|
||||
"text-table": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"ethereum-cryptography": {
|
||||
|
@ -107586,6 +107896,15 @@
|
|||
"p-locate": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
|
@ -107604,6 +107923,15 @@
|
|||
"p-limit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
|
||||
"integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"web3": {
|
||||
"version": "4.8.0",
|
||||
"resolved": "https://registry.npmjs.org/web3/-/web3-4.8.0.tgz",
|
||||
|
|
Loading…
Reference in New Issue