diff --git a/GatewayPlugin/config.ts b/GatewayPlugin/config.ts new file mode 100644 index 0000000000..734f8b660c --- /dev/null +++ b/GatewayPlugin/config.ts @@ -0,0 +1,23 @@ +// A list of "passes" offered by Civic to verify or gate access to a DAO. +export const availablePasses = [ + { + name: 'Uniqueness', + value: 'uniqobk8oGh4XBLMqM68K8M2zNu3CdYX7q5go7whQiv', + description: 'A biometric proof of personhood, preventing Sybil attacks while retaining privacy' + }, + { + name: 'ID Verification', + value: 'bni1ewus6aMxTxBi5SAfzEmmXLf8KcVFRmTfproJuKw', + description: 'A KYC process for your DAO, allowing users to prove their identity by presenting a government-issued ID' + }, + { + name: 'Bot Resistance', + value: 'ignREusXmGrscGNUesoU9mxfds9AiYTezUKex2PsZV6', + description: 'A simple CAPTCHA to prevent bots from spamming your DAO' + }, + { + name: 'Other', + value: '', + description: 'Set up your own custom verification (contact Civic.com for options)' + }, +] as const; \ No newline at end of file diff --git a/HeliumVotePlugin/components/LockTokensAccount.tsx b/HeliumVotePlugin/components/LockTokensAccount.tsx index c3bb1450f6..882ca86e15 100644 --- a/HeliumVotePlugin/components/LockTokensAccount.tsx +++ b/HeliumVotePlugin/components/LockTokensAccount.tsx @@ -401,7 +401,6 @@ export const LockTokensAccount: React.FC<{ diff --git a/HeliumVotePlugin/components/VotingPowerCard.tsx b/HeliumVotePlugin/components/VotingPowerCard.tsx index 3b20531b05..78fc7167e8 100644 --- a/HeliumVotePlugin/components/VotingPowerCard.tsx +++ b/HeliumVotePlugin/components/VotingPowerCard.tsx @@ -63,7 +63,6 @@ export const VotingPowerCard: React.FC<{ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..f49a4e16e6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/PythVotePlugin/components/PythAccountDetails.tsx b/PythVotePlugin/components/PythAccountDetails.tsx new file mode 100644 index 0000000000..09c81443b1 --- /dev/null +++ b/PythVotePlugin/components/PythAccountDetails.tsx @@ -0,0 +1,142 @@ +import { MintInfo } from '@solana/spl-token' +import BN from 'bn.js' +import useRealm from '@hooks/useRealm' +import { GoverningTokenType } from '@solana/spl-governance' +import { fmtMintAmount } from '@tools/sdk/units' +import { useEffect } from 'react' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { + useUserCommunityTokenOwnerRecord, +} from '@hooks/queries/tokenOwnerRecord' +import { useRealmConfigQuery } from '@hooks/queries/realmConfig' +import VanillaWithdrawTokensButton from '@components/TokenBalance/VanillaWithdrawTokensButton' +import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' +import PythVotingPower from './PythVotingPower' + +export const PYTH_INSTRUCTIONS = "You can deposit Pyth tokens at https://staking.pyth.network/. If you previously deposited tokens on https://app.realms.today/dao/PYTH, use the button below to withdraw them immediately. Those tokens have no voting power." + +const TokenDeposit = ({ + mint, + inAccountDetails, + setHasGovPower, +}: { + mint: MintInfo | undefined + inAccountDetails?: boolean + setHasGovPower?: (hasGovPower: boolean) => void +}) => { + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + + const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result + const config = useRealmConfigQuery().data?.result + + const relevantTokenConfig = config?.account.communityTokenConfig + const isMembership = + relevantTokenConfig?.tokenType === GoverningTokenType.Membership + + const { realmTokenAccount } = useRealm() + + const depositTokenRecord = ownTokenRecord + const depositTokenAccount = realmTokenAccount + + const hasTokensInWallet = + depositTokenAccount && depositTokenAccount.account.amount.gt(new BN(0)) + + const hasTokensDeposited = + depositTokenRecord && + depositTokenRecord.account.governingTokenDepositAmount.gt(new BN(0)) + + const availableTokens = + depositTokenRecord && mint + ? fmtMintAmount( + mint, + depositTokenRecord.account.governingTokenDepositAmount + ) + : '0' + + useEffect(() => { + if (availableTokens != '0' || hasTokensDeposited || hasTokensInWallet) { + if (setHasGovPower) setHasGovPower(true) + } + }, [availableTokens, hasTokensDeposited, hasTokensInWallet, setHasGovPower]) + + const canShowAvailableTokensMessage = hasTokensInWallet && connected + const tokensToShow = + hasTokensInWallet && depositTokenAccount + ? fmtMintAmount(mint, depositTokenAccount.account.amount) + : hasTokensInWallet + ? availableTokens + : 0 + + // Do not show deposits for mints with zero supply because nobody can deposit anyway + if (!mint || mint.supply.isZero()) { + return null + } + + return ( +
+ {(availableTokens != '0' || inAccountDetails) && ( +
+ +
+ )} + +
+ You have {tokensToShow} {hasTokensDeposited ? `more ` : ``} tokens available to deposit. +
+
+ {PYTH_INSTRUCTIONS} +
+ +
+ {!isMembership && // Membership tokens can't be withdrawn (that is their whole point, actually) + inAccountDetails && ( + + )} +
+
+ ) +} + +const PythAccountDetails = () => { + const mint = useRealmCommunityMintInfoQuery().data?.result + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + const hasLoaded = mint + + return ( + <> + {hasLoaded ? ( +
+ {!connected && ( +
+ Connect your wallet to see governance power +
+ )} + {( + + )} +
+ ) : ( + <> +
+
+ + )} + + ) +} + +export default PythAccountDetails diff --git a/PythVotePlugin/components/PythVotingPower.tsx b/PythVotePlugin/components/PythVotingPower.tsx new file mode 100644 index 0000000000..39bc29442c --- /dev/null +++ b/PythVotePlugin/components/PythVotingPower.tsx @@ -0,0 +1,109 @@ +import { BigNumber } from 'bignumber.js' +import { useMemo } from 'react' +import { useRealmQuery } from '@hooks/queries/realm' +import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' +import { useConnection } from '@solana/wallet-adapter-react' +import { getPythGovPower } from '@hooks/queries/governancePower' +import { useAsync } from 'react-async-hook' +import BN from 'bn.js' +import { getMintMetadata } from '@components/instructions/programs/splToken' +import VotingPowerPct from '@components/ProposalVotingPower/VotingPowerPct' +import clsx from 'clsx' +import { useRealmConfigQuery } from '@hooks/queries/realmConfig' +import { GoverningTokenType } from '@solana/spl-governance' +import usePythScalingFactor from '@hooks/PythNetwork/useScalingFactor' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' + +export const PYTH_INSTRUCTIONS = "You can deposit Pyth tokens at https://staking.pyth.network/. If you previously deposited tokens on https://app.realms.today/dao/PYTH, use the button below to withdraw them immediately. Those tokens have no voting power." + +interface Props { + className?: string + role: 'community' | 'council' + hideIfZero?: boolean + children?: React.ReactNode +} + +export default function PythVotingPower({ + role, + hideIfZero, + children, + ...props +}: Props) { + const realm = useRealmQuery().data?.result + const realmConfig = useRealmConfigQuery().data?.result + + const wallet = useWalletOnePointOh(); + + + const { connection } = useConnection() + + const relevantMint = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + + const mintInfo = useMintInfoByPubkeyQuery(relevantMint).data?.result + + const { result: personalAmount } = useAsync( + async () => wallet?.publicKey && getPythGovPower(connection, wallet?.publicKey), + [connection, wallet] + ) + + const pythScalingFactor: number | undefined = usePythScalingFactor(); + + const totalAmount = personalAmount ?? new BN(0) + + const formattedTotal = useMemo( + () => + mintInfo && totalAmount !== undefined + ? new BigNumber(totalAmount.toString()) + .multipliedBy(pythScalingFactor ?? 1) + .shiftedBy(-mintInfo.decimals) + .integerValue() + .toString() + : undefined, + [totalAmount, mintInfo] + ) + + const tokenName = + getMintMetadata(relevantMint)?.name ?? realm?.account.name ?? '' + + const disabled = + role === 'community' + ? realmConfig?.account.communityTokenConfig.tokenType === + GoverningTokenType.Dormant + : realmConfig?.account.councilTokenConfig.tokenType === + GoverningTokenType.Dormant + + return ( +
+
+
+ {tokenName} + {role === 'council' ? ' Council' : ''} Votes +
+
+
+
+ {formattedTotal ?? 0} +
+
+ + {mintInfo && ( + + )} +
+
+ {children} +
+ ) +} diff --git a/VoteStakeRegistry/components/Account/LockTokensAccount.tsx b/VoteStakeRegistry/components/Account/LockTokensAccount.tsx index c486b37120..e8c56a3b29 100644 --- a/VoteStakeRegistry/components/Account/LockTokensAccount.tsx +++ b/VoteStakeRegistry/components/Account/LockTokensAccount.tsx @@ -415,7 +415,6 @@ const LockTokensAccount: React.FC<{
diff --git a/VoteStakeRegistry/components/Account/LockTokensAccountWithdraw.tsx b/VoteStakeRegistry/components/Account/LockTokensAccountWithdraw.tsx index 8a97d2a872..c0a4c58665 100644 --- a/VoteStakeRegistry/components/Account/LockTokensAccountWithdraw.tsx +++ b/VoteStakeRegistry/components/Account/LockTokensAccountWithdraw.tsx @@ -438,7 +438,6 @@ const LockTokensAccount = ({ tokenOwnerRecordPk }) => {
diff --git a/VoteStakeRegistry/components/Account/LockTokensModal.tsx b/VoteStakeRegistry/components/Account/LockTokensModal.tsx index fa67087e0d..f211202819 100644 --- a/VoteStakeRegistry/components/Account/LockTokensModal.tsx +++ b/VoteStakeRegistry/components/Account/LockTokensModal.tsx @@ -110,7 +110,14 @@ const LockTokensModal = ({ display: '5y', }, { - defaultValue: 1, + defaultValue: depositToUnlock + ? Math.ceil( + secsToDays( + depositToUnlock?.lockup.endTs.toNumber() - + depositToUnlock.lockup.startTs.toNumber() + ) + ) + : 1, display: 'Custom', }, ] @@ -142,6 +149,7 @@ const LockTokensModal = ({ x.lockup.kind.none ) const [lockupPeriodDays, setLockupPeriodDays] = useState(0) + const allowClawback = false const [lockupPeriod, setLockupPeriod] = useState(lockupPeriods[0]) const [amount, setAmount] = useState() @@ -169,6 +177,7 @@ const LockTokensModal = ({ depositToUnlock?.amountInitiallyLockedNative ) : 0 + const maxAmountToLock = depositRecord && mint ? wantToLockMoreThenDeposited @@ -431,7 +440,7 @@ const LockTokensModal = ({ values={lockupPeriods.map((p) => p.display)} /> - {lockupPeriod.defaultValue === 1 && ( + {lockupPeriod.display === 'Custom' && ( <>
Number of days diff --git a/VoteStakeRegistry/components/TokenBalance/LockPluginTokenBalanceCard.tsx b/VoteStakeRegistry/components/TokenBalance/LockPluginTokenBalanceCard.tsx index 77cd8bcfbe..4435986393 100644 --- a/VoteStakeRegistry/components/TokenBalance/LockPluginTokenBalanceCard.tsx +++ b/VoteStakeRegistry/components/TokenBalance/LockPluginTokenBalanceCard.tsx @@ -133,7 +133,6 @@ const LockPluginTokenBalanceCard = ({
diff --git a/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx b/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx index 7dfe0e7caf..8106a94a33 100644 --- a/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx +++ b/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx @@ -68,7 +68,7 @@ export default function VSRCommunityVotingPower(props: Props) { .shiftedBy(-mint.decimals) : new BigNumber('0') - const delegatedTors = useTokenOwnerRecordsDelegatedToUser() + const { data: delegatedTors } = useTokenOwnerRecordsDelegatedToUser() const selectedDelegator = useSelectedDelegatorStore( (s) => s.communityDelegator ) diff --git a/VoteStakeRegistry/components/instructions/Clawback.tsx b/VoteStakeRegistry/components/instructions/Clawback.tsx index 49a13b802f..b52fd555b6 100644 --- a/VoteStakeRegistry/components/instructions/Clawback.tsx +++ b/VoteStakeRegistry/components/instructions/Clawback.tsx @@ -5,7 +5,7 @@ import React, { useMemo, useState, } from 'react' -import { TransactionInstruction } from '@solana/web3.js' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' import { tryGetMint } from '@utils/tokens' import { ClawbackForm, @@ -231,6 +231,23 @@ const Clawback = ({ } return ( <> +

+ Use only with realm authority governance cant be executed with other + governances +

+

governance: {realmAuthorityGov?.pubkey.toBase58()}

+

+ wallet:{' '} + {realmAuthorityGov + ? PublicKey.findProgramAddressSync( + [ + Buffer.from('native-treasury'), + realmAuthorityGov!.pubkey.toBuffer(), + ], + realm!.owner + )[0].toBase58() + : null} +

+ handleSetForm({ + value: evt.target.value, + propertyName: 'bufferSpillAddress', + }) + } + noMaxWidth={true} + error={formErrors['bufferSpillAddress']} + /> diff --git a/components/GovernancePower/GovernancePowerForRole.tsx b/components/GovernancePower/GovernancePowerForRole.tsx index 6b627cbc9f..0b3cc1a541 100644 --- a/components/GovernancePower/GovernancePowerForRole.tsx +++ b/components/GovernancePower/GovernancePowerForRole.tsx @@ -3,15 +3,15 @@ import { useAsync } from 'react-async-hook' import { determineVotingPowerType } from '@hooks/queries/governancePower' import { useConnection } from '@solana/wallet-adapter-react' import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' -import LockedCommunityVotingPower from '@components/ProposalVotingPower/LockedCommunityVotingPower' import NftVotingPower from '@components/ProposalVotingPower/NftVotingPower' import LockedCommunityNFTRecordVotingPower from '@components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower' import VanillaVotingPower from './Vanilla/VanillaVotingPower' import { Deposit } from './Vanilla/Deposit' import { useUserCommunityTokenOwnerRecord } from '@hooks/queries/tokenOwnerRecord' import { ExclamationIcon } from '@heroicons/react/solid' -import { VSR_PLUGIN_PKS } from '@constants/plugins' -import { useRealmConfigQuery } from '@hooks/queries/realmConfig' +import VanillaWithdrawTokensButton from '@components/TokenBalance/VanillaWithdrawTokensButton' +import LockedCommunityVotingPower from '@components/ProposalVotingPower/LockedCommunityVotingPower' +import PythVotingPower from 'PythVotePlugin/components/PythVotingPower' export default function GovernancePowerForRole({ role, @@ -23,16 +23,11 @@ export default function GovernancePowerForRole({ }) { const { connection } = useConnection() const realmPk = useSelectedRealmPubkey() - const config = useRealmConfigQuery().data?.result const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result - //if dao transited to use plugin and some users have still deposited tokens they should withdraw before + + //VSR if dao transited to use plugin and some users have still deposited tokens they should withdraw before //depositing to plugin - const isVsr = - config?.account?.communityTokenConfig?.voterWeightAddin && - VSR_PLUGIN_PKS.includes( - config?.account?.communityTokenConfig?.voterWeightAddin?.toBase58() - ) const didWithdrawFromVanillaSetup = !ownTokenRecord || ownTokenRecord.account.governingTokenDepositAmount.isZero() @@ -42,10 +37,8 @@ export default function GovernancePowerForRole({ const { result: kind } = useAsync(async () => { if (realmPk === undefined) return undefined - return didWithdrawFromVanillaSetup - ? determineVotingPowerType(connection, realmPk, role) - : 'vanilla' - }, [connection, realmPk, role, didWithdrawFromVanillaSetup]) + return determineVotingPowerType(connection, realmPk, role) + }, [connection, realmPk, role]) if (connected && kind === undefined && !props.hideIfZero) { return ( @@ -60,21 +53,35 @@ export default function GovernancePowerForRole({
- {isVsr && !didWithdrawFromVanillaSetup && ( - - - Please withdraw your tokens and deposit again to get governance - power - - )}
) : kind === 'VSR' ? ( - + didWithdrawFromVanillaSetup ? ( + + ) : ( + //TODO make a better generic little prompt for when a plugin is used but there are still tokens in vanilla + <> + +
+
+ + + Please withdraw your tokens and deposit again to get + governance power + +
+
+ +
+
+ + ) ) : kind === 'NFT' ? ( - - ) : kind === 'HeliumVSR' ? ( - - ) : null + ) + : kind === 'pyth' ? ( + + ) : kind === 'HeliumVSR' ? ( + + ) : null ) : kind === 'vanilla' ? (
diff --git a/components/GovernancePower/Vanilla/VanillaVotingPower.tsx b/components/GovernancePower/Vanilla/VanillaVotingPower.tsx index 938df7198b..421c983214 100644 --- a/components/GovernancePower/Vanilla/VanillaVotingPower.tsx +++ b/components/GovernancePower/Vanilla/VanillaVotingPower.tsx @@ -59,7 +59,7 @@ export default function VanillaVotingPower({ role === 'community' ? s.communityDelegator : s.councilDelegator ) - const torsDelegatedToUser = useTokenOwnerRecordsDelegatedToUser() + const { data: torsDelegatedToUser } = useTokenOwnerRecordsDelegatedToUser() const { result: delegatorsAmount } = useAsync( async () => diff --git a/components/Mango/ProgramSelector.tsx b/components/Mango/ProgramSelector.tsx new file mode 100644 index 0000000000..ba8bf37f85 --- /dev/null +++ b/components/Mango/ProgramSelector.tsx @@ -0,0 +1,73 @@ +import { useEffect, useState } from 'react' +import { + BOOST_MAINNET_GROUP, + MANGO_BOOST_PROGRAM_ID, + MANGO_V4_MAINNET_GROUP, +} from '@hooks/useMangoV4' +import { MANGO_V4_ID } from '@blockworks-foundation/mango-v4' +import { PublicKey } from '@metaplex-foundation/js' +import useProgramSelector from './useProgramSelector' +import { InstructionInputType } from 'pages/dao/[symbol]/proposal/components/instructions/inputInstructionType' +import InstructionForm, { + InstructionInput, +} from 'pages/dao/[symbol]/proposal/components/instructions/FormCreator' + +type Program = { name: string; val: PublicKey; group: PublicKey } + +interface ProgramSelectorForm { + program: Program +} + +const ProgramSelector = ({ + programSelectorHook, +}: { + programSelectorHook: ReturnType +}) => { + const programs: Program[] = [ + { + name: 'Mango v4 program', + val: MANGO_V4_ID['mainnet-beta'], + group: MANGO_V4_MAINNET_GROUP, + }, + { + name: 'JLP boost program', + val: MANGO_BOOST_PROGRAM_ID, + group: BOOST_MAINNET_GROUP, + }, + ] + const [form, setForm] = useState({ + program: programs[0], + }) + + useEffect(() => { + if (programSelectorHook.setProgram) { + programSelectorHook.setProgram(form.program) + } + }, [form.program, programSelectorHook]) + + const inputs: InstructionInput[] = [ + { + label: 'Program', + name: 'program', + type: InstructionInputType.SELECT, + initialValue: form.program, + options: programs, + }, + ] + + return ( + <> + {form && ( + null} + formErrors={{}} + > + )} + + ) +} + +export default ProgramSelector diff --git a/components/Mango/useProgramSelector.tsx b/components/Mango/useProgramSelector.tsx new file mode 100644 index 0000000000..03a61bff6b --- /dev/null +++ b/components/Mango/useProgramSelector.tsx @@ -0,0 +1,14 @@ +import { PublicKey } from '@solana/web3.js' +import { useState } from 'react' + +type Program = { name: string; val: PublicKey; group: PublicKey } + +const useProgramSelector = () => { + const [program, setProgram] = useState() + return { + program, + setProgram, + } +} + +export default useProgramSelector diff --git a/components/Profile/useProfile.ts b/components/Profile/useProfile.ts index 7c07b85e96..a2b1acbe92 100644 --- a/components/Profile/useProfile.ts +++ b/components/Profile/useProfile.ts @@ -1,31 +1,13 @@ -import { useEffect, useState } from 'react' -import { Connection, PublicKey } from '@solana/web3.js' +import { PublicKey } from '@solana/web3.js' import { CivicProfile, Profile as BaseProfile } from '@civic/profile' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { useQuery } from '@tanstack/react-query' type Profile = BaseProfile & { exists: boolean } -const profiles = new Map>() - -const getProfile = async ( - publicKey: PublicKey, - connection?: Connection -): Promise => { - const cached = profiles.get(publicKey.toBase58()); - if (cached) return cached; - - const options = connection ? { solana: { connection } } : undefined; - - const promise = CivicProfile.get(publicKey.toBase58(), options); - - profiles.set(publicKey.toBase58(), promise) - - return promise; -} - const profileIsSet = (profile: BaseProfile): boolean => !!profile.name || !!profile.image || !!profile.headline @@ -34,25 +16,24 @@ export const useProfile = ( ): { profile: Profile | undefined; loading: boolean } => { const connection = useLegacyConnectionContext() const connectedWallet = useWalletOnePointOh() - const [profile, setProfile] = useState() - const [loading, setLoading] = useState(true) const profileWalletPublicKey = publicKey || connectedWallet?.publicKey - - useEffect(() => { - if (profileWalletPublicKey) { - getProfile(profileWalletPublicKey, connection?.current).then( - (profile) => { - setProfile({ - ...profile, - exists: profileIsSet(profile), - }) - setLoading(false) - } - ) + const options = connection + ? { solana: { connection: connection?.current } } + : undefined + + const { data: profile, isLoading } = useQuery( + ['Civic Profile', profileWalletPublicKey?.toBase58() + 'Civic'], + // @ts-ignore we won't run this if there is no profileWalletPublicKey + () => CivicProfile.get(profileWalletPublicKey?.toBase58(), options), + { + enabled: !!profileWalletPublicKey, // Only run query if profileWalletPublicKey is available + select: (data) => ({ + ...data, + exists: profileIsSet(data), + }), } - // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree - }, [publicKey, connectedWallet?.publicKey, connection.current]) + ) - return { profile, loading } + return { profile, loading: isLoading } } diff --git a/components/ProposalActions.tsx b/components/ProposalActions.tsx index f989309343..b795f22ffb 100644 --- a/components/ProposalActions.tsx +++ b/components/ProposalActions.tsx @@ -259,7 +259,7 @@ const ProposalActionsPanel = () => { const handleRepropose = async () => { try { - if (proposal && realmInfo && signatoryRecord) { + if (proposal && realmInfo) { const proposalAddress = await propose({ title: proposal.account.name, description: proposal.account.descriptionLink, @@ -282,6 +282,7 @@ const ProposalActionsPanel = () => { isValid: true, governance: undefined, customHoldUpTime: tx.account.holdUpTime, + chunkBy: 2, }, }) ) diff --git a/components/ProposalVotingPower/LockedCommunityVotingPower.tsx b/components/ProposalVotingPower/LockedCommunityVotingPower.tsx index cafe39a128..cf0973bb15 100644 --- a/components/ProposalVotingPower/LockedCommunityVotingPower.tsx +++ b/components/ProposalVotingPower/LockedCommunityVotingPower.tsx @@ -18,7 +18,11 @@ interface Props { export default function LockedCommunityVotingPower(props: Props) { const realm = useRealmQuery().data?.result - const mint = useRealmCommunityMintInfoQuery().data?.result + const { + data: mintData, + isLoading: mintLoading, + } = useRealmCommunityMintInfoQuery() + const mint = mintData?.result const { realmTokenAccount } = useRealm() @@ -41,7 +45,7 @@ export default function LockedCommunityVotingPower(props: Props) { // memoize useAsync inputs to prevent constant refetch const relevantDelegators = useDelegators('community') - if (isLoading || votingPowerLoading || !(votingPower && mint)) { + if (isLoading || votingPowerLoading || mintLoading) { return (
- {votingPower.isZero() && (relevantDelegators?.length ?? 0) < 1 ? ( + {(votingPower === undefined || votingPower.isZero()) && + (relevantDelegators?.length ?? 0) < 1 ? (
You do not have any voting power in this dao.
diff --git a/components/ProposalVotingPower/NftVotingPower.tsx b/components/ProposalVotingPower/NftVotingPower.tsx index 541535f749..b6d3ff6954 100644 --- a/components/ProposalVotingPower/NftVotingPower.tsx +++ b/components/ProposalVotingPower/NftVotingPower.tsx @@ -89,7 +89,7 @@ const Join = () => { } return ( - (actingAsWalletPk?.toString === wallet?.publicKey?.toString() && + (actingAsWalletPk?.toString() === wallet?.publicKey?.toString() && connected && !ownTokenRecord && (
@@ -232,13 +478,15 @@ const MangoAccountItem = ({ group, }: { account: MangoAccount | null - group: Group + group: Group | null }) => { - return account ? ( + return account && group ? (
Name: {account.name}
{account.publicKey.toBase58()}
-
Pnl: ${account.getPnl(group).toString()}
+
+ Account Value: ${toUiDecimals(account.getAssetsValue(group), 6)} +
) : (
Create new account
diff --git a/components/VotePanel/YouVoted.tsx b/components/VotePanel/YouVoted.tsx index 0b1e5b3886..2ad303b9b8 100644 --- a/components/VotePanel/YouVoted.tsx +++ b/components/VotePanel/YouVoted.tsx @@ -146,7 +146,9 @@ export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { const isMulti = proposal?.account.voteType !== VoteType.SINGLE_CHOICE && proposal?.account.accountType === GovernanceAccountType.ProposalV2 - + + const nota = '$$_NOTA_$$' + return vote !== undefined ? (
@@ -164,7 +166,11 @@ export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { >
-
{proposal?.account.options[index].label}
+
{ + proposal?.account.options[index].label === nota ? + "None of the Above" : + proposal?.account.options[index].label + }
diff --git a/components/VotePanel/useDelegators.ts b/components/VotePanel/useDelegators.ts index e44a8716c1..d8fb8e3761 100644 --- a/components/VotePanel/useDelegators.ts +++ b/components/VotePanel/useDelegators.ts @@ -14,7 +14,7 @@ const useDelegators = (role: 'community' | 'council' | undefined) => { ? realm?.account.communityMint : realm?.account.config.councilMint - const torsDelegatedToUser = useTokenOwnerRecordsDelegatedToUser() + const { data: torsDelegatedToUser } = useTokenOwnerRecordsDelegatedToUser() const relevantDelegators = relevantMint && torsDelegatedToUser?.filter((x) => diff --git a/components/chat/DiscussionPanel.tsx b/components/chat/DiscussionPanel.tsx index f5723cc846..aaf49322a0 100644 --- a/components/chat/DiscussionPanel.tsx +++ b/components/chat/DiscussionPanel.tsx @@ -1,6 +1,5 @@ import { useMemo } from 'react' import DiscussionForm from './DiscussionForm' -import Comment from './Comment' import { useQuery } from '@tanstack/react-query' import { GOVERNANCE_CHAT_PROGRAM_ID, @@ -8,6 +7,7 @@ import { } from '@solana/spl-governance' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { useSelectedProposalPk } from '@hooks/queries/proposal' +import LazyLoadComment from './LazyLoadComment' export const useChatMessagesQuery = () => { const connection = useLegacyConnectionContext() @@ -57,7 +57,7 @@ const DiscussionPanel = () => {
{sortedMessages?.map((cm) => ( - + ))} ) diff --git a/components/chat/LazyLoadComment.tsx b/components/chat/LazyLoadComment.tsx new file mode 100644 index 0000000000..773c441727 --- /dev/null +++ b/components/chat/LazyLoadComment.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { useInView } from 'react-intersection-observer' +import Comment from './Comment' +import { ChatMessage } from '@solana/spl-governance' + +const LazyLoadComment = ({ chatMessage }: { chatMessage: ChatMessage }) => { + const { ref, inView } = useInView({ + /* Optional options */ + triggerOnce: true, + }) + + return ( +
+
{inView && }
+
+ ) +} + +export default LazyLoadComment diff --git a/components/instructions/TransactionCard.tsx b/components/instructions/TransactionCard.tsx index 1c6f719602..90ba969729 100644 --- a/components/instructions/TransactionCard.tsx +++ b/components/instructions/TransactionCard.tsx @@ -23,6 +23,7 @@ export default function TransactionCard({ ? PlayState.Played : PlayState.Unplayed ) + return (

{`Transaction ${index} `}

diff --git a/components/instructions/programs/governance.tsx b/components/instructions/programs/governance.tsx index 0326295be2..6681a5459a 100644 --- a/components/instructions/programs/governance.tsx +++ b/components/instructions/programs/governance.tsx @@ -35,6 +35,7 @@ import { import { dryRunInstruction } from 'actions/dryRunInstruction' import { tryGetMint } from '../../../utils/tokens' import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery' +import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount' const TOKEN_TYPES = { 0: 'Liquid', 1: 'Membership', 2: 'Disabled' } const governanceProgramId = 'GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw' @@ -83,10 +84,17 @@ export const GOVERNANCE_INSTRUCTIONS = { ) //accounts[2] is token account not mint account - const mintInfoQuery = await fetchMintInfoByPubkey( + const { result: tokenAccount } = await fetchTokenAccountByPubkey( connection, accounts[2].pubkey ) + if (!tokenAccount) { + throw new Error() + } + const mintInfoQuery = await fetchMintInfoByPubkey( + connection, + tokenAccount.mint + ) const args = deserializeBorsh( getGovernanceInstructionSchema(programVersion), diff --git a/components/instructions/programs/mangoV4.tsx b/components/instructions/programs/mangoV4.tsx index 509fcda4fb..1c3af336eb 100644 --- a/components/instructions/programs/mangoV4.tsx +++ b/components/instructions/programs/mangoV4.tsx @@ -1,17 +1,14 @@ import { Bank, - MANGO_V4_ID, - MangoClient, OracleProvider, USDC_MINT, toUiDecimals, } from '@blockworks-foundation/mango-v4' import AdvancedOptionsDropdown from '@components/NewRealmWizard/components/AdvancedOptionsDropdown' -import { AnchorProvider, BN, BorshInstructionCoder } from '@coral-xyz/anchor' +import { BN, BorshInstructionCoder } from '@coral-xyz/anchor' import { AccountMetaData } from '@solana/spl-governance' -import { Connection, Keypair, PublicKey } from '@solana/web3.js' -import EmptyWallet, { - getSuggestedCoinTier, +import { Connection, PublicKey } from '@solana/web3.js' +import { compareObjectsAndGetDifferentKeys, FlatListingArgs, ListingArgsFormatted, @@ -23,6 +20,7 @@ import EmptyWallet, { decodePriceFromOracleAi, getFormattedBankValues, REDUCE_ONLY_OPTIONS, + getSuggestedCoinPresetInfo, } from '@utils/Mango/listingTools' import { secondsToHours } from 'date-fns' import WarningFilledIcon from '@carbon/icons-react/lib/WarningFilled' @@ -32,17 +30,17 @@ import tokenPriceService, { TokenInfoWithoutDecimals, } from '@utils/services/tokenPrice' import { - LISTING_PRESETS, - LISTING_PRESETS_KEYS, - LISTING_PRESETS_PYTH, + LISTING_PRESETS_KEY, MidPriceImpact, coinTiersToNames, getMidPriceImpacts, - getProposedTier, + getProposedKey, } from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' import { tryParseKey } from '@tools/validators/pubkey' import Loading from '@components/Loading' -import queryClient from '@hooks/queries/queryClient' +import { getClient, getGroupForClient } from '@utils/mangoV4Tools' +import { tryGetMint } from '@utils/tokens' +import { formatNumber } from '@utils/formatNumber' // import { snakeCase } from 'snake-case' // import { sha256 } from 'js-sha256' @@ -234,11 +232,18 @@ const instructions = () => ({ const oracle = accounts[6].pubkey const isMintOnCurve = PublicKey.isOnCurve(proposedMint) - const [info, proposedOracle, args, oracleAi] = await Promise.all([ + const [ + info, + proposedOracle, + args, + oracleAi, + mintInfo, + ] = await Promise.all([ displayArgs(connection, data), getOracle(connection, oracle), getDataObjectFlattened(connection, data), connection.getAccountInfo(oracle), + tryGetMint(connection, proposedMint), ]) const oracleData = await decodePriceFromOracleAi( @@ -247,27 +252,55 @@ const instructions = () => ({ proposedOracle.type ) - const liqudityTier = await getSuggestedCoinTier( + const presetInfo = await getSuggestedCoinPresetInfo( proposedMint.toBase58(), proposedOracle.type === 'Pyth' ) const formattedProposedArgs = getFormattedListingValues(args) - const suggestedPreset = getFormattedListingPresets( - proposedOracle.type === 'Pyth' - )[liqudityTier.tier] - const suggestedUntrusted = liqudityTier.tier === 'UNTRUSTED' + const formattedSuggestedPresets = getFormattedListingPresets( + proposedOracle.type === 'Pyth', + 0, + mintInfo?.account.decimals || 0, + oracleData.uiPrice + ) - const suggestedFormattedPreset: ListingArgsFormatted = - Object.keys(suggestedPreset).length && !suggestedUntrusted - ? getFormattedListingValues({ - tokenIndex: args.tokenIndex, - name: args.name, - oracle: args.oracle, - ...suggestedPreset, - }) - : ({} as ListingArgsFormatted) + const currentListingArgsMatchedTier = Object.values( + formattedSuggestedPresets + ).find((preset) => { + const formattedPreset = getFormattedListingValues({ + tokenIndex: args.tokenIndex, + name: args.name, + oracle: args.oracle, + ...preset, + }) + + return ( + JSON.stringify({ + //deposit limit depends on current price so can be different a bit in proposal + ...formattedProposedArgs, + depositLimit: 0, + }) === + JSON.stringify({ + ...formattedPreset, + depositLimit: 0, + }) + ) + }) + + const suggestedPreset = formattedSuggestedPresets[presetInfo.presetKey] + + const suggestedFormattedPreset: ListingArgsFormatted = Object.keys( + suggestedPreset + ).length + ? getFormattedListingValues({ + tokenIndex: args.tokenIndex, + name: args.name, + oracle: args.oracle, + ...suggestedPreset, + }) + : ({} as ListingArgsFormatted) const invalidKeys: (keyof ListingArgsFormatted)[] = Object.keys( suggestedPreset @@ -277,24 +310,32 @@ const instructions = () => ({ suggestedFormattedPreset ) : [] - const invalidFields: Partial = invalidKeys.reduce( - (obj, key) => { + + const invalidFields: Partial = invalidKeys + .filter((x) => { + //soft invalid keys - some of the keys can be off by some small maring + if (x === 'depositLimit') { + return !isDifferenceWithin5Percent( + Number(formattedProposedArgs['depositLimit'] || 0), + Number(suggestedFormattedPreset['depositLimit'] || 0) + ) + } + return true + }) + .reduce((obj, key) => { return { ...obj, [key]: suggestedFormattedPreset[key], } - }, - {} - ) + }, {}) + const DisplayListingPropertyWrapped = ({ label, - suggestedUntrusted, valKey, suffix, prefix: perfix, }: { label: string - suggestedUntrusted: boolean valKey: string suffix?: string prefix?: string @@ -302,7 +343,6 @@ const instructions = () => ({ return ( ({ return (
- {suggestedUntrusted && ( + {presetInfo.presetKey === 'UNTRUSTED' && ( <>

- Suggested token tier: UNTRUSTED. + Suggested token tier: C

- Very low liquidity Price impact of{' '} - {liqudityTier.priceImpact}% on $1000 swap. This token should - probably be listed using the Register Trustless Token - instruction check params carefully + Very low liquidity check params carefully

)} - {!suggestedUntrusted && !invalidKeys.length && ( + {!invalidKeys.length && (

Proposal params match suggested token tier -{' '} - {coinTiersToNames[liqudityTier.tier]}. + {coinTiersToNames[presetInfo.presetKey]}.

)} - {!suggestedUntrusted && invalidKeys.length > 0 && ( + {invalidKeys.length > 0 && (

Proposal params do not match suggested token tier -{' '} - {coinTiersToNames[liqudityTier.tier]} check params carefully + {coinTiersToNames[presetInfo.presetKey]} check params + carefully +

+ )} + {currentListingArgsMatchedTier && ( +

+ + Full match found with tier {/* @ts-ignore */} + {currentListingArgsMatchedTier.preset_name}

)} {isMintOnCurve && ( @@ -391,186 +436,184 @@ const instructions = () => ({
- -
@@ -610,17 +653,17 @@ const instructions = () => ({ const info = await displayArgs(connection, data) const client = await getClient(connection) - const mangoGroup = await client.getGroup(group) + const mangoGroup = await getGroupForClient(client, group) const banks = [...mangoGroup.banksMapByMint.values()].map((x) => x[0]) let baseMint = banks.find((x) => x.publicKey.equals(baseBank))?.mint let quoteMint = banks.find((x) => x.publicKey.equals(quoteBank))?.mint + const currentMarket = await Market.load( + connection, + openbookMarketPk, + undefined, + openBookProgram + ) if (!baseMint || !quoteMint) { - const currentMarket = await Market.load( - connection, - openbookMarketPk, - undefined, - openBookProgram - ) baseMint = currentMarket.baseMintAddress quoteMint = currentMarket.quoteMintAddress } @@ -635,7 +678,7 @@ const instructions = () => ({ try { return (
- {bestMarket && openbookMarketPk.equals(bestMarket) && ( + {bestMarket && openbookMarketPk.equals(bestMarket.pubKey) && (
Proposed market match the best market according to listing @@ -648,7 +691,13 @@ const instructions = () => ({ Best market not found check market carefully
)} - {bestMarket && !openbookMarketPk.equals(bestMarket) && ( + {bestMarket?.error && ( +
+ + {bestMarket?.error} +
+ )} + {bestMarket && !openbookMarketPk.equals(bestMarket.pubKey) && (
+ +
+
Tick Size: {currentMarket.tickSize}
+
+ Base Lot Size: {currentMarket.decoded?.baseLotSize?.toNumber()} +
+
+ Quote Lot Size:{' '} + {currentMarket.decoded?.quoteLotSize?.toNumber()} +
+
+ Quote decimals: {currentMarket['_quoteSplTokenDecimals']} +
+
Base decimals: {currentMarket['_baseSplTokenDecimals']}
+
{info}
) @@ -779,15 +843,16 @@ const instructions = () => ({ displayArgs(connection, data), getDataObjectFlattened(connection, data), ]) + let priceImpact: MidPriceImpact | undefined const mint = [...mangoGroup.mintInfosMapByMint.values()].find((x) => x.publicKey.equals(mintInfo) )?.mint let liqudityTier: Partial<{ - tier: LISTING_PRESETS_KEYS + presetKey: LISTING_PRESETS_KEY priceImpact: string }> = {} - let suggestedUntrusted = false + let invalidKeys: (keyof EditTokenArgsFormatted)[] = [] let invalidFields: Partial = {} let bank: null | Bank = null @@ -798,11 +863,15 @@ const instructions = () => ({ const parsedArgs: Partial = { tokenIndex: args.tokenIndex, tokenName: args.nameOpt, - oracleConfidenceFilter: - args['oracleConfigOpt.confFilter'] !== undefined - ? (args['oracleConfigOpt.confFilter'] * 100)?.toFixed(2) - : undefined, - oracleMaxStalenessSlots: args['oracleConfigOpt.maxStalenessSlots'], + oracleConfidenceFilter: args['oracleConfigOpt.confFilter'] + ? args['oracleConfigOpt.confFilter'] >= 100 + ? args['oracleConfigOpt.confFilter'].toString() + : (args['oracleConfigOpt.confFilter'] * 100).toFixed(2) + : undefined, + oracleMaxStalenessSlots: + args['oracleConfigOpt.maxStalenessSlots'] === null + ? -1 + : args['oracleConfigOpt.maxStalenessSlots'], interestRateUtilizationPoint0: args['interestRateParamsOpt.util0'] !== undefined ? (args['interestRateParamsOpt.util0'] * 100)?.toFixed(2) @@ -873,7 +942,10 @@ const instructions = () => ({ args.tokenConditionalSwapMakerFeeRateOpt, tokenConditionalSwapTakerFeeRate: args.tokenConditionalSwapTakerFeeRateOpt, - flashLoanSwapFeeRate: args.flashLoanSwapFeeRateOpt, + flashLoanSwapFeeRate: + args.flashLoanSwapFeeRateOpt !== undefined + ? (args.loanOriginationFeeRateOpt * 10000)?.toFixed(2) + : undefined, reduceOnly: args.reduceOnlyOpt !== undefined ? REDUCE_ONLY_OPTIONS[args.reduceOnlyOpt].name @@ -894,12 +966,15 @@ const instructions = () => ({ bankFormattedValues = getFormattedBankValues(mangoGroup, bank) mintData = tokenPriceService.getTokenInfo(mint.toBase58()) const isPyth = bank?.oracleProvider === OracleProvider.Pyth - const midPriceImpacts = getMidPriceImpacts(mangoGroup.pis) - const PRESETS = isPyth ? LISTING_PRESETS_PYTH : LISTING_PRESETS + const midPriceImpacts = getMidPriceImpacts( + mangoGroup.pis.length ? mangoGroup.pis : [] + ) const tokenToPriceImpact = midPriceImpacts - .filter((x) => x.avg_price_impact_percent < 1) + .filter( + (x) => x.avg_price_impact_percent < 1 || x.target_amount <= 1000 + ) .reduce( (acc: { [key: string]: MidPriceImpact }, val: MidPriceImpact) => { if ( @@ -913,31 +988,35 @@ const instructions = () => ({ {} ) - const priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)] + priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)] - const suggestedTier = getProposedTier( - PRESETS, - priceImpact?.target_amount, - bank.oracleProvider === OracleProvider.Pyth - ) + const suggestedPresetKey = priceImpact + ? getProposedKey( + priceImpact.avg_price_impact_percent < 1 + ? priceImpact?.target_amount + : undefined, + bank.oracleProvider === OracleProvider.Pyth + ) + : 'UNTRUSTED' liqudityTier = !mint.equals(USDC_MINT) ? { - tier: suggestedTier, + presetKey: suggestedPresetKey, priceImpact: priceImpact ? priceImpact.avg_price_impact_percent.toString() : '', } : { - tier: 'ULTRA_PREMIUM', + presetKey: 'asset_250p', priceImpact: '0', } const suggestedPreset = getFormattedListingPresets( !!isPyth, - bank.nativeDeposits().mul(bank.price).toNumber() - )[liqudityTier.tier!] - suggestedUntrusted = liqudityTier.tier === 'UNTRUSTED' + bank.uiDeposits(), + bank.mintDecimals, + bank.uiPrice + )[liqudityTier.presetKey!] const suggestedFormattedPreset: | EditTokenArgsFormatted @@ -965,7 +1044,27 @@ const instructions = () => ({ Partial >(parsedArgs, suggestedFormattedPreset) : [] - ).filter((x) => parsedArgs[x] !== undefined) + ) + .filter((x) => parsedArgs[x] !== undefined) + .filter((x) => { + //soft invalid keys - some of the keys can be off by some small maring + if (x === 'depositLimit') { + return !isDifferenceWithin5Percent( + Number(parsedArgs['depositLimit'] || 0), + Number(suggestedFormattedPreset['depositLimit'] || 0) + ) + } + if (x === 'netBorrowLimitPerWindowQuote') { + return !isDifferenceWithin5Percent( + Number(parsedArgs['netBorrowLimitPerWindowQuote'] || 0), + Number( + suggestedFormattedPreset['netBorrowLimitPerWindowQuote'] || + 0 + ) + ) + } + return true + }) invalidFields = invalidKeys.reduce((obj, key) => { return { @@ -978,36 +1077,38 @@ const instructions = () => ({ return (

{mintData &&
Token: {mintData.symbol}
}

- {suggestedUntrusted && ( + {!priceImpact && ( +

+ + No price impact data in group +

+ )} + {liqudityTier.presetKey === 'UNTRUSTED' && ( <>

- Suggested token tier: UNTRUSTED. + Suggested token tier: C

- Very low liquidity Price impact of {liqudityTier?.priceImpact} - % on $1000 swap. Check params carefully token should be listed - with untrusted instruction + Very low liquidity check params carefully

)} - {!suggestedUntrusted && !invalidKeys.length && liqudityTier.tier && ( + {!invalidKeys.length && liqudityTier.presetKey && (

Proposal params match suggested token tier -{' '} - {coinTiersToNames[liqudityTier.tier]}. + {coinTiersToNames[liqudityTier.presetKey]}. +

+ )} + {invalidKeys && invalidKeys!.length > 0 && liqudityTier.presetKey && ( +

+ + Proposal params do not match suggested token tier -{' '} + {coinTiersToNames[liqudityTier.presetKey]} check params + carefully

)} - {!suggestedUntrusted && - invalidKeys && - invalidKeys!.length > 0 && - liqudityTier.tier && ( -

- - Proposal params do not match suggested token tier -{' '} - {coinTiersToNames[liqudityTier.tier]} check params carefully -

- )}
- Current values @@ -1047,7 +1148,11 @@ const instructions = () => ({ ({ `${invalidFields.netBorrowLimitWindowSizeTs}H` } /> + ({ /> ({ suggestedVal={invalidFields.maintWeightShiftLiabTarget} /> {parsedArgs?.maintWeightShiftAbort && ( ({ } }, }, - 73195: { + 11366: { name: 'Withdraw all token fees', accounts: [ { name: 'Group' }, @@ -1515,12 +1678,35 @@ const instructions = () => ({ ], getDataUI: async ( connection: Connection, - data: Uint8Array - //accounts: AccountMetaData[] + data: Uint8Array, + accounts: AccountMetaData[] ) => { - const info = await displayArgs(connection, data) + const args = await getDataObjectFlattened(connection, data) + const accountInfo = await connection.getParsedAccountInfo( + accounts[6].pubkey + ) + const mint = await tryGetMint( + connection, + new PublicKey(accountInfo.value?.data['parsed'].info.mint) + ) + const tokenInfo = tokenPriceService.getTokenInfo( + accountInfo.value?.data['parsed'].info.mint + ) try { - return
{info}
+ return ( +
+
+ amount:{' '} + {mint?.account.decimals + ? formatNumber( + toUiDecimals(args.amount, mint?.account.decimals) + ) + : args.amount}{' '} + {tokenInfo?.symbol} +
+
reduce only: {args.reduceOnly.toString()}
+
+ ) } catch (e) { console.log(e) return
{JSON.stringify(data)}
@@ -1553,79 +1739,52 @@ const instructions = () => ({ export const MANGO_V4_INSTRUCTIONS = { '4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg': instructions(), -} - -const getClient = async (connection: Connection) => { - const client = await queryClient.fetchQuery({ - queryKey: ['mangoClient', connection.rpcEndpoint], - queryFn: async () => { - const options = AnchorProvider.defaultOptions() - const adminProvider = new AnchorProvider( - connection, - new EmptyWallet(Keypair.generate()), - options - ) - const client = await MangoClient.connect( - adminProvider, - 'mainnet-beta', - MANGO_V4_ID['mainnet-beta'] - ) - - return client - }, - }) - return client -} -const getGroupForClient = async (client: MangoClient, groupPk: PublicKey) => { - const group = await queryClient.fetchQuery({ - queryKey: ['mangoGroup', groupPk.toBase58(), client.connection.rpcEndpoint], - queryFn: async () => { - const response = await client.getGroup(groupPk) - return response - }, - }) - return group + zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25: instructions(), } async function getDataObjectFlattened( connection: Connection, data: Uint8Array ) { - const client = await getClient(connection) - const decodedInstructionData = new BorshInstructionCoder( - client.program.idl - ).decode(Buffer.from(data))?.data as any + try { + const client = await getClient(connection) + const decodedInstructionData = new BorshInstructionCoder( + client.program.idl + ).decode(Buffer.from(data))?.data as any - // console.log( - // client.program.idl.instructions.map((ix) => { - // const sh = sighash('global', ix.name) - // return { - // name: ix.name, - // sh: `${sh[0]}${sh[1]}`, - // } - // }) - // ) + // console.log( + // client.program.idl.instructions.map((ix) => { + // const sh = sighash('global', ix.name) + // return { + // name: ix.name, + // sh: `${sh[0]}${sh[1]}`, + // } + // }) + // ) - const args = {} - for (const key of Object.keys(decodedInstructionData)) { - const val = decodedInstructionData[key] - if (val !== null) { - if ( - typeof val === 'object' && - !Array.isArray(val) && - !(val instanceof BN) && - !(val instanceof PublicKey) - ) { - for (const innerKey of Object.keys(val)) { - const innerVal = val[innerKey] - args[`${key}.${innerKey}`] = innerVal + const args = {} + for (const key of Object.keys(decodedInstructionData)) { + const val = decodedInstructionData[key] + if (val !== null) { + if ( + typeof val === 'object' && + !Array.isArray(val) && + !(val instanceof BN) && + !(val instanceof PublicKey) + ) { + for (const innerKey of Object.keys(val)) { + const innerVal = val[innerKey] + args[`${key}.${innerKey}`] = innerVal + } + } else { + args[key] = val } - } else { - args[key] = val } } + return args as T + } catch (e) { + return {} as T } - return args as T } const displayArgs = async (connection: Connection, data: Uint8Array) => { @@ -1710,14 +1869,12 @@ const DisplayNullishProperty = ({ const DisplayListingProperty = ({ label, - suggestedUntrusted, val, suggestedVal, suffix, prefix, }: { label: string - suggestedUntrusted: boolean val: any suggestedVal?: any suffix?: string @@ -1726,9 +1883,7 @@ const DisplayListingProperty = ({
{label}:
-
+
{prefix} {`${val}`} {suffix} @@ -1750,7 +1905,7 @@ const getFormattedListingValues = (args: FlatListingArgs) => { const formattedArgs: ListingArgsFormatted = { tokenIndex: args.tokenIndex, tokenName: args.name, - oracle: args.oracle?.toBase58(), + oracle: args.oracle?.toBase58 && args.oracle?.toBase58(), oracleConfidenceFilter: args['oracleConfig.confFilter'] >= 100 ? args['oracleConfig.confFilter'].toString() @@ -1798,7 +1953,7 @@ const getFormattedListingValues = (args: FlatListingArgs) => { stablePriceGrowthLimit: (args.stablePriceGrowthLimit * 100).toFixed(2), tokenConditionalSwapMakerFeeRate: args.tokenConditionalSwapMakerFeeRate, tokenConditionalSwapTakerFeeRate: args.tokenConditionalSwapTakerFeeRate, - flashLoanSwapFeeRate: args.flashLoanSwapFeeRate, + flashLoanSwapFeeRate: (args.flashLoanSwapFeeRate * 10000).toFixed(2), reduceOnly: REDUCE_ONLY_OPTIONS[args.reduceOnly].name, depositLimit: args.depositLimit.toString(), interestTargetUtilization: args.interestTargetUtilization, @@ -1821,3 +1976,17 @@ const getApiTokenName = (bankName: string) => { } return bankName } + +function isDifferenceWithin5Percent(a: number, b: number): boolean { + // Calculate the absolute difference + const difference = Math.abs(a - b) + + // Calculate the average of the two numbers + const average = (a + b) / 2 + + // Calculate the percentage difference + const percentageDifference = (difference / average) * 100 + + // Check if the difference is within 5% + return percentageDifference <= 5 +} diff --git a/components/instructions/tools.tsx b/components/instructions/tools.tsx index 418652698d..bb120a7095 100644 --- a/components/instructions/tools.tsx +++ b/components/instructions/tools.tsx @@ -137,6 +137,12 @@ export const ACCOUNT_NAMES = { FAFDfoUkaxoMqiNur9F1iigdBNrXFf4uNmS5XrhMewvf: 'Friends and Family Community Mint', + // Dean's List DAO + '6Vjsy1KabnHtSuHZcXuuCQFWoBML9JscSy3L4NGjqmhM': 'Deans List DAO Treasury', + 'CLgzSdeNcf9CYHiAdmXaPaCw2vYBeiqEeZcgguqirVM9': 'DAO: (DEAN) Strategic Reserve', + 'bDgqY2Qt4y2jSsRNvD7FETkRJJNiYZT1Q3UnAYYzUCo': 'DAO: (DEAN) Community Reserve', + 'BtJaNZrZZmagHGzCU2VazSJWzBS9KY7tG41enBrT2NtU': 'DAO: (DEAN) Liquidity Reserve', + // Physis DAO '29epeLvAMyRXtpA1HaoKB1hGcAnrc1NvMCbaZ8AVRwEi': 'Physis DAO Treasury', '4i2Yjk5bUiLeVNwqBpkRdFSECSCvMgKoeCSdRSx1TPcz': 'DAO: Rewards (PHY)', @@ -389,6 +395,12 @@ const HIDDEN_MNGO_TREASURES = [ 'PuXf9LNrmtVDhBTxteNTWS8D2SpzbhYvidkSatjRArt', ] +//badly created realms +export const HIDDEN_REALMS = [ + 'BWnVbUDohApiiaWBNNGcLH2KXRKEoTBJ7schsKQWYAtj', + 'FsoDEiZ9BoGTAaCLzXkyQWEqNKa5PW2iokzmuD7YsRdL', +] + //owner and desired accounts we want to show const MNGO_AUXILIARY_TOKEN_ACCOUNTS = [ { diff --git a/components/treasuryV2/Details/TokenDetails/Investments.tsx b/components/treasuryV2/Details/TokenDetails/Investments.tsx index 7e0bec0682..845b929a12 100644 --- a/components/treasuryV2/Details/TokenDetails/Investments.tsx +++ b/components/treasuryV2/Details/TokenDetails/Investments.tsx @@ -198,7 +198,6 @@ export default function Investments(props: Props) { {alternativeInvestment === 'Mango' && ( setAlternativeInvestment(null)} > diff --git a/components/treasuryV2/WalletList/WalletListItem/AssetList/NFTList.tsx b/components/treasuryV2/WalletList/WalletListItem/AssetList/NFTList.tsx index 5c011d80f2..8b9e7c9d79 100644 --- a/components/treasuryV2/WalletList/WalletListItem/AssetList/NFTList.tsx +++ b/components/treasuryV2/WalletList/WalletListItem/AssetList/NFTList.tsx @@ -33,7 +33,6 @@ export default function NFTList({ governance, ...props }: Props) { .map((x) => new PublicKey(x)), [nfts] ) - console.log('collectionIds', JSON.stringify(collectionIds)) const hasNftWithoutCollection = nfts?.find((x) => x.grouping.length < 1) diff --git a/hooks/PythNetwork/useScalingFactor.ts b/hooks/PythNetwork/useScalingFactor.ts new file mode 100644 index 0000000000..7f76becfe7 --- /dev/null +++ b/hooks/PythNetwork/useScalingFactor.ts @@ -0,0 +1,33 @@ +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +import { determineVotingPowerType } from "@hooks/queries/governancePower"; +import useSelectedRealmPubkey from "@hooks/selectedRealm/useSelectedRealmPubkey"; +import { PythClient } from "@pythnetwork/staking"; +import { useConnection } from "@solana/wallet-adapter-react"; +import { useAsync } from "react-async-hook"; +import { useQuery } from "@tanstack/react-query"; + +/** + * Returns undefined for everything except the Pyth DAO + */ +export default function usePythScalingFactor(): number | undefined { + const realm = useSelectedRealmPubkey() + const { connection } = useConnection() + const { result: plugin } = useAsync( + async () => + realm && determineVotingPowerType(connection, realm, 'community'), + [connection, realm] + ) + + const { data: scalingFactor } = useQuery(["pyth-scaling-factor"], + async (): Promise => { + const pythClient = await PythClient.connect(connection, {} as NodeWallet) + return pythClient.getScalingFactor() + }, { enabled: plugin == "pyth" }) + + if (plugin == "pyth") { + return scalingFactor + } else { + return undefined + } +} + diff --git a/hooks/queries/digitalAssets.ts b/hooks/queries/digitalAssets.ts index 147283d936..76409803eb 100644 --- a/hooks/queries/digitalAssets.ts +++ b/hooks/queries/digitalAssets.ts @@ -217,24 +217,35 @@ const dasByOwnerQueryFn = async (network: Network, owner: PublicKey) => { // https://docs.helius.xyz/solana-compression/digital-asset-standard-das-api/get-assets-by-owner - const response = await fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - jsonrpc: '2.0', - id: 'Realms user', - method: 'getAssetsByOwner', - params: { - ownerAddress: owner.toString(), - page: 1, // Starts at 1 - limit: 1000, // TODO support having >1k nfts + const PAGE_LIMIT = 1000 + const items: DasNftObject[] = [] + let moreNftsRemaining = true + let page = 1 + + while (moreNftsRemaining) { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', }, - }), - }) - const { result } = await response.json() - return result.items as DasNftObject[] + body: JSON.stringify({ + jsonrpc: '2.0', + id: 'Realms user', + method: 'getAssetsByOwner', + params: { + ownerAddress: owner.toString(), + page, // Starts at 1 + limit: PAGE_LIMIT, + }, + }), + }) + const { result } = await response.json() + const pageItems = result.items as DasNftObject[] + items.push(...pageItems) + page++ + if (pageItems.length < PAGE_LIMIT) moreNftsRemaining = false + } + return items } export const fetchDigitalAssetsByOwner = (network: Network, owner: PublicKey) => diff --git a/hooks/queries/jupiterPrice.ts b/hooks/queries/jupiterPrice.ts index daf578e942..0c153837cc 100644 --- a/hooks/queries/jupiterPrice.ts +++ b/hooks/queries/jupiterPrice.ts @@ -92,6 +92,17 @@ export const useJupiterPricesByMintsQuery = (mints: PublicKey[]) => { (acc, next) => ({ ...acc, ...next.data }), {} as Response['data'] ) + + //override chai price if its broken + const chaiMint = '3jsFX1tx2Z8ewmamiwSU851GzyzM2DJMq7KWW5DM8Py3' + const chaiData = data[chaiMint] + + if (chaiData?.price && (chaiData.price > 1.3 || chaiData.price < 0.9)) { + data[chaiMint] = { + ...chaiData, + price: 1, + } + } return data }, onSuccess: (data) => { diff --git a/hooks/queries/plugins/nftVoter.ts b/hooks/queries/plugins/nftVoter.ts index edc45a7d7b..4e56996482 100644 --- a/hooks/queries/plugins/nftVoter.ts +++ b/hooks/queries/plugins/nftVoter.ts @@ -24,6 +24,7 @@ export const useVotingNfts = (ownerPk: PublicKey | undefined) => { const { connection } = useConnection() const realmPk = useSelectedRealmPubkey() const { data: nfts } = useDigitalAssetsByOwner(ownerPk) + console.log('nfts', nfts) const registrar = useQuery(nftRegistrarQuery(connection, realmPk)).data ?.result diff --git a/hooks/queries/realm.ts b/hooks/queries/realm.ts index b750a1c51b..c55762c6e2 100644 --- a/hooks/queries/realm.ts +++ b/hooks/queries/realm.ts @@ -6,6 +6,7 @@ import { getNetworkFromEndpoint } from '@utils/connection' import asFindable from '@utils/queries/asFindable' import queryClient from './queryClient' import { useConnection } from '@solana/wallet-adapter-react' +import { HIDDEN_REALMS } from '@components/instructions/tools' export const realmQueryKeys = { all: (endpoint: string) => [endpoint, 'Realm'], @@ -30,7 +31,10 @@ export const useRealmsByProgramQuery = (program: PublicKey) => { : undefined, queryFn: async () => { if (!enabled) throw new Error() - return getRealms(connection, program) + const realms = (await getRealms(connection, program)).filter( + (x) => !HIDDEN_REALMS.includes(x.pubkey.toBase58()) + ) + return realms }, staleTime: 3600000, // 1 hour cacheTime: 3600000 * 24 * 10, diff --git a/hooks/queries/tokenOwnerRecord.ts b/hooks/queries/tokenOwnerRecord.ts index 092a438153..6f25a3316f 100644 --- a/hooks/queries/tokenOwnerRecord.ts +++ b/hooks/queries/tokenOwnerRecord.ts @@ -3,6 +3,7 @@ import { getGovernanceAccounts, getTokenOwnerRecord, pubkeyFilter, + booleanFilter, } from '@solana/spl-governance' import { Connection, PublicKey } from '@solana/web3.js' import { useQuery } from '@tanstack/react-query' @@ -12,7 +13,6 @@ import { useAddressQuery_CouncilTokenOwner, } from './addresses/tokenOwnerRecord' import { useRealmQuery } from './realm' -import { useMemo } from 'react' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import queryClient from './queryClient' @@ -27,14 +27,24 @@ export const tokenOwnerRecordQueryKeys = { byRealm: (endpoint: string, realm: PublicKey) => [ ...tokenOwnerRecordQueryKeys.all(endpoint), 'by Realm', - realm, + realm.toString(), ], + byRealmXDelegate: ( + endpoint: string, + realm: PublicKey, + delegate: PublicKey + ) => [ + ...tokenOwnerRecordQueryKeys.byRealm(endpoint, realm), + 'by Delegate', + delegate.toString(), + ], + byProgramXOwner: (endpoint: string, program: PublicKey, owner: PublicKey) => [ ...tokenOwnerRecordQueryKeys.all(endpoint), 'by Program', - program, + program.toString(), 'by Owner', - owner, + owner.toString(), ], } @@ -120,24 +130,58 @@ export const useTokenOwnerRecordsForRealmQuery = () => { return query } - +// 1 + 32 + 32 + 32 + 8 + 4 + 4 + 1 + 1 + 6 // TODO filter in the gPA (would need rpc to also index) export const useTokenOwnerRecordsDelegatedToUser = () => { - const { data: tors } = useTokenOwnerRecordsForRealmQuery() + const connection = useLegacyConnectionContext() + const realm = useRealmQuery().data?.result const wallet = useWalletOnePointOh() - const delagatingTors = useMemo( - () => - tors?.filter( - (x) => - wallet?.publicKey !== undefined && - wallet?.publicKey !== null && - x.account.governanceDelegate !== undefined && - x.account.governanceDelegate.equals(wallet.publicKey) - ), - [tors, wallet?.publicKey] - ) + const walletPk = wallet?.publicKey ?? undefined + const enabled = realm !== undefined && walletPk !== undefined + const query = useQuery({ + queryKey: enabled + ? tokenOwnerRecordQueryKeys.byRealmXDelegate( + connection.current.rpcEndpoint, + realm.pubkey, + walletPk + ) + : undefined, + queryFn: async () => { + if (!enabled) throw new Error() - return delagatingTors + const realmFilter = pubkeyFilter(1, realm.pubkey) + const hasDelegateFilter = booleanFilter( + 1 + 32 + 32 + 32 + 8 + 4 + 4 + 1 + 1 + 6, + true + ) + const delegatedToUserFilter = pubkeyFilter( + 1 + 32 + 32 + 32 + 8 + 4 + 4 + 1 + 1 + 6 + 1, + walletPk + ) + if (!realmFilter || !delegatedToUserFilter) throw new Error() // unclear why this would ever happen, probably it just cannot + + const results = await getGovernanceAccounts( + connection.current, + realm.owner, + TokenOwnerRecord, + [realmFilter, hasDelegateFilter, delegatedToUserFilter] + ) + + // This may or may not be resource intensive for big DAOs, and is not too useful + /* + results.forEach((x) => { + queryClient.setQueryData( + tokenOwnerRecordQueryKeys.byPubkey(connection.cluster, x.pubkey), + { found: true, result: x } + ) + }) */ + + return results + }, + enabled, + }) + + return query } const queryFn = (connection: Connection, pubkey: PublicKey) => diff --git a/hooks/selectedRealm/useSelectedRealmPubkey.ts b/hooks/selectedRealm/useSelectedRealmPubkey.ts index c6d2edb191..e4fc3301ed 100644 --- a/hooks/selectedRealm/useSelectedRealmPubkey.ts +++ b/hooks/selectedRealm/useSelectedRealmPubkey.ts @@ -8,7 +8,13 @@ import MAINNET_REALMS from 'public/realms/mainnet-beta.json' import { useMemo } from 'react' const useSelectedRealmPubkey = () => { - const { symbol, cluster } = useRouter().query + const { symbol } = useRouter().query + + return useRealmPubkeyByPkOrSymbol(symbol as string) +} + +export const useRealmPubkeyByPkOrSymbol = (symbol: string | undefined) => { + const { cluster } = useRouter().query const parsed = useMemo( () => (typeof symbol === 'string' ? tryParsePublicKey(symbol) : undefined), diff --git a/hooks/useAccountInvestments/staticInvestments.ts b/hooks/useAccountInvestments/staticInvestments.ts index 7c620067dd..f50325ec9e 100644 --- a/hooks/useAccountInvestments/staticInvestments.ts +++ b/hooks/useAccountInvestments/staticInvestments.ts @@ -46,17 +46,17 @@ export const getTokenInvestments = (tokenImg: string) => [ createProposalFcn: () => null, noProtocol: true, }, - // { - // liquidity: 0, - // protocolSymbol: '', - // apy: '', - // protocolName: 'Mango', - // handledMint: '', - // handledTokenSymbol: '', - // handledTokenImgSrc: tokenImg, - // protocolLogoSrc: 'https://alpha.mango.markets/logos/logo-mark.svg', - // strategyName: 'Trade', - // strategyDescription: '', - // createProposalFcn: () => null, - // }, + { + liquidity: 0, + protocolSymbol: '', + apy: '', + protocolName: 'Mango', + handledMint: '', + handledTokenSymbol: '', + handledTokenImgSrc: tokenImg, + protocolLogoSrc: 'https://mango.markets/logos/logo-mark.svg', + strategyName: 'Trade', + strategyDescription: '', + createProposalFcn: () => null, + }, ] diff --git a/hooks/useGovernanceAssets.ts b/hooks/useGovernanceAssets.ts index 08a8052c97..8ad15b3352 100644 --- a/hooks/useGovernanceAssets.ts +++ b/hooks/useGovernanceAssets.ts @@ -337,6 +337,21 @@ export default function useGovernanceAssets() { name: 'Split Stake Validator', packageId: PackageEnum.Common, }, + [Instructions.DaoVote]: { + name: 'Vote in another DAO', + isVisible: canUseTransferInstruction, + packageId: PackageEnum.Common, + }, + [Instructions.DualFinanceDelegateWithdraw]: { + name: 'Withdraw Vote Deposit', + isVisible: canUseTransferInstruction, + packageId: PackageEnum.Common, + }, + [Instructions.DualFinanceVoteDeposit]: { + name: 'Join a VSR DAO', + isVisible: canUseTransferInstruction, + packageId: PackageEnum.Common, + }, /* ██████ ██ ██ █████ ██ ███████ ██ ███ ██ █████ ███ ██ ██████ ███████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ██ ████ ██ ██ ██ @@ -390,21 +405,6 @@ export default function useGovernanceAssets() { isVisible: canUseTransferInstruction, packageId: PackageEnum.Dual, }, - [Instructions.DualFinanceDelegateWithdraw]: { - name: 'Withdraw Vote Deposit', - isVisible: canUseTransferInstruction, - packageId: PackageEnum.Dual, - }, - [Instructions.DualFinanceVoteDeposit]: { - name: 'Vote Deposit', - isVisible: canUseTransferInstruction, - packageId: PackageEnum.Dual, - }, - [Instructions.DualFinanceVote]: { - name: 'Vote', - isVisible: canUseTransferInstruction, - packageId: PackageEnum.Dual, - }, /* ███████ ██████ ██████ ███████ ███████ ██ ██████ ██ ██ ████████ @@ -515,11 +515,21 @@ export default function useGovernanceAssets() { packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4PerpCreateV23]: { + name: 'Create Perp v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4PerpEdit]: { name: 'Edit Perp', packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4PerpEditV23]: { + name: 'Edit Perp v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4OpenBookRegisterMarket]: { name: 'Register Openbook Market', packageId: PackageEnum.MangoMarketV4, @@ -530,11 +540,21 @@ export default function useGovernanceAssets() { packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4TokenEditV23]: { + name: 'Edit Token v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4TokenRegister]: { name: 'Register Token', packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4TokenRegisterV23]: { + name: 'Register Token v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4TokenRegisterTrustless]: { name: 'Register Trustless Token', packageId: PackageEnum.MangoMarketV4, @@ -545,6 +565,11 @@ export default function useGovernanceAssets() { packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4GroupEditV23]: { + name: 'Edit Group v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4AdminWithdrawTokenFees]: { name: 'Withdraw Token Fees', packageId: PackageEnum.MangoMarketV4, @@ -565,6 +590,11 @@ export default function useGovernanceAssets() { packageId: PackageEnum.MangoMarketV4, isVisible: canUseAnyInstruction, }, + [Instructions.MangoV4IxGateSetV23]: { + name: 'Enable/Disable individual instructions in Group v23', + packageId: PackageEnum.MangoMarketV4, + isVisible: canUseAnyInstruction, + }, [Instructions.MangoV4StubOracleCreate]: { name: 'Create Stub Oracle', packageId: PackageEnum.MangoMarketV4, diff --git a/hooks/useMangoV4.tsx b/hooks/useMangoV4.tsx index 9f2cbf3c91..4bb5f06bbc 100644 --- a/hooks/useMangoV4.tsx +++ b/hooks/useMangoV4.tsx @@ -11,7 +11,7 @@ import { useEffect, useState } from 'react' import useWalletOnePointOh from './useWalletOnePointOh' import useLegacyConnectionContext from './useLegacyConnectionContext' -export default function UseMangoV4() { +export default function UseMangoV4(programId?: PublicKey, group?: PublicKey) { const connection = useLegacyConnectionContext() const cluster = connection.cluster const wallet = useWalletOnePointOh() @@ -24,7 +24,13 @@ export default function UseMangoV4() { '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' ) const clientCluster = cluster === 'devnet' ? 'devnet' : 'mainnet-beta' - const GROUP = cluster === 'devnet' ? DEVNET_GROUP : MAINNET_GROUP + const GROUP = group + ? group + : cluster === 'devnet' + ? DEVNET_GROUP + : MAINNET_GROUP + + const program = programId ? programId : MANGO_V4_ID[clientCluster] const [mangoClient, setMangoClient] = useState(null) const [mangoGroup, setMangoGroup] = useState(null) const getClient = async ( @@ -41,7 +47,7 @@ export default function UseMangoV4() { const client = await MangoClient.connect( adminProvider, clientCluster, - MANGO_V4_ID[clientCluster] + program ) return client @@ -54,11 +60,16 @@ export default function UseMangoV4() { setMangoClient(client) setMangoGroup(group) } - if (wallet?.publicKey && connection) { + if (wallet && connection) { console.log('SET NEW CLIENT') handleSetClient() } - }, [connection.cluster, wallet?.publicKey?.toBase58()]) + }, [ + connection.cluster, + wallet?.publicKey?.toBase58(), + GROUP.toBase58(), + program.toBase58(), + ]) const docs = mangoClient?.program.idl.accounts .flatMap((x) => x.type.fields as any) @@ -86,3 +97,14 @@ export default function UseMangoV4() { getAdditionalLabelInfo, } } + +export const MANGO_BOOST_PROGRAM_ID = new PublicKey( + 'zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25' +) +export const BOOST_MAINNET_GROUP = new PublicKey( + 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf' +) + +export const MANGO_V4_MAINNET_GROUP = new PublicKey( + '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' +) diff --git a/hooks/useMangoV4V23.tsx b/hooks/useMangoV4V23.tsx new file mode 100644 index 0000000000..52c5634660 --- /dev/null +++ b/hooks/useMangoV4V23.tsx @@ -0,0 +1,113 @@ +import { AnchorProvider } from '@coral-xyz/anchor' +import { PublicKey } from '@solana/web3.js' +import { ConnectionContext } from '@utils/connection' +import { WalletSigner } from '@solana/spl-governance' +import { + Group, + MangoClient, + MANGO_V4_ID, +} from '@blockworks-foundation/mango-v4-rc' +import { useEffect, useState } from 'react' +import useWalletOnePointOh from './useWalletOnePointOh' +import useLegacyConnectionContext from './useLegacyConnectionContext' + +export default function UseMangoV4V23( + programId?: PublicKey, + group?: PublicKey +) { + const connection = useLegacyConnectionContext() + const cluster = connection.cluster + const wallet = useWalletOnePointOh() + const GROUP_NUM = 0 + const ADMIN_PK = new PublicKey('BJFYN2ZbcxRSTFGCAVkUEn4aJF99xaPFuyQj2rq5pFpo') + const DEVNET_GROUP = new PublicKey( + 'Bpk8VzppSEkygd4KgXSgVzgVHib4EArhbDzyRpiS4yaf' + ) + const MAINNET_GROUP = new PublicKey( + '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' + ) + const clientCluster = cluster === 'devnet' ? 'devnet' : 'mainnet-beta' + const GROUP = group + ? group + : cluster === 'devnet' + ? DEVNET_GROUP + : MAINNET_GROUP + + const program = programId ? programId : MANGO_V4_ID[clientCluster] + const [mangoClient, setMangoClient] = useState(null) + const [mangoGroup, setMangoGroup] = useState(null) + const getClient = async ( + connection: ConnectionContext, + wallet: WalletSigner + ) => { + const options = AnchorProvider.defaultOptions() + const adminProvider = new AnchorProvider( + connection.current, + wallet as any, + options + ) + + const client = await MangoClient.connect( + adminProvider, + clientCluster, + program + ) + + return client + } + + useEffect(() => { + const handleSetClient = async () => { + const client = await getClient(connection, wallet!) + const group = await client.getGroup(GROUP) + setMangoClient(client) + setMangoGroup(group) + } + if (wallet && connection) { + console.log('SET NEW CLIENT') + handleSetClient() + } + }, [ + connection.cluster, + wallet?.publicKey?.toBase58(), + GROUP.toBase58(), + program.toBase58(), + ]) + + const docs = mangoClient?.program.idl.accounts + .flatMap((x) => x.type.fields as any) + .filter((x) => x) + .filter((x) => (x as any).docs?.length) + .map((x) => ({ ...x, docs: x.docs.join(' ') })) + + const getAdditionalLabelInfo = (name: string) => { + const val = docs?.find((x) => x.name === name) + + if (val) { + return `${val.docs}` + } else { + return '' + } + } + + return { + ADMIN_PK, + GROUP_NUM, + GROUP, + getClient, + mangoClient, + mangoGroup, + getAdditionalLabelInfo, + } +} + +export const MANGO_BOOST_PROGRAM_ID = new PublicKey( + 'zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25' +) +export const BOOST_MAINNET_GROUP = new PublicKey( + 'AKeMSYiJekyKfwCc3CUfVNDVAiqk9FfbQVMY3G7RUZUf' +) + +export const MANGO_V4_MAINNET_GROUP = new PublicKey( + '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' +) diff --git a/hooks/useProposalVotes.tsx b/hooks/useProposalVotes.tsx index 5113b42bd9..390b5f7ca1 100644 --- a/hooks/useProposalVotes.tsx +++ b/hooks/useProposalVotes.tsx @@ -10,21 +10,25 @@ import { useRealmCouncilMintInfoQuery, } from './queries/mintInfo' import { useGovernanceByPubkeyQuery } from './queries/governance' +import usePythScalingFactor from './PythNetwork/useScalingFactor' // TODO support council plugins export default function useProposalVotes(proposal?: Proposal) { + const realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result const councilMint = useRealmCouncilMintInfoQuery().data?.result const maxVoteRecord = useMaxVoteRecord() const governance = useGovernanceByPubkeyQuery(proposal?.governance).data ?.result?.account + // This is always undefined except for Pyth + const pythScalingFactor: number | undefined = usePythScalingFactor(); const programVersion = useProgramVersion() const proposalMint = proposal?.governingTokenMint.toBase58() === - realm?.account.communityMint.toBase58() + realm?.account.communityMint.toBase58() ? mint : councilMint // TODO: optimize using memo @@ -52,8 +56,8 @@ export default function useProposalVotes(proposal?: Proposal) { ? governance.config.communityVoteThreshold.value : 0 : programVersion > 2 - ? governance.config.councilVoteThreshold.value || 0 - : governance.config.communityVoteThreshold.value || 0 + ? governance.config.councilVoteThreshold.value || 0 + : governance.config.communityVoteThreshold.value || 0 if (voteThresholdPct === undefined) throw new Error( @@ -100,12 +104,12 @@ export default function useProposalVotes(proposal?: Proposal) { voteThresholdPct, yesVotePct, yesVoteProgress, - yesVoteCount, - noVoteCount, + yesVoteCount: Math.floor(yesVoteCount * (pythScalingFactor || 1)), + noVoteCount: Math.floor(noVoteCount * (pythScalingFactor || 1)), relativeYesVotes, relativeNoVotes, minimumYesVotes, - yesVotesRequired, + yesVotesRequired: yesVotesRequired * (pythScalingFactor || 1), } // @asktree: you may be asking yourself, "is this different from the more succinct way to write this?" @@ -166,11 +170,11 @@ export default function useProposalVotes(proposal?: Proposal) { const vetoMaxVoteWeight = isPluginCommunityVeto ? maxVoteRecord.account.maxVoterWeight : getProposalMaxVoteWeight( - realm.account, - proposal, - vetoMintInfo, - vetoMintPk - ) + realm.account, + proposal, + vetoMintInfo, + vetoMintPk + ) const vetoVoteProgress = calculatePct( proposal.vetoVoteWeight, diff --git a/hooks/useTreasuryInfo/getDomains.ts b/hooks/useTreasuryInfo/getDomains.ts index 3d3133ed64..06be01ee72 100644 --- a/hooks/useTreasuryInfo/getDomains.ts +++ b/hooks/useTreasuryInfo/getDomains.ts @@ -10,19 +10,23 @@ const getAccountDomains = async ( account: AssetAccount, connection: Connection ): Promise => { - const domains = await getAllDomains(connection, account.pubkey) + try { + const domains = await getAllDomains(connection, account.pubkey) - if (!domains.length) { - return [] - } + if (!domains.length) { + return [] + } - const reverse = await performReverseLookupBatch(connection, domains) + const reverse = await performReverseLookupBatch(connection, domains) - return domains.map((domain, index) => ({ - name: reverse[index], - address: domain.toBase58(), - owner: account.pubkey.toBase58(), - })) + return domains.map((domain, index) => ({ + name: reverse[index], + address: domain.toBase58(), + owner: account.pubkey.toBase58(), + })) + } catch (e) { + return [] + } } export const getDomains = async ( diff --git a/hooks/useVotingTokenOwnerRecords.ts b/hooks/useVotingTokenOwnerRecords.ts index d5712f1979..891b07e8ad 100644 --- a/hooks/useVotingTokenOwnerRecords.ts +++ b/hooks/useVotingTokenOwnerRecords.ts @@ -9,7 +9,7 @@ import { getTokenOwnerRecordAddress } from '@solana/spl-governance' * Namely, this would be the user + any delegates that are enabled (by default, they all are) */ const useVotingTokenOwnerRecords = () => { - const delegated = useTokenOwnerRecordsDelegatedToUser() + const { data: delegated } = useTokenOwnerRecordsDelegatedToUser() const realm = useRealmQuery().data?.result const wallet = useWalletOnePointOh() diff --git a/hooks/useVsrMode.ts b/hooks/useVsrMode.ts index 39005bf032..7134513c48 100644 --- a/hooks/useVsrMode.ts +++ b/hooks/useVsrMode.ts @@ -1,8 +1,8 @@ import { useMemo } from 'react' -import { HELIUM_VSR_PLUGINS_PKS, VSR_PLUGIN_PKS } from '../constants/plugins' +import { HELIUM_VSR_PLUGINS_PKS, PYTH_PLUGIN_PK, VSR_PLUGIN_PKS } from '../constants/plugins' import { useRealmConfigQuery } from './queries/realmConfig' -export const useVsrMode = (): undefined | 'default' | 'helium' => { +export const useVsrMode = (): undefined | 'default' | 'helium' | 'pyth' => { const config = useRealmConfigQuery().data?.result const mode = useMemo(() => { const currentPluginPk = @@ -11,6 +11,7 @@ export const useVsrMode = (): undefined | 'default' | 'helium' => { if (VSR_PLUGIN_PKS.includes(currentPluginPk?.toBase58())) return 'default' if (HELIUM_VSR_PLUGINS_PKS.includes(currentPluginPk?.toBase58())) return 'helium' + if (PYTH_PLUGIN_PK.includes(currentPluginPk?.toBase58())) return 'pyth' }, [config?.account?.communityTokenConfig]) return mode diff --git a/hub/components/EditRealmConfig/CommunityStructure/index.tsx b/hub/components/EditRealmConfig/CommunityStructure/index.tsx index d1395f9328..b110bed608 100644 --- a/hub/components/EditRealmConfig/CommunityStructure/index.tsx +++ b/hub/components/EditRealmConfig/CommunityStructure/index.tsx @@ -25,11 +25,13 @@ interface Props nftCollection?: PublicKey; nftCollectionSize: number; nftCollectionWeight: BN; + civicPassType: Config['civicPassType']; }> { currentConfigAccount: Config['configAccount']; currentNftCollection?: PublicKey; currentNftCollectionSize: number; currentNftCollectionWeight: BN; + currentCivicPassType: Config['civicPassType']; communityMint: Config['communityMint']; className?: string; } @@ -43,6 +45,7 @@ export function CommunityStructure(props: Props) { nftCollection: props.currentNftCollection, nftCollectionSize: props.currentNftCollectionSize, nftCollectionWeight: props.currentNftCollectionWeight, + civicPassType: props.currentCivicPassType, }; const votingStructure = { @@ -52,6 +55,7 @@ export function CommunityStructure(props: Props) { nftCollection: props.nftCollection, nftCollectionSize: props.nftCollectionSize, nftCollectionWeight: props.nftCollectionWeight, + civicPassType: props.civicPassType, }; const minTokensToManage = new BigNumber( @@ -211,6 +215,7 @@ export function CommunityStructure(props: Props) { nftCollection, nftCollectionSize, nftCollectionWeight, + civicPassType, }) => { const newConfig = produce( { ...props.configAccount }, @@ -246,6 +251,13 @@ export function CommunityStructure(props: Props) { ) { props.onNftCollectionWeightChange?.(nftCollectionWeight); } + + if ( + typeof civicPassType !== 'undefined' && + !props.civicPassType?.equals(civicPassType) + ) { + props.onCivicPassTypeChange?.(civicPassType); + } }, 0); }} /> diff --git a/hub/components/EditRealmConfig/Form/index.tsx b/hub/components/EditRealmConfig/Form/index.tsx index bd008aae9a..5f13d3df2a 100644 --- a/hub/components/EditRealmConfig/Form/index.tsx +++ b/hub/components/EditRealmConfig/Form/index.tsx @@ -67,9 +67,11 @@ export function Form(props: Props) { currentNftCollection={props.currentConfig.nftCollection} currentNftCollectionSize={props.currentConfig.nftCollectionSize} currentNftCollectionWeight={props.currentConfig.nftCollectionWeight} + currentCivicPassType={props.currentConfig.civicPassType} nftCollection={props.config.nftCollection} nftCollectionSize={props.config.nftCollectionSize} nftCollectionWeight={props.config.nftCollectionWeight} + civicPassType={props.config.civicPassType} onConfigChange={(config) => { const newConfig = produce(props.config, (data) => { data.config = config; @@ -103,6 +105,13 @@ export function Form(props: Props) { data.nftCollectionWeight = nftCollectionWeight; }); + props.onConfigChange?.(newConfig); + }} + onCivicPassTypeChange={(civicPassType) => { + const newConfig = produce(props.config, (data) => { + data.civicPassType = civicPassType; + }); + props.onConfigChange?.(newConfig); }} /> diff --git a/hub/components/EditRealmConfig/UpdatesList/index.tsx b/hub/components/EditRealmConfig/UpdatesList/index.tsx index 489e4eb219..f6e7d3e723 100644 --- a/hub/components/EditRealmConfig/UpdatesList/index.tsx +++ b/hub/components/EditRealmConfig/UpdatesList/index.tsx @@ -10,6 +10,7 @@ import { PublicKey } from '@solana/web3.js'; import { BigNumber } from 'bignumber.js'; import BN from 'bn.js'; +import { availablePasses } from '../../../../GatewayPlugin/config'; import { Config } from '../fetchConfig'; import { getLabel } from '../TokenTypeSelector'; import { @@ -45,6 +46,7 @@ export function buildUpdates(config: Config) { nftCollection: config.nftCollection, nftCollectionSize: config.nftCollectionSize, nftCollectionWeight: config.nftCollectionWeight, + civicPassType: config.civicPassType, }; } @@ -81,6 +83,16 @@ export function diff( return diffs; } +const civicPassTypeLabel = (civicPassType: PublicKey | undefined): string => { + if (!civicPassType) return 'None'; + const foundPass = availablePasses.find( + (pass) => pass.value === civicPassType?.toBase58(), + ); + + if (!foundPass) return 'Other (' + abbreviateAddress(civicPassType) + ')'; + return foundPass.name; +}; + function votingStructureText( votingPluginDiff: [PublicKey | undefined, PublicKey | undefined], maxVotingPluginDiff: [PublicKey | undefined, PublicKey | undefined], @@ -156,7 +168,8 @@ export function UpdatesList(props: Props) { 'communityMaxVotingPlugin' in updates || 'nftCollection' in updates || 'nftCollectionSize' in updates || - 'nftCollectionWeight' in updates; + 'nftCollectionWeight' in updates || + 'civicPassType' in updates; const hasCouncilUpdates = 'councilTokenType' in updates || @@ -420,6 +433,19 @@ export function UpdatesList(props: Props) { } /> )} + {'civicPassType' in updates && ( + +
{civicPassTypeLabel(updates.civicPassType[1])}
+
+ {civicPassTypeLabel(updates.civicPassType[0])} +
+
+ } + /> + )}
)} diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx new file mode 100644 index 0000000000..83a6fdaef3 --- /dev/null +++ b/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx @@ -0,0 +1,219 @@ +import ChevronDownIcon from '@carbon/icons-react/lib/ChevronDown'; +import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; + +import { PublicKey } from '@solana/web3.js'; +import React, { FC, useRef, useState } from 'react'; + +import { availablePasses } from '../../../../GatewayPlugin/config'; +import Input from '@components/inputs/Input'; +import cx from '@hub/lib/cx'; + +const itemStyles = cx( + 'border', + 'cursor-pointer', + 'gap-x-4', + 'grid-cols-[150px,1fr,20px]', + 'grid', + 'h-14', + 'items-center', + 'px-4', + 'w-full', + 'rounded-md', + 'text-left', + 'transition-colors', + 'dark:bg-neutral-800', + 'dark:border-neutral-700', + 'dark:hover:bg-neutral-700', +); + +const labelStyles = cx('font-700', 'dark:text-neutral-50', 'w-full'); +const descriptionStyles = cx('dark:text-neutral-400 text-sm'); +const iconStyles = cx('fill-neutral-500', 'h-5', 'transition-transform', 'w-4'); + +// Infer the types from the available passes, giving type safety on the `other` and `default` pass types +type ArrayElement< + ArrayType extends readonly unknown[] +> = ArrayType extends readonly (infer ElementType)[] ? ElementType : never; +type CivicPass = ArrayElement; + +const isOther = (pass: CivicPass | undefined): boolean => + pass?.name === 'Other'; +const other = availablePasses.find(isOther) as CivicPass; + +// if nothing is selected, Uniqueness is most likely what the user wants +const defaultPass = availablePasses.find( + (pass) => pass.name === 'Uniqueness', +) as CivicPass; + +// If Other is selected, allow the user to enter a custom pass address here. +const ManualPassEntry: FC<{ + manualPassType?: PublicKey; + onChange: (newManualPassType?: PublicKey) => void; +}> = ({ manualPassType, onChange }) => { + const [error, setError] = useState(); + const [inputValue, setInputValue] = useState( + manualPassType?.toBase58() || '', + ); + + return ( +
+
+
+
+
+ { + const value = evt.target.value; + setInputValue(value); + try { + const pk = new PublicKey(value); + onChange(pk); + setError(undefined); + } catch { + setError('Invalid address'); + } + }} + error={error} + /> +
+
+
+ ); +}; + +// A dropdown of all the available Civic Passes +const CivicPassDropdown: FC<{ + className?: string; + previousSelected?: PublicKey; + onPassTypeChange(value: PublicKey | undefined): void; +}> = (props) => { + const [open, setOpen] = useState(false); + const trigger = useRef(null); + const [selectedPass, setSelectedPass] = useState( + !!props.previousSelected + ? availablePasses.find( + (pass) => pass.value === props.previousSelected?.toBase58(), + ) ?? other + : defaultPass, + ); + + return ( + +
+ +
+ {selectedPass?.name || 'Select a Civic Pass'} +
+
+ {selectedPass?.description || ''} +
+ +
+ + + {availablePasses.map((config, i) => ( + { + setSelectedPass(config); + props.onPassTypeChange( + config?.value ? new PublicKey(config.value) : undefined, + ); + }} + > +
{config.name}
+
{config.description}
+
+ ))} +
+
+
+ {isOther(selectedPass) && ( + { + setSelectedPass(other); + props.onPassTypeChange(manualPassType); + }} + manualPassType={ + props.previousSelected && selectedPass !== other + ? props.previousSelected + : undefined + } + /> + )} +
+ ); +}; + +interface Props { + className?: string; + currentPassType?: PublicKey; + onPassTypeChange(value: PublicKey | undefined): void; +} + +export function CivicConfigurator(props: Props) { + return ( +
+
+
+
+
+ What type of verification? +
+
+
+ +
+
+
+
+ ); +} diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx index a8706d676d..3b1ecd2a84 100644 --- a/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx +++ b/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx @@ -10,6 +10,7 @@ import cx from '@hub/lib/cx'; import { DEFAULT_NFT_VOTER_PLUGIN } from '@tools/constants'; +import { CivicConfigurator } from './CivicConfigurator'; import { Custom } from './Custom'; import { NFT } from './NFT'; @@ -51,33 +52,24 @@ const labelStyles = cx('font-700', 'dark:text-neutral-50'); const descriptionStyles = cx('dark:text-neutral-400'); const iconStyles = cx('fill-neutral-500', 'h-5', 'transition-transform', 'w-4'); +type VotingStructure = { + votingProgramId?: PublicKey; + maxVotingProgramId?: PublicKey; + nftCollection?: PublicKey; + nftCollectionSize?: number; + nftCollectionWeight?: BN; + civicPassType?: PublicKey; +}; + interface Props { allowNFT?: boolean; allowCivic?: boolean; allowVSR?: boolean; className?: string; communityMint: Config['communityMint']; - currentStructure: { - votingProgramId?: PublicKey; - maxVotingProgramId?: PublicKey; - nftCollection?: PublicKey; - nftCollectionSize?: number; - nftCollectionWeight?: BN; - }; - structure: { - votingProgramId?: PublicKey; - maxVotingProgramId?: PublicKey; - nftCollection?: PublicKey; - nftCollectionSize?: number; - nftCollectionWeight?: BN; - }; - onChange?(value: { - votingProgramId?: PublicKey; - maxVotingProgramId?: PublicKey; - nftCollection?: PublicKey; - nftCollectionSize?: number; - nftCollectionWeight?: BN; - }): void; + currentStructure: VotingStructure; + structure: VotingStructure; + onChange?(value: VotingStructure): void; } function areConfigsEqual(a: Props['structure'], b: Props['structure']) { @@ -258,6 +250,18 @@ export function VotingStructureSelector(props: Props) { }} /> )} + {isCivicConfig(props.structure) && ( + { + const newConfig = produce({ ...props.structure }, (data) => { + data.civicPassType = value ?? undefined; + }); + props.onChange?.(newConfig); + }} + /> + )} =7.23.2", "port-sdk/@saberhq/token-utils": "1.12.53", - "@solana/web3.js": "1.73.3", "react": "18.2.0", "@solana/spl-token-registry": "0.2.3775", "@solana/buffer-layout": "4.0.0", @@ -237,7 +240,8 @@ "@bundlr-network/client": "0.7.15", "@carbon/icons-react": "11.7.0", "@cardinal/namespaces-components": "2.5.5", - "crypto-js": ">=4.1.1" + "crypto-js": ">=4.1.1", + "@solana/web3.js": "1.78.2" }, "browser": { "child_process": false @@ -268,5 +272,8 @@ "draft-js>fbjs>core-js": false, "@switchboard-xyz/solana.js>@switchboard-xyz/common>protobufjs": false } + }, + "volta": { + "node": "18.19.0" } } diff --git a/pages/_error.js b/pages/_error.js index 1068f15f10..1254ef1be4 100644 --- a/pages/_error.js +++ b/pages/_error.js @@ -23,8 +23,8 @@ MyError.getInitialProps = async (context) => { // getInitialProps has run errorInitialProps.hasGetInitialPropsRun = true - // Returning early because we don't want to log 404 errors to Sentry. - if (res?.statusCode === 404) { + // Returning early because we don't want to log 404 or 403 errors to Sentry. + if (res?.statusCode === 404 || res?.statusCode === 403) { return errorInitialProps } diff --git a/pages/dao/[symbol]/account/DelegatorOptions.tsx b/pages/dao/[symbol]/account/DelegatorOptions.tsx index 42fce22055..c31e3af33c 100644 --- a/pages/dao/[symbol]/account/DelegatorOptions.tsx +++ b/pages/dao/[symbol]/account/DelegatorOptions.tsx @@ -4,7 +4,7 @@ import { useTokenOwnerRecordsDelegatedToUser } from '@hooks/queries/tokenOwnerRe import DelegatorsList from './DelegatorsList' const DelegatorOptions = () => { - const delegatesArray = useTokenOwnerRecordsDelegatedToUser() + const { data: delegatesArray } = useTokenOwnerRecordsDelegatedToUser() return delegatesArray === undefined || delegatesArray.length < 1 ? null : (
diff --git a/pages/dao/[symbol]/account/DelegatorsList.tsx b/pages/dao/[symbol]/account/DelegatorsList.tsx index b28d1de796..05a3d979ae 100644 --- a/pages/dao/[symbol]/account/DelegatorsList.tsx +++ b/pages/dao/[symbol]/account/DelegatorsList.tsx @@ -37,7 +37,7 @@ const DelegatorCheckbox = ({ const DelegatorsList = () => { const realm = useRealmQuery().data?.result - const delegatesArray = useTokenOwnerRecordsDelegatedToUser() + const { data: delegatesArray } = useTokenOwnerRecordsDelegatedToUser() // returns array of community tokenOwnerRecords that connected wallet has been delegated const communityTorsDelegatedToUser = useMemo( diff --git a/pages/dao/[symbol]/account/me.tsx b/pages/dao/[symbol]/account/me.tsx index b2bc6786ac..0c75b41d7a 100644 --- a/pages/dao/[symbol]/account/me.tsx +++ b/pages/dao/[symbol]/account/me.tsx @@ -11,6 +11,10 @@ const AccountPage: React.FC = () => { const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result const { data: tokenOwnerRecordPk } = useAddressQuery_CommunityTokenOwner() + if (vsrMode === 'pyth') { + return + } + if ( vsrMode && (!ownTokenRecord || @@ -23,7 +27,6 @@ const AccountPage: React.FC = () => { ) } - return tokenOwnerRecordPk ? ( diff --git a/pages/dao/[symbol]/index.tsx b/pages/dao/[symbol]/index.tsx index 9d37b739da..7f9c38c00c 100644 --- a/pages/dao/[symbol]/index.tsx +++ b/pages/dao/[symbol]/index.tsx @@ -54,6 +54,8 @@ import { } from '@hooks/queries/proposal' import queryClient from '@hooks/queries/queryClient' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import { getFeeEstimate } from '@tools/feeEstimate' +import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' const AccountsCompactWrapper = dynamic( () => import('@components/TreasuryAccount/AccountsCompactWrapper') @@ -263,9 +265,10 @@ const REALM = () => { try { setIsMultiVoting(true) - const { - blockhash: recentBlockhash, - } = await connection.getLatestBlockhash() + const [{ blockhash: recentBlockhash }, fee] = await Promise.all([ + connection.getLatestBlockhash(), + getFeeEstimate(connection), + ]) const transactions: Transaction[] = [] for (let i = 0; i < selectedProposals.length; i++) { @@ -311,8 +314,9 @@ const REALM = () => { } const transaction = new Transaction() - transaction.add(...instructions) + transaction.add(...[createComputeBudgetIx(fee), ...instructions]) transaction.recentBlockhash = recentBlockhash + transaction.feePayer = wallet.publicKey! transaction.setSigners( // fee payed by the wallet owner wallet.publicKey! diff --git a/pages/dao/[symbol]/members/Members.tsx b/pages/dao/[symbol]/members/Members.tsx index ef230c195b..7ae9cadf49 100644 --- a/pages/dao/[symbol]/members/Members.tsx +++ b/pages/dao/[symbol]/members/Members.tsx @@ -1,5 +1,5 @@ import useRealm from '@hooks/useRealm' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import MemberOverview from '@components/Members/MemberOverview' import { PlusCircleIcon, SearchIcon, UsersIcon } from '@heroicons/react/outline' import useGovernanceAssets from '@hooks/useGovernanceAssets' @@ -15,6 +15,10 @@ import { Member } from '@utils/uiTypes/members' import PaginationComponent from '@components/Pagination' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useMembersQuery } from '@components/Members/useMembers' +import { useConnection } from '@solana/wallet-adapter-react' +import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' +import { determineVotingPowerType } from '@hooks/queries/governancePower' +import { useAsync } from 'react-async-hook' const Members = () => { const { @@ -25,7 +29,6 @@ const Members = () => { const pagination = useRef<{ setPage: (val) => void }>(null) const membersPerPage = 10 - const { data: activeMembers } = useMembersQuery() const wallet = useWalletOnePointOh() const connected = !!wallet?.connected const { @@ -38,6 +41,25 @@ const Members = () => { const [searchString, setSearchString] = useState('') const [filteredMembers, setFilteredMembers] = useState([]) + const { connection } = useConnection() + const realmPk = useSelectedRealmPubkey() + const { data: activeMembersData } = useMembersQuery() + + const { result: kind } = useAsync(async () => { + if (realmPk === undefined) return undefined + return determineVotingPowerType(connection, realmPk, 'community') + }, [connection, realmPk]) + + // if this is not vanilla or NFT, this view is used only to show council. filter accordingly. + const councilOnly = !(kind === 'vanilla' || kind === 'NFT') + const activeMembers = useMemo( + () => + councilOnly + ? activeMembersData?.filter((x) => x.councilVotes.gtn(0)) + : activeMembersData, + [activeMembersData, councilOnly] + ) + const filterMembers = (v) => { if (activeMembers !== undefined) { setSearchString(v) @@ -98,7 +120,7 @@ const Members = () => { ) : null}

{realmInfo?.displayName}

-

Members

+

{councilOnly ? 'Council ' : ''}Members

diff --git a/pages/dao/[symbol]/members/index.tsx b/pages/dao/[symbol]/members/index.tsx index 27f1b06c3d..5a84af1007 100644 --- a/pages/dao/[symbol]/members/index.tsx +++ b/pages/dao/[symbol]/members/index.tsx @@ -1,18 +1,8 @@ -import { NFT_PLUGINS_PKS } from '@constants/plugins' import Members from './Members' -import { useRealmConfigQuery } from '@hooks/queries/realmConfig' const MembersPage = () => { - const config = useRealmConfigQuery().data?.result - const currentPluginPk = config?.account.communityTokenConfig.voterWeightAddin - const isNftMode = - (currentPluginPk && - NFT_PLUGINS_PKS.includes(currentPluginPk?.toBase58())) || - false return (
- {!config?.account.communityTokenConfig.voterWeightAddin || isNftMode ? ( - - ) : null} +
) } diff --git a/pages/dao/[symbol]/proposal/[pk]/index.tsx b/pages/dao/[symbol]/proposal/[pk]/index.tsx index 40f03beca6..df6d65f4b1 100644 --- a/pages/dao/[symbol]/proposal/[pk]/index.tsx +++ b/pages/dao/[symbol]/proposal/[pk]/index.tsx @@ -85,7 +85,7 @@ const Proposal = () => { proposal.account.state === ProposalState.ExecutingWithErrors) return ( -
+
{proposal ? ( <> diff --git a/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx b/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx index 72af7f0574..590eadaa19 100644 --- a/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx +++ b/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx @@ -51,6 +51,8 @@ import { useRealmProposalsQuery, } from '@hooks/queries/proposal' import queryClient from '@hooks/queries/queryClient' +import { getFeeEstimate } from '@tools/feeEstimate' +import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' const MyProposalsBn = () => { const [modalIsOpen, setModalIsOpen] = useState(false) @@ -163,9 +165,10 @@ const MyProposalsBn = () => { if (!wallet || !programId || !realm) return setIsLoading(true) try { - const { - blockhash: recentBlockhash, - } = await connection.getLatestBlockhash() + const [{ blockhash: recentBlockhash }, fee] = await Promise.all([ + connection.getLatestBlockhash(), + getFeeEstimate(connection), + ]) const transactions: Transaction[] = [] const instructions: TransactionInstruction[] = [] @@ -180,7 +183,7 @@ const MyProposalsBn = () => { recentBlockhash, feePayer: wallet.publicKey!, }) - transaction.add(...chunk) + transaction.add(...[createComputeBudgetIx(fee), ...chunk]) transaction.recentBlockhash = recentBlockhash transaction.setSigners( // fee payed by the wallet owner diff --git a/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx b/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx index fed05758a5..75642e4f61 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx @@ -33,7 +33,7 @@ import { parseMintNaturalAmountFromDecimal } from '@tools/sdk/units' import { validateInstruction } from '@utils/instructionTools' import useGovernanceNfts from '@components/treasuryV2/WalletList/WalletListItem/AssetList/useGovernanceNfts' -export const SEASON_PREFIX = 117 +export const SEASON_PREFIX = 119 interface FillVaultsForm { governedAccount: AssetAccount | null diff --git a/pages/dao/[symbol]/proposal/components/instructions/Dual/DualGso.tsx b/pages/dao/[symbol]/proposal/components/instructions/Dual/DualGso.tsx index b944bca69d..8d7aa580b0 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Dual/DualGso.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Dual/DualGso.tsx @@ -26,6 +26,7 @@ const DualGso = ({ optionExpirationUnixSeconds: 0, numTokens: 0, lotSize: 0, + lockupMint: '', baseTreasury: undefined, quoteTreasury: undefined, payer: undefined, @@ -91,6 +92,18 @@ const DualGso = ({ error={formErrors['soName']} /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'lockupMint', + }) + } + error={formErrors['lockupMint']} + /> { const [form, setForm] = useState({ numTokens: 0, - realm: 'EGYbpow8V9gt8JFmadFYai4sjfwc7Vc9gazU735hE6u7', + realm: '', delegateToken: undefined, }) const connection = useLegacyConnectionContext() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) const { assetAccounts } = useGovernanceAssets() - const [governedAccount, setGovernedAccount] = useState< - ProgramAccount | undefined - >(undefined) + const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) const handleSetForm = ({ propertyName, value }) => { setFormErrors({}) setForm({ ...form, [propertyName]: value }) } - function getInstruction(): Promise { - return getVoteDepositInstruction({ - connection, - form, - schema, - setFormErrors, - wallet, - }) - } - const schema = useMemo(getDualFinanceVoteDepositSchema, []) + + const realmInputParsed = useRealmPubkeyByPkOrSymbol(form.realm) + useEffect(() => { + const schema = getDualFinanceVoteDepositSchema() + function getInstruction(): Promise { + return getVoteDepositInstruction({ + connection, + form, + schema, + setFormErrors, + wallet, + realmPk: realmInputParsed, + }) + } handleSetInstructions( - { governedAccount: governedAccount, getInstruction }, + { governedAccount: form.delegateToken?.governance, getInstruction }, index ) - }, [form, governedAccount, handleSetInstructions, index, connection, wallet]) - useEffect(() => { - handleSetForm({ value: undefined, propertyName: 'mintPk' }) - }, [form.delegateToken]) - useEffect(() => { - setGovernedAccount(form.delegateToken?.governance) - }, [form.delegateToken]) + }, [form, handleSetInstructions, index, connection, wallet, realmInputParsed]) // TODO: Include this in the config instruction which can optionally be done // if the project doesnt need to change where the tokens get returned to. @@ -85,7 +82,6 @@ const DualVoteDeposit = ({ label="Realm" value={form.realm} type="text" - disabled={true} onChange={(evt) => handleSetForm({ value: evt.target.value, diff --git a/pages/dao/[symbol]/proposal/components/instructions/Dual/StakingOption.tsx b/pages/dao/[symbol]/proposal/components/instructions/Dual/StakingOption.tsx index 6ef9cf33d5..5bb64c82e1 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Dual/StakingOption.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Dual/StakingOption.tsx @@ -34,7 +34,7 @@ const StakingOption = ({ const [form, setForm] = useState({ soName: undefined, optionExpirationUnixSeconds: 0, - numTokens: 0, + numTokens: '0', lotSize: 1, baseTreasury: undefined, quoteTreasury: undefined, @@ -255,7 +255,7 @@ const StakingOption = ({ {baseMetadata && quoteMetadata && ( <>
- {form.strike / form.lotSize * 10 ** (-quoteMetadata.decimals + baseMetadata.decimals) * (form.numTokens / 10 ** baseMetadata.decimals)} + {form.strike / form.lotSize * 10 ** (-quoteMetadata.decimals + baseMetadata.decimals) * (Number(form.numTokens) / 10 ** baseMetadata.decimals)} = - {form.numTokens / 10 ** baseMetadata.decimals} + {Number(form.numTokens) / 10 ** baseMetadata.decimals} | null }) => { const realm = useRealmQuery().data?.result - const { realmInfo } = useRealm() const gatewayClient = useVotePluginsClientStore((s) => s.state.gatewayClient) const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() @@ -63,30 +61,12 @@ const CreateGatewayPluginRegistrar = ({ form!.governedAccount?.governance?.account && wallet?.publicKey ) { - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - gatewayClient!.program.programId + const createRegistrarIx = await createCivicRegistrarIx( + realm!, + wallet.publicKey!, + gatewayClient!, + chosenGatekeeperNetwork!, ) - - const remainingAccounts = form!.predecessor - ? [{ pubkey: form!.predecessor, isSigner: false, isWritable: false }] - : [] - - const createRegistrarIx = await gatewayClient!.program.methods - .createRegistrar(false) - .accounts({ - registrar, - realm: realm!.pubkey, - governanceProgramId: realmInfo!.programId, - realmAuthority: realm!.account.authority!, - governingTokenMint: realm!.account.communityMint!, - gatekeeperNetwork: chosenGatekeeperNetwork, - payer: wallet.publicKey!, - systemProgram: SYSTEM_PROGRAM_ID, - }) - .remainingAccounts(remainingAccounts) - .instruction() serializedInstruction = serializeInstructionToBase64(createRegistrarIx) } return { @@ -146,28 +126,7 @@ const CreateGatewayPluginRegistrar = ({ ), - options: [ - { - name: 'Bot Resistance', - value: 'ignREusXmGrscGNUesoU9mxfds9AiYTezUKex2PsZV6', - }, - { - name: 'Uniqueness', - value: 'uniqobk8oGh4XBLMqM68K8M2zNu3CdYX7q5go7whQiv', - }, - { - name: 'ID Verification', - value: 'bni1ewus6aMxTxBi5SAfzEmmXLf8KcVFRmTfproJuKw', - }, - { - name: 'ID Verification for DeFi', - value: 'gatbGF9DvLAw3kWyn1EmH5Nh1Sqp8sTukF7yaQpSc71', - }, - { - name: 'Other', - value: '', - }, - ], + options: availablePasses as any, }, { label: 'Other Pass', diff --git a/pages/dao/[symbol]/proposal/components/instructions/JoinDAO.tsx b/pages/dao/[symbol]/proposal/components/instructions/JoinDAO.tsx index da950b76d0..af10290233 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/JoinDAO.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/JoinDAO.tsx @@ -162,7 +162,7 @@ const JoinDAO = ({ ((routeHasClusterInPath && cluster) || !routeHasClusterInPath) ) { const realms = getCertifiedRealmInfos(connection) - setCertifiedRealms(realms.filter((r) => !!r.communityMint)) + setCertifiedRealms(realms) } else setCertifiedRealms([]) // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree }, [connection.current.rpcEndpoint]) @@ -201,7 +201,11 @@ const JoinDAO = ({ error={formErrors['realm']} > {certifiedRealms.map((r) => ( - + {r.displayName} ))} diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/AltExtend.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/AltExtend.tsx index 57585a84b8..0e7363c81a 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/AltExtend.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/AltExtend.tsx @@ -14,6 +14,8 @@ import InstructionForm, { InstructionInput } from '../../FormCreator' import { InstructionInputType } from '../../inputInstructionType' import UseMangoV4 from '../../../../../../../../hooks/useMangoV4' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' interface AltExtendForm { governedAccount: AssetAccount | null @@ -31,7 +33,13 @@ const AltExtend = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -148,6 +156,9 @@ const AltExtend = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -135,6 +141,9 @@ const AltSet = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { getAdditionalLabelInfo, mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + + const { getAdditionalLabelInfo, mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const [forcedValues, setForcedValues] = useState([]) const forwarderProgramHelpers = useForwarderProgramHelpers() @@ -387,7 +394,11 @@ const EditToken = ({ const formTokenPk = form.token?.value.toBase58() useEffect(() => { - if (formTokenPk && mangoGroup) { + if ( + formTokenPk && + mangoGroup && + mangoGroup!.banksMapByMint.get(formTokenPk) + ) { const currentToken = mangoGroup!.banksMapByMint.get(formTokenPk)![0] const groupInsuranceFund = mangoGroup.mintInfosMapByMint.get(formTokenPk) ?.groupInsuranceFund @@ -827,6 +838,9 @@ const EditToken = ({ return ( <> + {form && ( <> | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + + const { getAdditionalLabelInfo, mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const [forcedValues, setForcedValues] = useState([]) + const forwarderProgramHelpers = useForwarderProgramHelpers() + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + ((mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup.admin)) || + (mangoGroup?.securityAdmin && + x.extensions.transferAddress?.equals(mangoGroup.securityAdmin))) + ) + const shouldBeGoverned = !!(index !== 0 && governance) + const [tokens, setTokens] = useState([]) + const [originalFormValues, setOriginalFormValues] = useState({ + ...defaultFormValues, + }) + const [form, setForm] = useState({ + ...defaultFormValues, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const bank = mangoGroup!.getFirstBankByMint(new PublicKey(form.mintPk)) + const mintInfo = mangoGroup!.mintInfosMapByTokenIndex.get( + bank.tokenIndex + )! + const values = getChangedValues< + Omit & { reduceOnly: number } + >( + { + ...originalFormValues, + reduceOnly: originalFormValues.reduceOnly.value, + }, + { + ...form, + reduceOnly: form.reduceOnly.value, + }, + forcedValues + ) + + const oracleConfFilter = + (form.oracleConfFilter as number | string) === '' + ? null + : form.oracleConfFilter + const maxStalenessSlots = + (form.maxStalenessSlots as number | string) === '' || + form.maxStalenessSlots === -1 + ? null + : form.maxStalenessSlots + + const isThereNeedOfSendingOracleConfig = + originalFormValues.oracleConfFilter !== oracleConfFilter || + originalFormValues.maxStalenessSlots !== maxStalenessSlots + const rateConfigs = { + adjustmentFactor: getNullOrTransform( + values.adjustmentFactor, + null, + Number + ), + util0: getNullOrTransform(values.util0, null, Number), + rate0: getNullOrTransform(values.rate0, null, Number), + util1: getNullOrTransform(values.util1, null, Number), + rate1: getNullOrTransform(values.rate1, null, Number), + maxRate: getNullOrTransform(values.maxRate, null, Number), + } + const isThereNeedOfSendingRateConfigs = Object.values(rateConfigs).filter( + (x) => x !== null + ).length + //Mango instruction call and serialize + const ix = await mangoClient!.program.methods + .tokenEdit( + getNullOrTransform(values.oraclePk, PublicKey), + isThereNeedOfSendingOracleConfig + ? { + confFilter: Number(form.oracleConfFilter), + maxStalenessSlots: maxStalenessSlots, + } + : null, + values.groupInsuranceFund!, + isThereNeedOfSendingRateConfigs + ? { + adjustmentFactor: Number(form.adjustmentFactor), + util0: Number(form.util0), + rate0: Number(form.rate0), + util1: Number(form.util1), + rate1: Number(form.rate1), + maxRate: Number(form.maxRate), + } + : null, + getNullOrTransform(values.loanFeeRate, null, Number), + getNullOrTransform(values.loanOriginationFeeRate, null, Number), + getNullOrTransform(values.maintAssetWeight, null, Number), + getNullOrTransform(values.initAssetWeight, null, Number), + getNullOrTransform(values.maintLiabWeight, null, Number), + getNullOrTransform(values.initLiabWeight, null, Number), + getNullOrTransform(values.liquidationFee, null, Number), + getNullOrTransform( + values.stablePriceDelayIntervalSeconds, + null, + Number + ), + getNullOrTransform(values.stablePriceDelayGrowthLimit, null, Number), + getNullOrTransform(values.stablePriceGrowthLimit, null, Number), + getNullOrTransform(values.minVaultToDepositsRatio, null, Number), + getNullOrTransform(values.netBorrowLimitPerWindowQuote, BN), + getNullOrTransform(values.netBorrowLimitWindowSizeTs, BN), + getNullOrTransform(values.borrowWeightScaleStartQuote, null, Number), + getNullOrTransform(values.depositWeightScaleStartQuote, null, Number), + values.resetStablePrice!, + values.resetNetBorrowLimit!, + getNullOrTransform(values.reduceOnly, null, Number), + getNullOrTransform(values.name, null, String), + values.forceClose!, + getNullOrTransform( + values.tokenConditionalSwapTakerFeeRate, + null, + Number + ), + getNullOrTransform( + values.tokenConditionalSwapMakerFeeRate, + null, + Number + ), + getNullOrTransform(values.flashLoanSwapFeeRate, null, Number), + getNullOrTransform(values.interestCurveScaling, null, Number), + getNullOrTransform(values.interestTargetUtilization, null, Number), + getNullOrTransform(values.maintWeightShiftStart, BN), + getNullOrTransform(values.maintWeightShiftEnd, BN), + getNullOrTransform(values.maintWeightShiftAssetTarget, null, Number), + getNullOrTransform(values.maintWeightShiftLiabTarget, null, Number), + values.maintWeightShiftAbort!, + values.setFallbackOracle!, + getNullOrTransform(values.depositLimit, BN), + getNullOrTransform(values.zeroUtilRate, null, Number), + getNullOrTransform(values.platformLiquidationFee, null, Number), + values.disableAssetLiquidation!, + getNullOrTransform(values.collateralFeePerDay, null, Number), + values.forceWithdraw! + ) + .accounts({ + group: mangoGroup!.publicKey, + oracle: form.oraclePk ? new PublicKey(form.oraclePk) : bank.oracle, + admin: form.governedAccount.extensions.transferAddress, + mintInfo: mintInfo.publicKey, + fallbackOracle: form.fallbackOracle + ? new PublicKey(form.fallbackOracle) + : bank.fallbackOracle, + }) + .remainingAccounts([ + { + pubkey: bank.publicKey, + isWritable: true, + isSigner: false, + } as AccountMeta, + ]) + .instruction() + + serializedInstruction = serializeInstructionToBase64( + forwarderProgramHelpers.withForwarderWrapper(ix) + ) + } + const obj: UiInstruction = { + serializedInstruction: serializedInstruction, + isValid, + chunkBy: 1, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [ + form, + forcedValues, + forwarderProgramHelpers.form, + forwarderProgramHelpers.withForwarderWrapper, + ]) + + useEffect(() => { + const getTokens = async () => { + const currentTokens = [...mangoGroup!.banksMapByMint.values()].map( + (x) => ({ + name: x[0].name, + value: x[0].mint, + }) + ) + setTokens(currentTokens) + } + if (wallet?.publicKey && mangoGroup) { + getTokens() + } + }, [mangoGroup, wallet?.publicKey]) + + const formTokenPk = form.token?.value.toBase58() + useEffect(() => { + if ( + formTokenPk && + mangoGroup && + mangoGroup!.banksMapByMint.get(formTokenPk) + ) { + const currentToken = mangoGroup!.banksMapByMint.get(formTokenPk)![0] + const groupInsuranceFund = mangoGroup.mintInfosMapByMint.get(formTokenPk) + ?.groupInsuranceFund + + const vals = { + oraclePk: currentToken.oracle.toBase58(), + fallbackOracle: currentToken.fallbackOracle.toBase58(), + oracleConfFilter: currentToken.oracleConfig.confFilter.toNumber(), + maxStalenessSlots: currentToken.oracleConfig.maxStalenessSlots.toNumber(), + mintPk: currentToken.mint.toBase58(), + name: currentToken.name, + adjustmentFactor: currentToken.adjustmentFactor.toNumber(), + util0: currentToken.util0.toNumber(), + rate0: currentToken.rate0.toNumber(), + util1: currentToken.util1.toNumber(), + rate1: currentToken.rate1.toNumber(), + maxRate: currentToken.maxRate.toNumber(), + loanFeeRate: currentToken.loanFeeRate.toNumber(), + loanOriginationFeeRate: currentToken.loanOriginationFeeRate.toNumber(), + maintAssetWeight: currentToken.maintAssetWeight.toNumber(), + initAssetWeight: currentToken.initAssetWeight.toNumber(), + maintLiabWeight: currentToken.maintLiabWeight.toNumber(), + initLiabWeight: currentToken.initLiabWeight.toNumber(), + liquidationFee: currentToken.liquidationFee.toNumber(), + stablePriceDelayIntervalSeconds: + currentToken.stablePriceModel.delayIntervalSeconds, + stablePriceDelayGrowthLimit: + currentToken.stablePriceModel.delayGrowthLimit, + stablePriceGrowthLimit: currentToken.stablePriceModel.stableGrowthLimit, + minVaultToDepositsRatio: currentToken.minVaultToDepositsRatio, + netBorrowLimitPerWindowQuote: currentToken.netBorrowLimitPerWindowQuote.toNumber(), + netBorrowLimitWindowSizeTs: currentToken.netBorrowLimitWindowSizeTs.toNumber(), + borrowWeightScaleStartQuote: currentToken.borrowWeightScaleStartQuote, + depositWeightScaleStartQuote: currentToken.depositWeightScaleStartQuote, + groupInsuranceFund: !!groupInsuranceFund, + reduceOnly: REDUCE_ONLY_OPTIONS.find( + (x) => x.value === currentToken.reduceOnly + )!, + forceClose: currentToken.forceClose, + tokenConditionalSwapTakerFeeRate: + currentToken.tokenConditionalSwapTakerFeeRate, + tokenConditionalSwapMakerFeeRate: + currentToken.tokenConditionalSwapMakerFeeRate, + flashLoanSwapFeeRate: currentToken.flashLoanSwapFeeRate, + interestCurveScaling: currentToken.interestCurveScaling, + interestTargetUtilization: currentToken.interestTargetUtilization, + maintWeightShiftStart: currentToken.maintWeightShiftStart.toNumber(), + maintWeightShiftEnd: currentToken.maintWeightShiftEnd.toNumber(), + maintWeightShiftAssetTarget: currentToken.maintWeightShiftAssetTarget.toNumber(), + maintWeightShiftLiabTarget: currentToken.maintWeightShiftLiabTarget.toNumber(), + depositLimit: currentToken.depositLimit.toNumber(), + zeroUtilRate: currentToken.zeroUtilRate.toNumber(), + platformLiquidationFeeOpt: currentToken.platformLiquidationFee.toNumber(), + collateralFeePerDayOpt: currentToken.collateralFeePerDay, + } + setForm((prevForm) => ({ + ...prevForm, + ...vals, + })) + setOriginalFormValues((prevForm) => ({ ...prevForm, ...vals })) + } + }, [formTokenPk, mangoGroup]) + + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + mintPk: yup + .string() + .required() + .test('is-valid-address1', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + oraclePk: yup + .string() + .required() + .test('is-valid-address2', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + name: yup.string().required(), + }) + + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: 'Token', + name: 'token', + type: InstructionInputType.SELECT, + initialValue: form.token, + options: tokens, + }, + { + label: keyToLabel['mintPk'], + initialValue: form.mintPk, + type: InstructionInputType.INPUT, + name: 'mintPk', + }, + { + label: keyToLabel['oraclePk'], + initialValue: form.oraclePk, + type: InstructionInputType.INPUT, + name: 'oraclePk', + }, + { + label: keyToLabel['fallbackOracle'], + initialValue: form.fallbackOracle, + type: InstructionInputType.INPUT, + name: 'fallbackOracle', + }, + { + label: keyToLabel['oracleConfFilter'], + subtitle: getAdditionalLabelInfo('oracleConfFilter'), + initialValue: form.oracleConfFilter, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'oracleConfFilter', + }, + { + label: keyToLabel['maxStalenessSlots'], + subtitle: getAdditionalLabelInfo('maxStalenessSlots'), + initialValue: form.maxStalenessSlots, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxStalenessSlots', + }, + { + label: keyToLabel['name'], + initialValue: form.name, + type: InstructionInputType.INPUT, + name: 'name', + }, + { + label: keyToLabel['adjustmentFactor'], + subtitle: getAdditionalLabelInfo('adjustmentFactor'), + initialValue: form.adjustmentFactor, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'adjustmentFactor', + }, + { + label: keyToLabel['util0'], + initialValue: form.util0, + subtitle: getAdditionalLabelInfo('util0'), + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'util0', + }, + { + label: keyToLabel['rate0'], + subtitle: getAdditionalLabelInfo('rate0'), + initialValue: form.rate0, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'rate0', + }, + { + label: keyToLabel['util1'], + subtitle: getAdditionalLabelInfo('util1'), + initialValue: form.util1, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'util1', + }, + { + label: keyToLabel['rate1'], + subtitle: getAdditionalLabelInfo('rate1'), + initialValue: form.rate1, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'rate1', + }, + { + label: keyToLabel['maxRate'], + subtitle: getAdditionalLabelInfo('maxRate'), + initialValue: form.maxRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxRate', + }, + { + label: keyToLabel['loanFeeRate'], + subtitle: getAdditionalLabelInfo('loanFeeRate'), + initialValue: form.loanFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'loanFeeRate', + }, + { + label: keyToLabel['loanOriginationFeeRate'], + subtitle: getAdditionalLabelInfo('loanOriginationFeeRate'), + initialValue: form.loanOriginationFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'loanOriginationFeeRate', + }, + { + label: keyToLabel['maintAssetWeight'], + subtitle: getAdditionalLabelInfo('maintAssetWeight'), + initialValue: form.maintAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintAssetWeight', + }, + { + label: keyToLabel['initAssetWeight'], + subtitle: getAdditionalLabelInfo('initAssetWeight'), + initialValue: form.initAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initAssetWeight', + }, + { + label: keyToLabel['maintLiabWeight'], + subtitle: getAdditionalLabelInfo('maintLiabWeight'), + initialValue: form.maintLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintLiabWeight', + }, + { + label: keyToLabel['initLiabWeight'], + subtitle: getAdditionalLabelInfo('initLiabWeight'), + initialValue: form.initLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initLiabWeight', + }, + { + label: keyToLabel['liquidationFee'], + subtitle: getAdditionalLabelInfo('liquidationFee'), + initialValue: form.liquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'liquidationFee', + }, + { + label: keyToLabel['groupInsuranceFund'], + subtitle: getAdditionalLabelInfo('groupInsuranceFund'), + initialValue: form.groupInsuranceFund, + type: InstructionInputType.SWITCH, + name: 'groupInsuranceFund', + }, + { + label: keyToLabel['stablePriceDelayIntervalSeconds'], + subtitle: getAdditionalLabelInfo('stablePriceDelayIntervalSeconds'), + initialValue: form.stablePriceDelayIntervalSeconds, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayIntervalSeconds', + }, + { + label: keyToLabel['stablePriceDelayGrowthLimit'], + subtitle: getAdditionalLabelInfo('stablePriceDelayGrowthLimit'), + initialValue: form.stablePriceDelayGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayGrowthLimit', + }, + { + label: keyToLabel['stablePriceGrowthLimit'], + subtitle: getAdditionalLabelInfo('stablePriceGrowthLimit'), + initialValue: form.stablePriceGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceGrowthLimit', + }, + { + label: keyToLabel['minVaultToDepositsRatio'], + subtitle: getAdditionalLabelInfo('minVaultToDepositsRatio'), + initialValue: form.minVaultToDepositsRatio, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'minVaultToDepositsRatio', + }, + { + label: keyToLabel['netBorrowLimitPerWindowQuote'], + subtitle: getAdditionalLabelInfo('netBorrowLimitPerWindowQuote'), + initialValue: form.netBorrowLimitPerWindowQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'netBorrowLimitPerWindowQuote', + }, + { + label: keyToLabel['netBorrowLimitWindowSizeTs'], + subtitle: getAdditionalLabelInfo('netBorrowLimitWindowSizeTs'), + initialValue: form.netBorrowLimitWindowSizeTs, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'netBorrowLimitWindowSizeTs', + }, + { + label: keyToLabel['borrowWeightScaleStartQuote'], + subtitle: getAdditionalLabelInfo('borrowWeightScaleStartQuote'), + initialValue: form.borrowWeightScaleStartQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'borrowWeightScaleStartQuote', + }, + { + label: keyToLabel['depositWeightScaleStartQuote'], + subtitle: getAdditionalLabelInfo('depositWeightScaleStartQuote'), + initialValue: form.depositWeightScaleStartQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'depositWeightScaleStartQuote', + }, + { + label: keyToLabel['resetStablePrice'], + subtitle: getAdditionalLabelInfo('resetStablePrice'), + initialValue: form.resetStablePrice, + type: InstructionInputType.SWITCH, + name: 'resetStablePrice', + }, + { + label: keyToLabel['resetNetBorrowLimit'], + subtitle: getAdditionalLabelInfo('resetNetBorrowLimit'), + initialValue: form.resetNetBorrowLimit, + type: InstructionInputType.SWITCH, + name: 'resetNetBorrowLimit', + }, + { + label: keyToLabel['reduceOnly'], + subtitle: getAdditionalLabelInfo('reduceOnly'), + initialValue: form.reduceOnly, + type: InstructionInputType.SELECT, + options: REDUCE_ONLY_OPTIONS, + name: 'reduceOnly', + }, + { + label: keyToLabel['forceClose'], + subtitle: getAdditionalLabelInfo('forceClose'), + initialValue: form.forceClose, + type: InstructionInputType.SWITCH, + name: 'forceClose', + }, + { + label: keyToLabel['tokenConditionalSwapMakerFeeRate'], + subtitle: getAdditionalLabelInfo('tokenConditionalSwapMakerFeeRate'), + initialValue: form.tokenConditionalSwapMakerFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'tokenConditionalSwapMakerFeeRate', + }, + { + label: keyToLabel['tokenConditionalSwapTakerFeeRate'], + subtitle: getAdditionalLabelInfo('tokenConditionalSwapTakerFeeRate'), + initialValue: form.tokenConditionalSwapTakerFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'tokenConditionalSwapTakerFeeRate', + }, + { + label: keyToLabel['flashLoanSwapFeeRate'], + subtitle: getAdditionalLabelInfo('flashLoanSwapFeeRate'), + initialValue: form.flashLoanSwapFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'flashLoanSwapFeeRate', + }, + { + label: keyToLabel['interestCurveScaling'], + subtitle: getAdditionalLabelInfo('interestCurveScaling'), + initialValue: form.interestCurveScaling, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'interestCurveScaling', + }, + { + label: keyToLabel['interestTargetUtilization'], + subtitle: getAdditionalLabelInfo('interestTargetUtilization'), + initialValue: form.interestTargetUtilization, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'interestTargetUtilization', + }, + { + label: keyToLabel['maintWeightShiftStart'], + subtitle: getAdditionalLabelInfo('maintWeightShiftStart'), + initialValue: form.maintWeightShiftStart, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintWeightShiftStart', + }, + { + label: keyToLabel['maintWeightShiftEnd'], + subtitle: getAdditionalLabelInfo('maintWeightShiftEnd'), + initialValue: form.maintWeightShiftEnd, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintWeightShiftEnd', + }, + { + label: keyToLabel['maintWeightShiftAssetTarget'], + subtitle: getAdditionalLabelInfo('maintWeightShiftAssetTarget'), + initialValue: form.maintWeightShiftAssetTarget, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintWeightShiftAssetTarget', + }, + { + label: keyToLabel['maintWeightShiftLiabTarget'], + subtitle: getAdditionalLabelInfo('maintWeightShiftLiabTarget'), + initialValue: form.maintWeightShiftLiabTarget, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintWeightShiftLiabTarget', + }, + { + label: keyToLabel['maintWeightShiftAbort'], + subtitle: getAdditionalLabelInfo('maintWeightShiftAbort'), + initialValue: form.maintWeightShiftAbort, + type: InstructionInputType.SWITCH, + name: 'maintWeightShiftAbort', + }, + { + label: keyToLabel['setFallbackOracle'], + subtitle: getAdditionalLabelInfo('setFallbackOracle'), + initialValue: form.setFallbackOracle, + type: InstructionInputType.SWITCH, + name: 'setFallbackOracle', + }, + { + label: keyToLabel['depositLimit'], + subtitle: getAdditionalLabelInfo('depositLimit'), + initialValue: form.depositLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'depositLimit', + }, + { + label: keyToLabel['zeroUtilRate'], + subtitle: getAdditionalLabelInfo('zeroUtilRate'), + initialValue: form.zeroUtilRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'zeroUtilRate', + }, + { + label: keyToLabel['platformLiquidationFee'], + subtitle: getAdditionalLabelInfo('platformLiquidationFee'), + initialValue: form.platformLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'platformLiquidationFee', + }, + { + label: keyToLabel['disableAssetLiquidation'], + subtitle: getAdditionalLabelInfo('disableAssetLiquidation'), + initialValue: form.disableAssetLiquidation, + type: InstructionInputType.SWITCH, + name: 'disableAssetLiquidation', + }, + { + label: keyToLabel['collateralFeePerDay'], + subtitle: getAdditionalLabelInfo('collateralFeePerDay'), + initialValue: form.collateralFeePerDay, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'collateralFeePerDay', + }, + { + label: keyToLabel['forceWithdraw'], + subtitle: getAdditionalLabelInfo('forceWithdraw'), + initialValue: form.forceWithdraw, + type: InstructionInputType.SWITCH, + name: 'forceWithdraw', + }, + ] + + return ( + <> + + {form && ( + <> + + + +

Force values

+
+ {Object.keys(defaultFormValues) + .filter((x) => x !== 'governedAccount') + .filter((x) => x !== 'token') + .filter((x) => x !== 'holdupTime') + .map((key) => ( +
+
{keyToLabel[key]}
+
+ x === key) ? true : false + } + onChange={(checked) => { + if (checked) { + setForcedValues([...forcedValues, key]) + } else { + setForcedValues([ + ...forcedValues.filter((x) => x !== key), + ]) + } + }} + /> +
+
+ ))} +
+
+ + )} + + ) +} + +export default EditToken diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/GroupEdit.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/GroupEdit.tsx index 426bf98a7b..37f76268a9 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/GroupEdit.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/GroupEdit.tsx @@ -17,6 +17,8 @@ import { getChangedValues, getNullOrTransform } from '@utils/mangoV4Tools' import AdvancedOptionsDropdown from '@components/NewRealmWizard/components/AdvancedOptionsDropdown' import Switch from '@components/Switch' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' const keyToLabel = { admin: 'Admin', @@ -74,7 +76,11 @@ const GroupEdit = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -328,6 +334,9 @@ const GroupEdit = ({ return ( <> + {form && ( <> | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + ((mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup.admin)) || + (mangoGroup?.securityAdmin && + x.extensions.transferAddress?.equals(mangoGroup.securityAdmin))) + ) + const shouldBeGoverned = !!(index !== 0 && governance) + const [originalFormValues, setOriginalFormValues] = useState({ + ...defaultFormValues, + }) + const [form, setForm] = useState({ ...defaultFormValues }) + const [forcedValues, setForcedValues] = useState([]) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const values = getChangedValues( + originalFormValues, + form, + forcedValues + ) + //Mango instruction call and serialize + const ix = await mangoClient!.program.methods + .groupEdit( + getNullOrTransform(values.admin, PublicKey), + getNullOrTransform(values.fastListingAdmin, PublicKey), + getNullOrTransform(values.securityAdmin, PublicKey), + getNullOrTransform(values.testing, null, Number), + getNullOrTransform(values.version, null, Number), + getNullOrTransform(values.depositLimitQuote, BN), + getNullOrTransform(values.feePayWithMngo, null, Boolean), + getNullOrTransform(values.feesMngoBonusRate, null, Number), + getNullOrTransform(values.feesSwapMangoAccount, PublicKey), + getNullOrTransform(values.feesMngoTokenIndex, null, Number), + getNullOrTransform(values.feesExpiryInterval, BN), + getNullOrTransform( + values.allowedFastListingsPerInterval, + null, + Number + ), + getNullOrTransform(values.collateralFeeInterval, BN) + ) + .accounts({ + group: mangoGroup!.publicKey, + admin: mangoGroup!.admin, + }) + .instruction() + + serializedInstruction = serializeInstructionToBase64(ix) + } + const obj: UiInstruction = { + serializedInstruction: serializedInstruction, + isValid, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [form, forcedValues]) + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + admin: yup + .string() + .required() + .test('is-valid-address', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + fastListingAdmin: yup + .string() + .required() + .test('is-valid-address1', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + securityAdmin: yup + .string() + .required() + .test('is-valid-address2', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + feesSwapMangoAccount: yup + .string() + .nullable() + .test('is-valid-address3', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + testing: yup.string().required(), + version: yup.string().required(), + depositLimitQuote: yup.string().required(), + }) + + useEffect(() => { + const getGroupParams = async () => { + const vals = { + admin: mangoGroup!.admin.toBase58(), + fastListingAdmin: mangoGroup!.fastListingAdmin.toBase58(), + securityAdmin: mangoGroup!.securityAdmin.toBase58(), + testing: mangoGroup!.testing, + version: mangoGroup!.version, + feePayWithMngo: mangoGroup!.buybackFees, + feesMngoBonusRate: mangoGroup!.buybackFeesMngoBonusFactor, + feesSwapMangoAccount: mangoGroup!.buybackFeesSwapMangoAccount?.toBase58(), + feesMngoTokenIndex: mangoGroup!.mngoTokenIndex, + feesExpiryInterval: mangoGroup!.buybackFeesExpiryInterval?.toNumber(), + allowedFastListingsPerInterval: mangoGroup! + .allowedFastListingsPerInterval, + collateralFeeInterval: mangoGroup!.collateralFeeInterval.toNumber(), + } + setForm((prevForm) => ({ + ...prevForm, + ...vals, + })) + setOriginalFormValues((prevForm) => ({ ...prevForm, ...vals })) + } + if (mangoGroup) { + getGroupParams() + } + }, [mangoGroup]) + + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: keyToLabel['admin'], + subtitle: getAdditionalLabelInfo('admin'), + initialValue: form.admin, + type: InstructionInputType.INPUT, + name: 'admin', + }, + { + label: keyToLabel['fastListingAdmin'], + subtitle: getAdditionalLabelInfo('fastListingAdmin'), + initialValue: form.fastListingAdmin, + type: InstructionInputType.INPUT, + name: 'fastListingAdmin', + }, + { + label: keyToLabel['securityAdmin'], + subtitle: getAdditionalLabelInfo('securityAdmin'), + initialValue: form.securityAdmin, + type: InstructionInputType.INPUT, + name: 'securityAdmin', + }, + { + label: keyToLabel['testing'], + subtitle: getAdditionalLabelInfo('testing'), + initialValue: form.testing, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'testing', + }, + { + label: keyToLabel['version'], + subtitle: getAdditionalLabelInfo('version'), + initialValue: form.version, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'version', + }, + { + label: keyToLabel['depositLimitQuote'], + subtitle: getAdditionalLabelInfo('depositLimitQuote'), + initialValue: form.depositLimitQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'depositLimitQuote', + }, + { + label: keyToLabel['feePayWithMngo'], + initialValue: form.feePayWithMngo, + subtitle: getAdditionalLabelInfo('buybackFees'), + type: InstructionInputType.SWITCH, + name: 'feePayWithMngo', + }, + { + label: keyToLabel['feesMngoBonusRate'], + subtitle: getAdditionalLabelInfo('buybackFeesMngoBonusFactor'), + initialValue: form.feesMngoBonusRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'feesMngoBonusRate', + }, + { + label: keyToLabel['feesSwapMangoAccount'], + subtitle: getAdditionalLabelInfo('buybackFeesSwapMangoAccount'), + initialValue: form.feesSwapMangoAccount, + type: InstructionInputType.INPUT, + name: 'feesSwapMangoAccount', + }, + { + label: keyToLabel['feesMngoTokenIndex'], + subtitle: getAdditionalLabelInfo('mngoTokenIndex'), + initialValue: form.feesMngoTokenIndex, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'feesMngoTokenIndex', + }, + { + label: keyToLabel['feesExpiryInterval'], + subtitle: getAdditionalLabelInfo('feesExpiryInterval'), + initialValue: form.feesExpiryInterval, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'feesExpiryInterval', + }, + { + label: keyToLabel['allowedFastListingsPerInterval'], + subtitle: getAdditionalLabelInfo('allowedFastListingsPerInterval'), + initialValue: form.allowedFastListingsPerInterval, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'allowedFastListingsPerInterval', + }, + { + label: keyToLabel['collateralFeeInterval'], + subtitle: getAdditionalLabelInfo('collateralFeeInterval'), + initialValue: form.collateralFeeInterval, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'collateralFeeInterval', + }, + ] + + return ( + <> + + {form && ( + <> + + +

Force values

+
+ {Object.keys(defaultFormValues) + .filter((x) => x !== 'governedAccount') + .filter((x) => x !== 'holdupTime') + .map((key) => ( +
+
{keyToLabel[key]}
+
+ x === key) ? true : false + } + onChange={(checked) => { + if (checked) { + setForcedValues([...forcedValues, key]) + } else { + setForcedValues([ + ...forcedValues.filter((x) => x !== key), + ]) + } + }} + /> +
+
+ ))} +
+
+ + )} + + ) +} + +export default GroupEdit diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/IxGateSet.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/IxGateSet.tsx index 01890ab643..ea37e78ac4 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/IxGateSet.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/IxGateSet.tsx @@ -15,6 +15,8 @@ import UseMangoV4 from '../../../../../../../../hooks/useMangoV4' import { buildIxGate } from '@blockworks-foundation/mango-v4' import { IxGateParams } from '@blockworks-foundation/mango-v4/dist/types/src/clientIxParamBuilder' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' type IxGateSetForm = IxGateParams & { governedAccount: AssetAccount | null @@ -29,7 +31,11 @@ const IxGateSet = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -638,6 +644,9 @@ const IxGateSet = ({ return ( <> + {form && ( | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + ((mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup.admin)) || + (mangoGroup?.securityAdmin && + x.extensions.transferAddress?.equals(mangoGroup.securityAdmin))) + ) + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + holdupTime: 0, + AccountClose: true, + AccountCreate: true, + AccountEdit: true, + AccountExpand: true, + AccountToggleFreeze: true, + AltExtend: true, + AltSet: true, + FlashLoan: true, + GroupClose: true, + GroupCreate: true, + GroupToggleHalt: true, + HealthRegion: true, + PerpCancelAllOrders: true, + PerpCancelAllOrdersBySide: true, + PerpCancelOrder: true, + PerpCancelOrderByClientOrderId: true, + PerpCloseMarket: true, + PerpConsumeEvents: true, + PerpCreateMarket: true, + PerpDeactivatePosition: true, + PerpEditMarket: true, + PerpLiqBaseOrPositivePnl: true, + PerpLiqForceCancelOrders: true, + PerpLiqNegativePnlOrBankruptcy: true, + PerpPlaceOrder: true, + PerpSettleFees: true, + PerpSettlePnl: true, + PerpUpdateFunding: true, + Serum3CancelAllOrders: true, + Serum3CancelOrder: true, + Serum3CloseOpenOrders: true, + Serum3CreateOpenOrders: true, + Serum3DeregisterMarket: true, + Serum3EditMarket: true, + Serum3LiqForceCancelOrders: true, + Serum3PlaceOrder: true, + Serum3RegisterMarket: true, + Serum3SettleFunds: true, + StubOracleClose: true, + StubOracleCreate: true, + StubOracleSet: true, + TokenAddBank: true, + TokenDeposit: true, + TokenDeregister: true, + TokenEdit: true, + TokenLiqBankruptcy: true, + TokenLiqWithToken: true, + TokenRegister: true, + TokenRegisterTrustless: true, + TokenUpdateIndexAndRate: true, + TokenWithdraw: true, + AccountBuybackFeesWithMngo: true, + TokenForceCloseBorrowsWithToken: true, + PerpForceClosePosition: true, + GroupWithdrawInsuranceFund: true, + TokenConditionalSwapCreate: true, + TokenConditionalSwapTrigger: true, + TokenConditionalSwapCancel: true, + OpenbookV2CancelOrder: true, + OpenbookV2CloseOpenOrders: true, + OpenbookV2CreateOpenOrders: true, + OpenbookV2DeregisterMarket: true, + OpenbookV2EditMarket: true, + OpenbookV2LiqForceCancelOrders: true, + OpenbookV2PlaceOrder: true, + OpenbookV2PlaceTakeOrder: true, + OpenbookV2RegisterMarket: true, + OpenbookV2SettleFunds: true, + AdminTokenWithdrawFees: true, + AdminPerpWithdrawFees: true, + AccountSizeMigration: true, + TokenConditionalSwapStart: true, + TokenConditionalSwapCreatePremiumAuction: true, + TokenConditionalSwapCreateLinearAuction: true, + Serum3PlaceOrderV2: true, + TokenForceWithdraw: true, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const ix = await mangoClient!.program.methods + .ixGateSet(buildIxGate(form)) + .accounts({ + group: mangoGroup!.publicKey, + admin: form.governedAccount.extensions.transferAddress, + }) + .instruction() + + serializedInstruction = serializeInstructionToBase64(ix) + } + const obj: UiInstruction = { + serializedInstruction: serializedInstruction, + isValid, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [form]) + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: 'Account Close', + initialValue: form.AccountClose, + type: InstructionInputType.SWITCH, + name: 'AccountClose', + }, + { + label: 'Account Create', + initialValue: form.AccountCreate, + type: InstructionInputType.SWITCH, + name: 'AccountCreate', + }, + { + label: 'Account Edit', + initialValue: form.AccountEdit, + type: InstructionInputType.SWITCH, + name: 'AccountEdit', + }, + { + label: 'Account Expand', + initialValue: form.AccountExpand, + type: InstructionInputType.SWITCH, + name: 'AccountExpand', + }, + { + label: 'Account Toggle Freeze', + initialValue: form.AccountToggleFreeze, + type: InstructionInputType.SWITCH, + name: 'AccountToggleFreeze', + }, + { + label: 'Alt Extend', + initialValue: form.AltExtend, + type: InstructionInputType.SWITCH, + name: 'AltExtend', + }, + { + label: 'Alt Set', + initialValue: form.AltSet, + type: InstructionInputType.SWITCH, + name: 'AltSet', + }, + { + label: 'Flash Loan', + initialValue: form.FlashLoan, + type: InstructionInputType.SWITCH, + name: 'FlashLoan', + }, + { + label: 'Group Close', + initialValue: form.GroupClose, + type: InstructionInputType.SWITCH, + name: 'GroupClose', + }, + { + label: 'Group Create', + initialValue: form.GroupCreate, + type: InstructionInputType.SWITCH, + name: 'GroupCreate', + }, + { + label: 'Group Toggle Halt', + initialValue: form.GroupToggleHalt, + type: InstructionInputType.SWITCH, + name: 'GroupToggleHalt', + }, + { + label: 'Health Region', + initialValue: form.HealthRegion, + type: InstructionInputType.SWITCH, + name: 'HealthRegion', + }, + { + label: 'Perp Cancel All Orders', + initialValue: form.PerpCancelAllOrders, + type: InstructionInputType.SWITCH, + name: 'PerpCancelAllOrders', + }, + { + label: 'Perp Cancel All Orders By Side', + initialValue: form.PerpCancelAllOrdersBySide, + type: InstructionInputType.SWITCH, + name: 'PerpCancelAllOrdersBySide', + }, + { + label: 'Perp Cancel Order', + initialValue: form.PerpCancelOrder, + type: InstructionInputType.SWITCH, + name: 'PerpCancelOrder', + }, + { + label: 'Perp Cancel Order By Client Order Id', + initialValue: form.PerpCancelOrderByClientOrderId, + type: InstructionInputType.SWITCH, + name: 'PerpCancelOrderByClientOrderId', + }, + { + label: 'Perp Close Market', + initialValue: form.PerpCloseMarket, + type: InstructionInputType.SWITCH, + name: 'PerpCloseMarket', + }, + { + label: 'Perp Consume Events', + initialValue: form.PerpConsumeEvents, + type: InstructionInputType.SWITCH, + name: 'PerpConsumeEvents', + }, + { + label: 'Perp Create Market', + initialValue: form.PerpCreateMarket, + type: InstructionInputType.SWITCH, + name: 'PerpCreateMarket', + }, + { + label: 'Perp Deactivate Position', + initialValue: form.PerpDeactivatePosition, + type: InstructionInputType.SWITCH, + name: 'PerpDeactivatePosition', + }, + { + label: 'Perp Edit Market', + initialValue: form.PerpEditMarket, + type: InstructionInputType.SWITCH, + name: 'PerpEditMarket', + }, + { + label: 'Perp Liq Base Or Positive Pnl', + initialValue: form.PerpLiqBaseOrPositivePnl, + type: InstructionInputType.SWITCH, + name: 'PerpLiqBaseOrPositivePnl', + }, + { + label: 'Perp Liq Negative Pnl Or Bankruptcy', + initialValue: form.PerpLiqNegativePnlOrBankruptcy, + type: InstructionInputType.SWITCH, + name: 'PerpLiqNegativePnlOrBankruptcy', + }, + { + label: 'Perp Liq Force Cancel Orders', + initialValue: form.PerpLiqForceCancelOrders, + type: InstructionInputType.SWITCH, + name: 'PerpLiqForceCancelOrders', + }, + { + label: 'Perp Place Order', + initialValue: form.PerpPlaceOrder, + type: InstructionInputType.SWITCH, + name: 'PerpPlaceOrder', + }, + { + label: 'Perp Settle Fees', + initialValue: form.PerpSettleFees, + type: InstructionInputType.SWITCH, + name: 'PerpSettleFees', + }, + { + label: 'Perp Settle Pnl', + initialValue: form.PerpSettlePnl, + type: InstructionInputType.SWITCH, + name: 'PerpSettlePnl', + }, + { + label: 'Perp Update Funding', + initialValue: form.PerpUpdateFunding, + type: InstructionInputType.SWITCH, + name: 'PerpUpdateFunding', + }, + { + label: 'Serum 3 Cancel All Orders', + initialValue: form.Serum3CancelAllOrders, + type: InstructionInputType.SWITCH, + name: 'Serum3CancelAllOrders', + }, + { + label: 'Serum 3 Cancel Order', + initialValue: form.Serum3CancelOrder, + type: InstructionInputType.SWITCH, + name: 'Serum3CancelOrder', + }, + { + label: 'Serum 3 Close Open Orders', + initialValue: form.Serum3CloseOpenOrders, + type: InstructionInputType.SWITCH, + name: 'Serum3CloseOpenOrders', + }, + { + label: 'Serum 3 Create Open Orders', + initialValue: form.Serum3CreateOpenOrders, + type: InstructionInputType.SWITCH, + name: 'Serum3CreateOpenOrders', + }, + { + label: 'Serum 3 Deregister Market', + initialValue: form.Serum3DeregisterMarket, + type: InstructionInputType.SWITCH, + name: 'Serum3DeregisterMarket', + }, + { + label: 'Serum 3 Edit Market', + initialValue: form.Serum3EditMarket, + type: InstructionInputType.SWITCH, + name: 'Serum3EditMarket', + }, + { + label: 'Serum 3 Liq Force Cancel Orders', + initialValue: form.Serum3LiqForceCancelOrders, + type: InstructionInputType.SWITCH, + name: 'Serum3LiqForceCancelOrders', + }, + { + label: 'Serum 3 Place Order', + initialValue: form.Serum3PlaceOrder, + type: InstructionInputType.SWITCH, + name: 'Serum3PlaceOrder', + }, + { + label: 'Serum 3 Register Market', + initialValue: form.Serum3RegisterMarket, + type: InstructionInputType.SWITCH, + name: 'Serum3RegisterMarket', + }, + { + label: 'Serum 3 Settle Funds', + initialValue: form.Serum3SettleFunds, + type: InstructionInputType.SWITCH, + name: 'Serum3SettleFunds', + }, + { + label: 'Stub Oracle Close', + initialValue: form.StubOracleClose, + type: InstructionInputType.SWITCH, + name: 'StubOracleClose', + }, + { + label: 'Stub Oracle Create', + initialValue: form.StubOracleCreate, + type: InstructionInputType.SWITCH, + name: 'StubOracleCreate', + }, + { + label: 'Stub Oracle Set', + initialValue: form.StubOracleSet, + type: InstructionInputType.SWITCH, + name: 'StubOracleSet', + }, + { + label: 'Token Add Bank', + initialValue: form.TokenAddBank, + type: InstructionInputType.SWITCH, + name: 'TokenAddBank', + }, + { + label: 'Token Deposit', + initialValue: form.TokenDeposit, + type: InstructionInputType.SWITCH, + name: 'TokenDeposit', + }, + { + label: 'Token Deregister', + initialValue: form.TokenDeregister, + type: InstructionInputType.SWITCH, + name: 'TokenDeregister', + }, + { + label: 'Token Edit', + initialValue: form.TokenEdit, + type: InstructionInputType.SWITCH, + name: 'TokenEdit', + }, + { + label: 'Token Liq Bankruptcy', + initialValue: form.TokenLiqBankruptcy, + type: InstructionInputType.SWITCH, + name: 'TokenLiqBankruptcy', + }, + { + label: 'Token Liq With Token', + initialValue: form.TokenLiqWithToken, + type: InstructionInputType.SWITCH, + name: 'TokenLiqWithToken', + }, + { + label: 'Token Register', + initialValue: form.TokenRegister, + type: InstructionInputType.SWITCH, + name: 'TokenRegister', + }, + { + label: 'Token Register Trustless', + initialValue: form.TokenRegisterTrustless, + type: InstructionInputType.SWITCH, + name: 'TokenRegisterTrustless', + }, + { + label: 'Token Update Index And Rate', + initialValue: form.TokenUpdateIndexAndRate, + type: InstructionInputType.SWITCH, + name: 'TokenUpdateIndexAndRate', + }, + { + label: 'Token Withdraw', + initialValue: form.TokenWithdraw, + type: InstructionInputType.SWITCH, + name: 'TokenWithdraw', + }, + { + label: 'Account Buyback Fees With Mngo', + initialValue: form.AccountBuybackFeesWithMngo, + type: InstructionInputType.SWITCH, + name: 'AccountBuybackFeesWithMngo', + }, + { + label: 'Token Force Close Borrows With Token', + initialValue: form.TokenForceCloseBorrowsWithToken, + type: InstructionInputType.SWITCH, + name: 'TokenForceCloseBorrowsWithToken', + }, + { + label: 'Perp Force Close Position', + initialValue: form.PerpForceClosePosition, + type: InstructionInputType.SWITCH, + name: 'PerpForceClosePosition', + }, + { + label: 'Group Withdraw Insurance Fund', + initialValue: form.GroupWithdrawInsuranceFund, + type: InstructionInputType.SWITCH, + name: 'GroupWithdrawInsuranceFund', + }, + { + label: 'Token Conditional Swap Create', + initialValue: form.TokenConditionalSwapCreate, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapCreate', + }, + { + label: 'Token Conditional Swap Trigger', + initialValue: form.TokenConditionalSwapTrigger, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapTrigger', + }, + { + label: 'Token Conditional Swap Cancel', + initialValue: form.TokenConditionalSwapCancel, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapCancel', + }, + { + label: 'Openbook V2 Cancel Order', + initialValue: form.OpenbookV2CancelOrder, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2CancelOrder', + }, + { + label: 'Openbook V2 Close Open Orders', + initialValue: form.OpenbookV2CloseOpenOrders, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2CloseOpenOrders', + }, + { + label: 'Openbook V2 Create Open Orders', + initialValue: form.OpenbookV2CreateOpenOrders, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2CreateOpenOrders', + }, + { + label: 'Openbook V2 Deregister Market', + initialValue: form.OpenbookV2DeregisterMarket, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2DeregisterMarket', + }, + { + label: 'Openbook V2 Edit Market', + initialValue: form.OpenbookV2EditMarket, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2EditMarket', + }, + { + label: 'Openbook V2 Liq Force Cancel Orders', + initialValue: form.OpenbookV2LiqForceCancelOrders, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2LiqForceCancelOrders', + }, + { + label: 'Openbook V2 Place Order', + initialValue: form.OpenbookV2PlaceOrder, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2PlaceOrder', + }, + { + label: 'Openbook V2 Place Take Order', + initialValue: form.OpenbookV2PlaceTakeOrder, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2PlaceTakeOrder', + }, + { + label: 'Openbook V2 Register Market', + initialValue: form.OpenbookV2RegisterMarket, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2RegisterMarket', + }, + { + label: 'Openbook V2 Settle Funds', + initialValue: form.OpenbookV2SettleFunds, + type: InstructionInputType.SWITCH, + name: 'OpenbookV2SettleFunds', + }, + { + label: 'Admin Token Withdraw Fees', + initialValue: form.AdminTokenWithdrawFees, + type: InstructionInputType.SWITCH, + name: 'AdminTokenWithdrawFees', + }, + { + label: 'Admin Perp Withdraw Fees', + initialValue: form.AdminPerpWithdrawFees, + type: InstructionInputType.SWITCH, + name: 'AdminPerpWithdrawFees', + }, + { + label: 'Account Size Migration', + initialValue: form.AccountSizeMigration, + type: InstructionInputType.SWITCH, + name: 'AccountSizeMigration', + }, + { + label: 'Token Conditional Swap Start', + initialValue: form.TokenConditionalSwapStart, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapStart', + }, + { + label: 'Token Conditional Swap Create Premium Auction', + initialValue: form.TokenConditionalSwapCreatePremiumAuction, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapCreatePremiumAuction', + }, + { + label: 'Token Conditional Swap Create Linear Auction', + initialValue: form.TokenConditionalSwapCreateLinearAuction, + type: InstructionInputType.SWITCH, + name: 'TokenConditionalSwapCreateLinearAuction', + }, + { + label: 'Serum 3 Place Order V2', + initialValue: form.Serum3PlaceOrderV2, + type: InstructionInputType.SWITCH, + name: 'Serum3PlaceOrderV2', + }, + { + label: 'Token Force withdraw', + initialValue: form.TokenForceWithdraw, + type: InstructionInputType.SWITCH, + name: 'TokenForceWithdraw', + }, + ] + + return ( + <> + + {form && ( + + )} + + ) +} + +export default IxGateSet diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/OpenBookEditMarket.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/OpenBookEditMarket.tsx index 6295d02792..086156199c 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/OpenBookEditMarket.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/OpenBookEditMarket.tsx @@ -17,6 +17,8 @@ import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import ForwarderProgram, { useForwarderProgramHelpers, } from '@components/ForwarderProgram/ForwarderProgram' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' type NameMarketIndexVal = { name: string @@ -41,7 +43,11 @@ const OpenBookEditMarket = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const forwarderProgramHelpers = useForwarderProgramHelpers() const solAccounts = assetAccounts.filter( @@ -142,7 +148,7 @@ const OpenBookEditMarket = ({ ) setForm((prevForm) => ({ ...prevForm, - oraclePriceBand: 0, + oraclePriceBand: Number(market?.oraclePriceBand) || 0, reduceOnly: market?.reduceOnly || false, forceClose: market?.forceClose || false, name: market?.name || '', @@ -176,6 +182,13 @@ const OpenBookEditMarket = ({ inputType: 'number', name: 'holdupTime', }, + { + label: 'Price band', + initialValue: form.oraclePriceBand, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'oraclePriceBand', + }, { label: 'Market', name: 'market', @@ -206,6 +219,9 @@ const OpenBookEditMarket = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const forwarderProgramHelpers = useForwarderProgramHelpers() const solAccounts = assetAccounts.filter( @@ -231,6 +237,9 @@ const OpenBookRegisterMarket = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -516,6 +522,9 @@ const PerpCreate = ({ ] return ( <> + {form && ( | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup?.admin) + ) + const connection = useLegacyConnectionContext() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + oracleConfFilter: 0.1, + maxStalenessSlots: '', + oraclePk: '', + name: '', + perpMarketIndex: 0, + baseDecimals: 6, + quoteLotSize: 10, + baseLotSize: 100, + maintBaseAssetWeight: 0.975, + initBaseAssetWeight: 0.95, + maintBaseLiabWeight: 1.025, + initBaseLiabWeight: 1.05, + maintOverallAssetWeight: 1, + initOverallAssetWeight: 1, + baseLiquidationFee: 0.0125, + makerFee: -0.0001, + takerFee: 0.0004, + feePenalty: 5, + minFunding: -0.05, + maxFunding: 0.05, + impactQuantity: 100, + groupInsuranceFund: true, + settleFeeFlat: 1000, + settleFeeAmountThreshold: 1000000, + settleFeeFractionLowHealth: 0.01, + settleTokenIndex: 0, + settlePnlLimitFactor: 1.0, + settlePnlLimitWindowSize: 60 * 60, + positivePnlLiquidationFee: 0, + holdupTime: 0, + platformLiquidationFee: 0, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + const forwarderProgramHelpers = useForwarderProgramHelpers() + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + let prerequisiteInstructions: TransactionInstruction[] = [] + let prerequisiteInstructionsSigners: Keypair[] = [] + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const bids = new Keypair() + const asks = new Keypair() + const eventQueue = new Keypair() + + const bookSideSize = mangoClient!.program.coder.accounts.size( + (mangoClient!.program.account.bookSide as any)._idlAccount + ) + const eventQueueSize = mangoClient!.program.coder.accounts.size( + (mangoClient!.program.account.eventQueue as any)._idlAccount + ) + prerequisiteInstructionsSigners = [bids, asks, eventQueue] + prerequisiteInstructions = [ + SystemProgram.createAccount({ + programId: mangoClient!.program.programId, + space: bookSideSize, + lamports: await connection.current.getMinimumBalanceForRentExemption( + bookSideSize + ), + fromPubkey: wallet.publicKey, + newAccountPubkey: bids.publicKey, + }), + SystemProgram.createAccount({ + programId: mangoClient!.program.programId, + space: bookSideSize, + lamports: await connection.current.getMinimumBalanceForRentExemption( + bookSideSize + ), + fromPubkey: wallet.publicKey, + newAccountPubkey: asks.publicKey, + }), + SystemProgram.createAccount({ + programId: mangoClient!.program.programId, + space: eventQueueSize, + lamports: await connection.current.getMinimumBalanceForRentExemption( + eventQueueSize + ), + fromPubkey: wallet.publicKey, + newAccountPubkey: eventQueue.publicKey, + }), + ] + const ix = await mangoClient!.program.methods + .perpCreateMarket( + Number(form.perpMarketIndex), + form.name, + { + confFilter: Number(form.oracleConfFilter), + maxStalenessSlots: + form.maxStalenessSlots !== '' + ? Number(form.maxStalenessSlots) + : null, + }, + Number(form.baseDecimals), + new BN(form.quoteLotSize), + new BN(form.baseLotSize), + Number(form.maintBaseAssetWeight), + Number(form.initBaseAssetWeight), + Number(form.maintBaseLiabWeight), + Number(form.initBaseLiabWeight), + Number(form.maintOverallAssetWeight), + Number(form.initOverallAssetWeight), + Number(form.baseLiquidationFee), + Number(form.makerFee), + Number(form.takerFee), + Number(form.minFunding), + Number(form.maxFunding), + new BN(form.impactQuantity), + form.groupInsuranceFund, + Number(form.feePenalty), + Number(form.settleFeeFlat), + Number(form.settleFeeAmountThreshold), + Number(form.settleFeeFractionLowHealth), + Number(form.settleTokenIndex), + Number(form.settlePnlLimitFactor), + new BN(form.settlePnlLimitWindowSize), + Number(form.positivePnlLiquidationFee), + Number(form.platformLiquidationFee) + ) + .accounts({ + group: mangoGroup!.publicKey, + admin: form.governedAccount.extensions.transferAddress, + oracle: new PublicKey(form.oraclePk), + bids: bids.publicKey, + asks: asks.publicKey, + eventQueue: eventQueue.publicKey, + payer: form.governedAccount.extensions.transferAddress, + }) + .signers([bids, asks, eventQueue]) + .instruction() + + serializedInstruction = serializeInstructionToBase64( + forwarderProgramHelpers.withForwarderWrapper(ix) + ) + } + const obj: UiInstruction = { + prerequisiteInstructions: prerequisiteInstructions, + prerequisiteInstructionsSigners: prerequisiteInstructionsSigners, + serializedInstruction: serializedInstruction, + isValid, + chunkBy: 1, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [ + form, + forwarderProgramHelpers.form, + forwarderProgramHelpers.withForwarderWrapper, + ]) + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + name: yup.string().required(), + perpMarketIndex: yup.string().required(), + oraclePk: yup + .string() + .required() + .test('is-valid-address', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + }) + + useEffect(() => { + const perpMarketIndex = + !mangoGroup || mangoGroup?.perpMarketsMapByMarketIndex.size === 0 + ? 0 + : Math.max(...[...mangoGroup!.perpMarketsMapByMarketIndex.keys()]) + 1 + setForm((prevForm) => ({ + ...prevForm, + perpMarketIndex: perpMarketIndex, + })) + }, [mangoGroup]) + + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: 'Perp Name', + initialValue: form.name, + type: InstructionInputType.INPUT, + name: 'name', + }, + { + label: `Perp Market Index`, + initialValue: form.perpMarketIndex, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'perpMarketIndex', + }, + { + label: 'Oracle PublicKey', + initialValue: form.oraclePk, + type: InstructionInputType.INPUT, + name: 'oraclePk', + }, + { + label: `Oracle Confidence Filter`, + subtitle: getAdditionalLabelInfo('confFilter'), + initialValue: form.oracleConfFilter, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'oracleConfFilter', + }, + + { + label: `Max Staleness Slots`, + subtitle: getAdditionalLabelInfo('maxStalenessSlots'), + initialValue: form.maxStalenessSlots, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxStalenessSlots', + }, + { + label: 'Base Decimals', + initialValue: form.baseDecimals, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'baseDecimals', + }, + { + label: `Quote Lot Size`, + subtitle: getAdditionalLabelInfo('quoteLotSize'), + initialValue: form.quoteLotSize, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'quoteLotSize', + }, + { + label: `Base Lot Size`, + subtitle: getAdditionalLabelInfo('baseLotSize'), + initialValue: form.baseLotSize, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'baseLotSize', + }, + { + label: `Maintenance Base Asset Weight`, + subtitle: getAdditionalLabelInfo('maintBaseAssetWeight'), + initialValue: form.maintBaseAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintBaseAssetWeight', + }, + { + label: `Init Base Asset Weight`, + subtitle: getAdditionalLabelInfo('initBaseAssetWeight'), + initialValue: form.initBaseAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initBaseAssetWeight', + }, + { + label: `Maintenance Base Liab Weight`, + subtitle: getAdditionalLabelInfo('maintBaseLiabWeight'), + initialValue: form.maintBaseLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintBaseLiabWeight', + }, + { + label: `Init Base Liab Weight`, + subtitle: getAdditionalLabelInfo('initBaseLiabWeight'), + initialValue: form.initBaseLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initBaseLiabWeight', + }, + { + label: `Maint Overall Asset Weight`, + subtitle: getAdditionalLabelInfo('maintOverallAssetWeight'), + initialValue: form.maintOverallAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintOverallAssetWeight', + }, + { + label: `Init Overall Asset Weight`, + subtitle: getAdditionalLabelInfo('initOverallAssetWeight'), + initialValue: form.initOverallAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initOverallAssetWeight', + }, + { + label: `Base Liquidation Fee`, + subtitle: getAdditionalLabelInfo('baseLiquidationFee'), + initialValue: form.baseLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'baseLiquidationFee', + }, + { + label: `Maker Fee`, + subtitle: getAdditionalLabelInfo('makerFee'), + initialValue: form.makerFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'makerFee', + }, + { + label: `Taker Fee`, + subtitle: getAdditionalLabelInfo('takerFee'), + initialValue: form.takerFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'takerFee', + }, + { + label: `Fee Penalty`, + subtitle: getAdditionalLabelInfo('feePenalty'), + initialValue: form.feePenalty, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'feePenalty', + }, + { + label: `Group Insurance Fund`, + subtitle: getAdditionalLabelInfo('groupInsuranceFund'), + initialValue: form.groupInsuranceFund, + type: InstructionInputType.SWITCH, + name: 'groupInsuranceFund', + }, + { + label: `Settle Fee Flat`, + subtitle: getAdditionalLabelInfo('settleFeeFlat'), + initialValue: form.settleFeeFlat, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeFlat', + }, + { + label: `Settle Fee Amount Threshold`, + subtitle: getAdditionalLabelInfo('settleFeeAmountThreshold'), + initialValue: form.settleFeeAmountThreshold, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeAmountThreshold', + }, + { + label: `Settle Fee Fraction Low Health`, + subtitle: getAdditionalLabelInfo('settleFeeFractionLowHealth'), + initialValue: form.settleFeeFractionLowHealth, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeFractionLowHealth', + }, + { + label: `Settle Token Index`, + subtitle: getAdditionalLabelInfo('settleTokenIndex'), + initialValue: form.settleTokenIndex, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleTokenIndex', + }, + { + label: `Settle Pnl Limit Factor`, + subtitle: getAdditionalLabelInfo('settlePnlLimitFactor'), + initialValue: form.settlePnlLimitFactor, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settlePnlLimitFactor', + }, + { + label: `Settle Pnl Limit Window Size`, + subtitle: getAdditionalLabelInfo('settlePnlLimitWindowSize'), + initialValue: form.settlePnlLimitWindowSize, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settlePnlLimitWindowSize', + }, + { + label: `Min Funding`, + subtitle: getAdditionalLabelInfo('minFunding'), + initialValue: form.minFunding, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'minFunding', + }, + { + label: `Max Funding`, + subtitle: getAdditionalLabelInfo('maxFunding'), + initialValue: form.maxFunding, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxFunding', + }, + { + label: `Impact Quantity`, + subtitle: getAdditionalLabelInfo('impactQuantity'), + initialValue: form.impactQuantity, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'impactQuantity', + }, + { + label: `Positive Pnl Liquidation Fee`, + subtitle: getAdditionalLabelInfo('positivePnlLiquidationFee'), + initialValue: form.positivePnlLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'positivePnlLiquidationFee', + }, + { + label: `Platform Liquidation Fee`, + subtitle: getAdditionalLabelInfo('platformLiquidationFee'), + initialValue: form.platformLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'platformLiquidationFee', + }, + ] + return ( + <> + + {form && ( + + )} + + + ) +} + +export default PerpCreate diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/PerpEdit.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/PerpEdit.tsx index dbab5d8230..cbfc2632e1 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/PerpEdit.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/PerpEdit.tsx @@ -22,6 +22,8 @@ import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import ForwarderProgram, { useForwarderProgramHelpers, } from '@components/ForwarderProgram/ForwarderProgram' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' const keyToLabel = { oraclePk: 'Oracle', @@ -144,7 +146,11 @@ const PerpEdit = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const [perps, setPerps] = useState([]) const [forcedValues, setForcedValues] = useState([]) @@ -305,7 +311,11 @@ const PerpEdit = ({ }, [mangoGroup]) useEffect(() => { - if (form.perp && mangoGroup) { + if ( + form.perp && + mangoGroup && + mangoGroup!.perpMarketsMapByMarketIndex.get(form.perp.value) + ) { const currentPerp = mangoGroup!.perpMarketsMapByMarketIndex.get( form.perp.value )! @@ -618,6 +628,9 @@ const PerpEdit = ({ ] return ( <> + {form && ( <> | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const [perps, setPerps] = useState([]) + const [forcedValues, setForcedValues] = useState([]) + const forwarderProgramHelpers = useForwarderProgramHelpers() + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + ((mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup.admin)) || + (mangoGroup?.securityAdmin && + x.extensions.transferAddress?.equals(mangoGroup.securityAdmin))) + ) + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ ...defaultFormValues }) + const [originalFormValues, setOriginalFormValues] = useState({ + ...defaultFormValues, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const perpMarket = mangoGroup!.perpMarketsMapByMarketIndex.get( + form.perp!.value + )! + const values = getChangedValues( + originalFormValues, + form, + forcedValues + ) + + const oracleConfFilter = + (form.oracleConfFilter as number | string) === '' + ? null + : form.oracleConfFilter + const maxStalenessSlots = + (form.maxStalenessSlots as number | string) === '' + ? null + : form.maxStalenessSlots + + const isThereNeedOfSendingOracleConfig = + originalFormValues.oracleConfFilter !== oracleConfFilter || + originalFormValues.maxStalenessSlots !== maxStalenessSlots + //Mango instruction call and serialize + const ix = await mangoClient!.program.methods + .perpEditMarket( + getNullOrTransform(values.oraclePk, PublicKey), + isThereNeedOfSendingOracleConfig + ? { + confFilter: Number(form.oracleConfFilter), + maxStalenessSlots: maxStalenessSlots, + } + : null, + getNullOrTransform(values.baseDecimals, null, Number), + getNullOrTransform(values.maintBaseAssetWeight, null, Number), + getNullOrTransform(values.initBaseAssetWeight, null, Number), + getNullOrTransform(values.maintBaseLiabWeight, null, Number), + getNullOrTransform(values.initBaseLiabWeight, null, Number), + getNullOrTransform(values.maintOverallAssetWeight, null, Number), + getNullOrTransform(values.initOverallAssetWeight, null, Number), + getNullOrTransform(values.baseLiquidationFee, null, Number), + getNullOrTransform(values.makerFee, null, Number), + getNullOrTransform(values.takerFee, null, Number), + getNullOrTransform(values.minFunding, null, Number), + getNullOrTransform(values.maxFunding, null, Number), + getNullOrTransform(values.impactQuantity, BN), + values.groupInsuranceFund!, + getNullOrTransform(values.feePenalty, null, Number), + getNullOrTransform(values.settleFeeFlat, null, Number), + getNullOrTransform(values.settleFeeAmountThreshold, null, Number), + getNullOrTransform(values.settleFeeFractionLowHealth, null, Number), + getNullOrTransform( + values.stablePriceDelayIntervalSeconds, + null, + Number + ), + getNullOrTransform(values.stablePriceDelayGrowthLimit, null, Number), + getNullOrTransform(values.stablePriceGrowthLimit, null, Number), + getNullOrTransform(values.settlePnlLimitFactor, null, Number), + getNullOrTransform(values.settlePnlLimitWindowSize, BN), + values.reduceOnly!, + values.resetStablePrice!, + getNullOrTransform(values.positivePnlLiquidationFee, null, Number), + getNullOrTransform(values.name, null, String), + values.forceClose!, + getNullOrTransform(values.platformLiquidationFee, null, Number) + ) + .accounts({ + group: mangoGroup!.publicKey, + admin: form.governedAccount.extensions.transferAddress, + perpMarket: perpMarket.publicKey, + oracle: + getNullOrTransform(values.oraclePk, PublicKey) || perpMarket.oracle, + }) + .instruction() + + serializedInstruction = serializeInstructionToBase64( + forwarderProgramHelpers.withForwarderWrapper(ix) + ) + } + const obj: UiInstruction = { + serializedInstruction: serializedInstruction, + isValid, + chunkBy: 1, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [ + form, + forcedValues, + forwarderProgramHelpers.form, + forwarderProgramHelpers.withForwarderWrapper, + ]) + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + oraclePk: yup + .string() + .required() + .test('is-valid-address', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + }) + useEffect(() => { + const getTokens = async () => { + const currentTokens = [ + ...mangoGroup!.perpMarketsMapByMarketIndex.values(), + ].map((x) => ({ + name: x.name, + value: x.perpMarketIndex, + })) + setPerps(currentTokens) + } + if (mangoGroup) { + getTokens() + } + }, [mangoGroup]) + + useEffect(() => { + if ( + form.perp && + mangoGroup && + mangoGroup!.perpMarketsMapByMarketIndex.get(form.perp.value) + ) { + const currentPerp = mangoGroup!.perpMarketsMapByMarketIndex.get( + form.perp.value + )! + const vals = { + oraclePk: currentPerp.oracle.toBase58(), + name: currentPerp.name, + oracleConfFilter: currentPerp.oracleConfig.confFilter.toNumber(), + maxStalenessSlots: currentPerp.oracleConfig.maxStalenessSlots.toNumber(), + baseDecimals: currentPerp.baseDecimals, + maintBaseAssetWeight: currentPerp.maintBaseAssetWeight.toNumber(), + initBaseAssetWeight: currentPerp.initBaseAssetWeight.toNumber(), + maintBaseLiabWeight: currentPerp.maintBaseLiabWeight.toNumber(), + initBaseLiabWeight: currentPerp.initBaseLiabWeight.toNumber(), + maintOverallAssetWeight: currentPerp.maintOverallAssetWeight.toNumber(), + initOverallAssetWeight: currentPerp.initOverallAssetWeight.toNumber(), + liquidationFee: currentPerp.baseLiquidationFee.toNumber(), + makerFee: currentPerp.makerFee.toNumber(), + takerFee: currentPerp.takerFee.toNumber(), + feePenalty: currentPerp.feePenalty, + minFunding: currentPerp.minFunding.toNumber(), + maxFunding: currentPerp.maxFunding.toNumber(), + impactQuantity: currentPerp.impactQuantity.toNumber(), + groupInsuranceFund: currentPerp.groupInsuranceFund, + settleFeeFlat: currentPerp.settleFeeFlat, + settleFeeAmountThreshold: currentPerp.settleFeeAmountThreshold, + settleFeeFractionLowHealth: currentPerp.settleFeeFractionLowHealth, + stablePriceDelayIntervalSeconds: + currentPerp.stablePriceModel.delayIntervalSeconds, + stablePriceDelayGrowthLimit: + currentPerp.stablePriceModel.delayGrowthLimit, + stablePriceGrowthLimit: currentPerp.stablePriceModel.stableGrowthLimit, + settlePnlLimitFactor: currentPerp.settlePnlLimitFactor, + settlePnlLimitWindowSize: currentPerp.settlePnlLimitWindowSizeTs.toNumber(), + reduceOnly: currentPerp.reduceOnly, + resetStablePrice: false, + forceClose: currentPerp.forceClose, + positivePnlLiquidationFee: currentPerp.positivePnlLiquidationFee.toNumber(), + } + setForm((prevForm) => ({ + ...prevForm, + ...vals, + })) + setOriginalFormValues((prevForm) => ({ ...prevForm, ...vals })) + } + }, [form.perp, mangoGroup]) + + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: keyToLabel['perp'], + name: 'perp', + type: InstructionInputType.SELECT, + initialValue: form.perp, + options: perps, + }, + { + label: keyToLabel['name'], + initialValue: form.name, + type: InstructionInputType.INPUT, + name: 'name', + }, + { + label: keyToLabel['oraclePk'], + initialValue: form.oraclePk, + type: InstructionInputType.INPUT, + name: 'oraclePk', + }, + { + label: keyToLabel['oracleConfFilter'], + subtitle: getAdditionalLabelInfo('confFilter'), + initialValue: form.oracleConfFilter, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'oracleConfFilter', + }, + { + label: keyToLabel['maxStalenessSlots'], + subtitle: getAdditionalLabelInfo('maxStalenessSlots'), + initialValue: form.maxStalenessSlots, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxStalenessSlots', + }, + { + label: keyToLabel['baseDecimals'], + initialValue: form.baseDecimals, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'baseDecimals', + }, + { + label: keyToLabel['stablePriceDelayGrowthLimit'], + subtitle: getAdditionalLabelInfo('stablePriceDelayGrowthLimit'), + initialValue: form.stablePriceDelayGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayGrowthLimit', + }, + { + label: keyToLabel['stablePriceGrowthLimit'], + subtitle: getAdditionalLabelInfo('stablePriceGrowthLimit'), + initialValue: form.stablePriceGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceGrowthLimit', + }, + { + label: keyToLabel['maintBaseAssetWeight'], + subtitle: getAdditionalLabelInfo('maintBaseAssetWeight'), + initialValue: form.maintBaseAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintBaseAssetWeight', + }, + { + label: keyToLabel['initBaseAssetWeight'], + subtitle: getAdditionalLabelInfo('initBaseAssetWeight'), + initialValue: form.initBaseAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initBaseAssetWeight', + }, + { + label: keyToLabel['maintBaseLiabWeight'], + subtitle: getAdditionalLabelInfo('maintBaseLiabWeight'), + initialValue: form.maintBaseLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintBaseLiabWeight', + }, + { + label: keyToLabel['initBaseLiabWeight'], + subtitle: getAdditionalLabelInfo('initBaseLiabWeight'), + initialValue: form.initBaseLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initBaseLiabWeight', + }, + { + label: keyToLabel['maintOverallAssetWeight'], + subtitle: getAdditionalLabelInfo('maintOverallAssetWeight'), + initialValue: form.maintOverallAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintOverallAssetWeight', + }, + { + label: keyToLabel['initOverallAssetWeight'], + subtitle: getAdditionalLabelInfo('initOverallAssetWeight'), + initialValue: form.initOverallAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initOverallAssetWeight', + }, + { + label: keyToLabel['baseLiquidationFee'], + subtitle: getAdditionalLabelInfo('baseLiquidationFee'), + initialValue: form.baseLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'baseLiquidationFee', + }, + { + label: keyToLabel['makerFee'], + subtitle: getAdditionalLabelInfo('makerFee'), + initialValue: form.makerFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'makerFee', + }, + { + label: keyToLabel['takerFee'], + subtitle: getAdditionalLabelInfo('takerFee'), + initialValue: form.takerFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'takerFee', + }, + { + label: keyToLabel['feePenalty'], + subtitle: getAdditionalLabelInfo('feePenalty'), + initialValue: form.feePenalty, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'feePenalty', + }, + { + label: keyToLabel['settleFeeFlat'], + subtitle: getAdditionalLabelInfo('settleFeeFlat'), + initialValue: form.settleFeeFlat, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeFlat', + }, + { + label: keyToLabel['settleFeeAmountThreshold'], + subtitle: getAdditionalLabelInfo('settleFeeAmountThreshold'), + initialValue: form.settleFeeAmountThreshold, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeAmountThreshold', + }, + { + label: keyToLabel['settleFeeFractionLowHealth'], + subtitle: getAdditionalLabelInfo('settleFeeFractionLowHealth'), + initialValue: form.settleFeeFractionLowHealth, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settleFeeFractionLowHealth', + }, + { + label: keyToLabel['stablePriceDelayIntervalSeconds'], + subtitle: getAdditionalLabelInfo('stablePriceDelayIntervalSeconds'), + initialValue: form.stablePriceDelayIntervalSeconds, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayIntervalSeconds', + }, + { + label: keyToLabel['settlePnlLimitFactor'], + subtitle: getAdditionalLabelInfo('settlePnlLimitFactor'), + initialValue: form.settlePnlLimitFactor, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settlePnlLimitFactor', + }, + { + label: keyToLabel['settlePnlLimitWindowSize'], + subtitle: getAdditionalLabelInfo('settlePnlLimitWindowSize'), + initialValue: form.settlePnlLimitWindowSize, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'settlePnlLimitWindowSize', + }, + { + label: keyToLabel['minFunding'], + subtitle: getAdditionalLabelInfo('minFunding'), + initialValue: form.minFunding, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'minFunding', + }, + { + label: keyToLabel['maxFunding'], + subtitle: getAdditionalLabelInfo('maxFunding'), + initialValue: form.maxFunding, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxFunding', + }, + { + label: keyToLabel['impactQuantity'], + subtitle: getAdditionalLabelInfo('impactQuantity'), + initialValue: form.impactQuantity, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'impactQuantity', + }, + { + label: keyToLabel['positivePnlLiquidationFee'], + subtitle: getAdditionalLabelInfo('positivePnlLiquidationFee'), + initialValue: form.positivePnlLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'positivePnlLiquidationFee', + }, + { + label: keyToLabel['platformLiquidationFee'], + subtitle: getAdditionalLabelInfo('platformLiquidationFee'), + initialValue: form.platformLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'platformLiquidationFee', + }, + { + label: keyToLabel['groupInsuranceFund'], + subtitle: getAdditionalLabelInfo('groupInsuranceFund'), + initialValue: form.groupInsuranceFund, + type: InstructionInputType.SWITCH, + name: 'groupInsuranceFund', + }, + { + label: keyToLabel['reduceOnly'], + subtitle: getAdditionalLabelInfo('reduceOnly'), + initialValue: form.reduceOnly, + type: InstructionInputType.SWITCH, + name: 'reduceOnly', + }, + { + label: keyToLabel['resetStablePrice'], + subtitle: getAdditionalLabelInfo('resetStablePrice'), + initialValue: form.resetStablePrice, + type: InstructionInputType.SWITCH, + name: 'resetStablePrice', + }, + { + label: keyToLabel['forceClose'], + subtitle: getAdditionalLabelInfo('forceClose'), + initialValue: form.forceClose, + type: InstructionInputType.SWITCH, + name: 'forceClose', + }, + ] + return ( + <> + + {form && ( + <> + + +

Force values

+
+ {Object.keys(defaultFormValues) + .filter((x) => x !== 'governedAccount') + .filter((x) => x !== 'perp') + .filter((x) => x !== 'holdupTime') + .map((key) => ( +
+
{keyToLabel[key]}
+
+ x === key) ? true : false + } + onChange={(checked) => { + if (checked) { + setForcedValues([...forcedValues, key]) + } else { + setForcedValues([ + ...forcedValues.filter((x) => x !== key), + ]) + } + }} + /> +
+
+ ))} +
+
+ + + )} + + ) +} + +export default PerpEdit diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/StubOracleCreate.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/StubOracleCreate.tsx index 87a757705e..dd779713c4 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/StubOracleCreate.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/StubOracleCreate.tsx @@ -15,6 +15,8 @@ import { InstructionInputType } from '../../inputInstructionType' import UseMangoV4 from '../../../../../../../../hooks/useMangoV4' import { I80F48 } from '@blockworks-foundation/mango-v4' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' interface StubOracleCreateForm { governedAccount: AssetAccount | null @@ -31,7 +33,11 @@ const StubOracleCreate = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -139,6 +145,9 @@ const StubOracleCreate = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -136,6 +142,9 @@ const StubOracleSet = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoGroup, mangoClient } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -157,6 +163,9 @@ const TokenAddBank = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() - const connection = useLegacyConnectionContext() const forwarderProgramHelpers = useForwarderProgramHelpers() const solAccounts = assetAccounts.filter( @@ -134,7 +136,6 @@ const TokenRegister = ({ async function getInstruction(): Promise { const isValid = await validateInstruction() let serializedInstruction = '' - const additionalSerializedInstructions: string[] = [] if ( isValid && form.governedAccount?.governance?.account && @@ -193,27 +194,6 @@ const TokenRegister = ({ }) .instruction() - const rp = new ReferralProvider(connection.current) - - const tx = await rp.initializeReferralTokenAccount({ - payerPubKey: form.governedAccount.extensions.transferAddress!, - referralAccountPubKey: JUPITER_REFERRAL_PK, - mint: new PublicKey(form.mintPk), - }) - const isExistingAccount = await connection.current.getAccountInfo( - tx.referralTokenAccountPubKey - ) - - if (!isExistingAccount) { - additionalSerializedInstructions.push( - ...tx.tx.instructions.map((x) => - serializeInstructionToBase64( - forwarderProgramHelpers.withForwarderWrapper(x) - ) - ) - ) - } - serializedInstruction = serializeInstructionToBase64( forwarderProgramHelpers.withForwarderWrapper(ix) ) @@ -563,6 +543,9 @@ const TokenRegister = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const solAccounts = assetAccounts.filter( (x) => @@ -49,7 +52,7 @@ const TokenRegisterTrustless = ({ x.extensions.transferAddress?.equals(mangoGroup?.admin))) ) const forwarderProgramHelpers = useForwarderProgramHelpers() - const connection = useLegacyConnectionContext() + const shouldBeGoverned = !!(index !== 0 && governance) const [form, setForm] = useState({ governedAccount: null, @@ -89,27 +92,6 @@ const TokenRegisterTrustless = ({ }) .instruction() - const rp = new ReferralProvider(connection.current) - - const tx = await rp.initializeReferralTokenAccount({ - payerPubKey: form.governedAccount.extensions.transferAddress!, - referralAccountPubKey: JUPITER_REFERRAL_PK, - mint: new PublicKey(form.mintPk), - }) - const isExistingAccount = await connection.current.getAccountInfo( - tx.referralTokenAccountPubKey - ) - - if (!isExistingAccount) { - additionalSerializedInstructions.push( - ...tx.tx.instructions.map((x) => - serializeInstructionToBase64( - forwarderProgramHelpers.withForwarderWrapper(x) - ) - ) - ) - } - serializedInstruction = serializeInstructionToBase64( forwarderProgramHelpers.withForwarderWrapper(ix) ) @@ -213,6 +195,9 @@ const TokenRegisterTrustless = ({ return ( <> + {form && ( | null +}) => { + const wallet = useWalletOnePointOh() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getAdditionalLabelInfo } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const { assetAccounts } = useGovernanceAssets() + const forwarderProgramHelpers = useForwarderProgramHelpers() + + const solAccounts = assetAccounts.filter( + (x) => + x.type === AccountType.SOL && + mangoGroup?.admin && + x.extensions.transferAddress?.equals(mangoGroup?.admin) + ) + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + mintPk: '', + maxStalenessSlots: '', + oraclePk: '', + fallbackOracle: '', + oracleConfFilter: 0.1, + name: '', + adjustmentFactor: 0.004, // rate parameters are chosen to be the same for all high asset weight tokens, + util0: 0.7, + rate0: 0.1, + util1: 0.85, + rate1: 0.2, + maxRate: 2.0, + loanFeeRate: 0.005, + loanOriginationFeeRate: 0.0005, + maintAssetWeight: 1, + initAssetWeight: 1, + maintLiabWeight: 1, + initLiabWeight: 1, + liquidationFee: 0, + minVaultToDepositsRatio: 0.2, + netBorrowLimitWindowSizeTs: 24 * 60 * 60, + netBorrowLimitPerWindowQuote: toNative(1000000, 6).toNumber(), + tokenIndex: 0, + holdupTime: 0, + stablePriceDelayIntervalSeconds: 60 * 60, + stablePriceGrowthLimit: 0.0003, + stablePriceDelayGrowthLimit: 0.06, + tokenConditionalSwapTakerFeeRate: 0, + tokenConditionalSwapMakerFeeRate: 0, + flashLoanSwapFeeRate: 0, + reduceOnly: REDUCE_ONLY_OPTIONS[0], + borrowWeightScaleStartQuote: toNative(10000, 6).toNumber(), + depositWeightScaleStartQuote: toNative(10000, 6).toNumber(), + depositLimit: 0, + interestTargetUtilization: 0.5, + interestCurveScaling: 4, + insuranceFound: false, + zeroUtilRate: 0, + platformLiquidationFee: 0, + disableAssetLiquidation: false, + collateralFeePerDay: 0, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const validateInstruction = async (): Promise => { + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + async function getInstruction(): Promise { + const isValid = await validateInstruction() + let serializedInstruction = '' + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const ix = await mangoClient!.program.methods + .tokenRegister( + Number(form.tokenIndex), + form.name, + { + confFilter: Number(form.oracleConfFilter), + maxStalenessSlots: + form.maxStalenessSlots !== '' + ? Number(form.maxStalenessSlots) + : null, + }, + { + adjustmentFactor: Number(form.adjustmentFactor), + util0: Number(form.util0), + rate0: Number(form.rate0), + util1: Number(form.util1), + rate1: Number(form.rate1), + maxRate: Number(form.maxRate), + }, + Number(form.loanFeeRate), + Number(form.loanOriginationFeeRate), + Number(form.maintAssetWeight), + Number(form.initAssetWeight), + Number(form.maintLiabWeight), + Number(form.initLiabWeight), + Number(form.liquidationFee), + Number(form.stablePriceDelayIntervalSeconds), + Number(form.stablePriceDelayGrowthLimit), + Number(form.stablePriceGrowthLimit), + Number(form.minVaultToDepositsRatio), + new BN(form.netBorrowLimitWindowSizeTs), + new BN(form.netBorrowLimitPerWindowQuote), + Number(form.borrowWeightScaleStartQuote), + Number(form.depositWeightScaleStartQuote), + Number(form.reduceOnly.value), + Number(form.tokenConditionalSwapTakerFeeRate), + Number(form.tokenConditionalSwapMakerFeeRate), + Number(form.flashLoanSwapFeeRate), + Number(form.interestCurveScaling), + Number(form.interestTargetUtilization), + form.insuranceFound, + new BN(form.depositLimit), + Number(form.zeroUtilRate), + Number(form.platformLiquidationFee), + form.disableAssetLiquidation, + Number(form.collateralFeePerDay) + ) + .accounts({ + group: mangoGroup!.publicKey, + admin: form.governedAccount.extensions.transferAddress, + mint: new PublicKey(form.mintPk), + oracle: new PublicKey(form.oraclePk), + payer: form.governedAccount.extensions.transferAddress, + rent: SYSVAR_RENT_PUBKEY, + fallbackOracle: new PublicKey(form.fallbackOracle), + }) + .instruction() + + serializedInstruction = serializeInstructionToBase64( + forwarderProgramHelpers.withForwarderWrapper(ix) + ) + } + const obj: UiInstruction = { + serializedInstruction: serializedInstruction, + isValid, + chunkBy: 1, + governance: form.governedAccount?.governance, + customHoldUpTime: form.holdupTime, + } + return obj + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: form.governedAccount?.governance, getInstruction }, + index + ) + // eslint-disable-next-line react-hooks/exhaustive-deps -- TODO please fix, it can cause difficult bugs. You might wanna check out https://bobbyhadz.com/blog/react-hooks-exhaustive-deps for info. -@asktree + }, [ + form, + forwarderProgramHelpers.form, + forwarderProgramHelpers.withForwarderWrapper, + ]) + const schema = yup.object().shape({ + governedAccount: yup + .object() + .nullable() + .required('Program governed account is required'), + oraclePk: yup + .string() + .required() + .test('is-valid-address', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + mintPk: yup + .string() + .required() + .test('is-valid-address1', 'Please enter a valid PublicKey', (value) => + value ? validatePubkey(value) : true + ), + name: yup.string().required(), + tokenIndex: yup.string().required(), + }) + useEffect(() => { + const tokenIndex = + !mangoGroup || mangoGroup?.banksMapByTokenIndex.size === 0 + ? 0 + : Math.max(...[...mangoGroup!.banksMapByTokenIndex.keys()]) + 1 + setForm({ + ...form, + tokenIndex: tokenIndex, + }) + }, [mangoGroup?.banksMapByTokenIndex.size]) + + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: solAccounts, + }, + { + label: 'Instruction hold up time (days)', + initialValue: form.holdupTime, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'holdupTime', + }, + { + label: 'Mint PublicKey', + initialValue: form.mintPk, + type: InstructionInputType.INPUT, + name: 'mintPk', + }, + { + label: `Oracle PublicKey`, + initialValue: form.oraclePk, + type: InstructionInputType.INPUT, + name: 'oraclePk', + }, + { + label: `Fallback oracle`, + initialValue: form.fallbackOracle, + type: InstructionInputType.INPUT, + name: 'fallbackOracle', + }, + { + label: `Oracle Confidence Filter`, + subtitle: getAdditionalLabelInfo('confFilter'), + initialValue: form.oracleConfFilter, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'oracleConfFilter', + }, + { + label: `Max Staleness Slots`, + subtitle: getAdditionalLabelInfo('maxStalenessSlots'), + initialValue: form.maxStalenessSlots, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxStalenessSlots', + }, + { + label: 'Token Name', + initialValue: form.name, + type: InstructionInputType.INPUT, + name: 'name', + }, + { + label: `Token Index`, + initialValue: form.tokenIndex, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'tokenIndex', + }, + { + label: `Interest rate adjustment factor`, + subtitle: getAdditionalLabelInfo('adjustmentFactor'), + initialValue: form.adjustmentFactor, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'adjustmentFactor', + }, + { + label: `Interest rate utilization point 0`, + subtitle: getAdditionalLabelInfo('util0'), + initialValue: form.util0, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'util0', + }, + { + label: `Interest rate point 0`, + subtitle: getAdditionalLabelInfo('rate0'), + initialValue: form.rate0, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'rate0', + }, + { + label: `Interest rate utilization point 1`, + subtitle: getAdditionalLabelInfo('util1'), + initialValue: form.util1, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'util1', + }, + { + label: `Interest rate point 1`, + subtitle: getAdditionalLabelInfo('rate1'), + initialValue: form.rate1, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'rate1', + }, + { + label: `Interest rate max rate`, + subtitle: getAdditionalLabelInfo('maxRate'), + initialValue: form.maxRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maxRate', + }, + { + label: `Loan Fee Rate`, + subtitle: getAdditionalLabelInfo('loanFeeRate'), + initialValue: form.loanFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'loanFeeRate', + }, + { + label: `Loan Origination Fee Rate`, + subtitle: getAdditionalLabelInfo('loanOriginationFeeRate'), + initialValue: form.loanOriginationFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'loanOriginationFeeRate', + }, + { + label: 'Maintenance Asset Weight', + subtitle: getAdditionalLabelInfo('maintAssetWeight'), + initialValue: form.maintAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintAssetWeight', + }, + { + label: `Init Asset Weight`, + subtitle: getAdditionalLabelInfo('initAssetWeight'), + initialValue: form.initAssetWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initAssetWeight', + }, + { + label: `Maintenance Liab Weight`, + subtitle: getAdditionalLabelInfo('maintLiabWeight'), + initialValue: form.maintLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'maintLiabWeight', + }, + { + label: `Init Liab Weight`, + subtitle: getAdditionalLabelInfo('initLiabWeight'), + initialValue: form.initLiabWeight, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'initLiabWeight', + }, + { + label: `Liquidation Fee`, + subtitle: getAdditionalLabelInfo('liquidationFee'), + initialValue: form.liquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'liquidationFee', + }, + { + label: `Min Vault To Deposits Ratio`, + subtitle: getAdditionalLabelInfo('minVaultToDepositsRatio'), + initialValue: form.minVaultToDepositsRatio, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'minVaultToDepositsRatio', + }, + { + label: `Net Borrow Limit Window Size`, + subtitle: getAdditionalLabelInfo('netBorrowLimitWindowSizeTs'), + initialValue: form.netBorrowLimitWindowSizeTs, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'netBorrowLimitWindowSizeTs', + }, + { + label: `Net Borrow Limit Per Window Quote`, + subtitle: getAdditionalLabelInfo('netBorrowLimitPerWindowQuote'), + initialValue: form.netBorrowLimitPerWindowQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'netBorrowLimitPerWindowQuote', + }, + { + label: 'Reduce only', + subtitle: getAdditionalLabelInfo('reduceOnly'), + initialValue: form.reduceOnly, + type: InstructionInputType.SELECT, + options: REDUCE_ONLY_OPTIONS, + name: 'reduceOnly', + }, + { + label: `Stable Price Delay Interval Seconds`, + subtitle: getAdditionalLabelInfo('stablePriceDelayIntervalSeconds'), + initialValue: form.stablePriceDelayIntervalSeconds, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayIntervalSeconds', + }, + { + label: `Stable Price Growth Limit`, + subtitle: getAdditionalLabelInfo('stablePriceGrowthLimit'), + initialValue: form.stablePriceGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceGrowthLimit', + }, + { + label: `Stable Price Delay Growth Limit`, + subtitle: getAdditionalLabelInfo('stablePriceDelayGrowthLimit'), + initialValue: form.stablePriceDelayGrowthLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'stablePriceDelayGrowthLimit', + }, + { + label: `Token Conditional Swap Taker Fee Rate`, + subtitle: getAdditionalLabelInfo('tokenConditionalSwapTakerFeeRate'), + initialValue: form.tokenConditionalSwapTakerFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'tokenConditionalSwapTakerFeeRate', + }, + { + label: `Token Conditional Swap Maker Fee Rate`, + subtitle: getAdditionalLabelInfo('tokenConditionalSwapMakerFeeRate'), + initialValue: form.tokenConditionalSwapMakerFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'tokenConditionalSwapMakerFeeRate', + }, + { + label: `Flash Loan Deposit Fee Rate`, + subtitle: getAdditionalLabelInfo('flashLoanSwapFeeRate'), + initialValue: form.flashLoanSwapFeeRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'flashLoanSwapFeeRate', + }, + { + label: `Borrow Weight Scale Start Quote`, + subtitle: getAdditionalLabelInfo('borrowWeightScaleStartQuote'), + initialValue: form.borrowWeightScaleStartQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'borrowWeightScaleStartQuote', + }, + { + label: `Deposit Weight Scale Start Quote`, + subtitle: getAdditionalLabelInfo('depositWeightScaleStartQuote'), + initialValue: form.depositWeightScaleStartQuote, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'depositWeightScaleStartQuote', + }, + { + label: `Interest Curve Scaling`, + subtitle: getAdditionalLabelInfo('interestCurveScaling'), + initialValue: form.interestCurveScaling, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'interestCurveScaling', + }, + { + label: `Interest Target Utilization`, + subtitle: getAdditionalLabelInfo('interestTargetUtilization'), + initialValue: form.interestTargetUtilization, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'interestTargetUtilization', + }, + { + label: `Deposit Limit`, + subtitle: getAdditionalLabelInfo('depositLimit'), + initialValue: form.depositLimit, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'depositLimit', + }, + { + label: `Insurance Found`, + subtitle: getAdditionalLabelInfo('insuranceFound'), + initialValue: form.insuranceFound, + type: InstructionInputType.SWITCH, + name: 'insuranceFound', + }, + { + label: 'Zero Util Rate', + subtitle: getAdditionalLabelInfo('zeroUtilRate'), + initialValue: form.zeroUtilRate, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'zeroUtilRate', + }, + { + label: 'Platform Liquidation Fee', + subtitle: getAdditionalLabelInfo('platformLiquidationFee'), + initialValue: form.platformLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'platformLiquidationFee', + }, + { + label: 'Disable Asset Liquidation', + subtitle: getAdditionalLabelInfo('disableAssetLiquidation'), + initialValue: form.disableAssetLiquidation, + type: InstructionInputType.SWITCH, + name: 'disableAssetLiquidation', + }, + { + label: 'Collateral Fee Per Day', + subtitle: getAdditionalLabelInfo('collateralFeePerDay'), + initialValue: form.collateralFeePerDay, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'collateralFeePerDay', + }, + ] + + return ( + <> + + {form && ( + + )} + + + ) +} + +export default TokenRegister diff --git a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/WithdrawPerpFees.tsx b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/WithdrawPerpFees.tsx index c13bbd6572..bdf66ab0d4 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/WithdrawPerpFees.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Mango/MangoV4/WithdrawPerpFees.tsx @@ -21,6 +21,8 @@ import { import { TransactionInstruction } from '@solana/web3.js' import { useConnection } from '@solana/wallet-adapter-react' import { PerpMarketIndex } from '@blockworks-foundation/mango-v4' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' type NameMarketIndexVal = { name: string @@ -41,7 +43,11 @@ const WithdrawPerpFees = ({ governance: ProgramAccount | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const { connection } = useConnection() const solAccounts = assetAccounts.filter( @@ -185,6 +191,9 @@ const WithdrawPerpFees = ({ return ( <> + {form && ( | null }) => { const wallet = useWalletOnePointOh() - const { mangoClient, mangoGroup } = UseMangoV4() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { assetAccounts } = useGovernanceAssets() const { connection } = useConnection() const solAccounts = assetAccounts.filter( @@ -56,6 +63,7 @@ const AdminTokenWithdrawTokenFees = ({ governedAccount: null, token: null, holdupTime: 0, + withdrawFromAllBanks: false, }) const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) @@ -75,60 +83,64 @@ const AdminTokenWithdrawTokenFees = ({ form.governedAccount?.governance?.account && wallet?.publicKey ) { - const bank = mangoGroup!.banksMapByMint.get( - form.token!.value.toBase58() - )![0] - const ataAddress = await Token.getAssociatedTokenAddress( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - bank.mint, - form.governedAccount.extensions.transferAddress!, - true - ) + const banks = form.withdrawFromAllBanks + ? [...mangoGroup!.banksMapByMint.values()].map((x) => x[0]) + : [mangoGroup!.banksMapByMint.get(form.token!.value.toBase58())![0]] - const depositAccountInfo = await connection.getAccountInfo(ataAddress) - if (!depositAccountInfo) { - // generate the instruction for creating the ATA - prerequisiteInstructions.push( - Token.createAssociatedTokenAccountInstruction( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - bank.mint, - ataAddress, - form.governedAccount.extensions.transferAddress!, - wallet.publicKey - ) + for (const bank of banks) { + const ataAddress = await Token.getAssociatedTokenAddress( + ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + bank.mint, + form.governedAccount.extensions.transferAddress!, + true ) - } - const ix = await mangoClient!.program.methods - .adminTokenWithdrawFees() - .accounts({ - group: mangoGroup!.publicKey, - admin: form.governedAccount.extensions.transferAddress, - tokenProgram: TOKEN_PROGRAM_ID, - bank: bank.publicKey, - vault: bank.vault, - tokenAccount: ataAddress, - }) - .instruction() - - additionalSerializedInstructions.push(serializeInstructionToBase64(ix)) - - if (bank.mint.toBase58() === WSOL_MINT) { - additionalSerializedInstructions.push( - serializeInstructionToBase64( - Token.createCloseAccountInstruction( + const depositAccountInfo = await connection.getAccountInfo(ataAddress) + if (!depositAccountInfo) { + // generate the instruction for creating the ATA + prerequisiteInstructions.push( + Token.createAssociatedTokenAccountInstruction( + ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID, + bank.mint, ataAddress, form.governedAccount.extensions.transferAddress!, - form.governedAccount.extensions.transferAddress!, - [] + wallet.publicKey ) ) - ) + } + + const ix = await mangoClient!.program.methods + .adminTokenWithdrawFees() + .accounts({ + group: mangoGroup!.publicKey, + admin: form.governedAccount.extensions.transferAddress, + tokenProgram: TOKEN_PROGRAM_ID, + bank: bank.publicKey, + vault: bank.vault, + tokenAccount: ataAddress, + }) + .instruction() + + additionalSerializedInstructions.push(serializeInstructionToBase64(ix)) + + if (bank.mint.toBase58() === WSOL_MINT) { + additionalSerializedInstructions.push( + serializeInstructionToBase64( + Token.createCloseAccountInstruction( + TOKEN_PROGRAM_ID, + ataAddress, + form.governedAccount.extensions.transferAddress!, + form.governedAccount.extensions.transferAddress!, + [] + ) + ) + ) + } } } + const obj: UiInstruction = { prerequisiteInstructions, serializedInstruction: serializedInstruction, @@ -136,6 +148,7 @@ const AdminTokenWithdrawTokenFees = ({ isValid, governance: form.governedAccount?.governance, customHoldUpTime: form.holdupTime, + chunkBy: 2, } return obj } @@ -192,10 +205,19 @@ const AdminTokenWithdrawTokenFees = ({ inputType: 'number', name: 'holdupTime', }, + { + label: 'Withdraw from all banks', + initialValue: form.withdrawFromAllBanks, + type: InstructionInputType.SWITCH, + name: 'withdrawFromAllBanks', + }, ] return ( <> + {form && ( { + const { result: realm } = await fetchRealmByPubkey(connection, realmPk) + if (realm === undefined) { + throw new Error('Realm not found') + } + +} */ -const DualVote = ({ +const DaoVote = ({ index, governance, }: { index: number governance: ProgramAccount | null }) => { - const [form, setForm] = useState({ - realm: 'EGYbpow8V9gt8JFmadFYai4sjfwc7Vc9gazU735hE6u7', - governanceProgram: 'GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw', + const [form, setForm] = useState({ proposal: '', voteOption: 'Yes', delegateToken: undefined, @@ -61,9 +74,6 @@ const DualVote = ({ const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) const { assetAccounts } = useGovernanceAssets() - const [governedAccount, setGovernedAccount] = useState< - ProgramAccount | undefined - >(undefined) const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) const handleSetForm = ({ propertyName, value }) => { @@ -89,6 +99,15 @@ const DualVote = ({ return isValid }, [form, schema]) + /* + const parsedProposalPk = tryParsePublicKey(form.proposal) + const { + data: proposalData, + isLoading: proposalLoading, + } = useProposalByPubkeyQuery(parsedProposalPk) +*/ + // TODO preview proposal title! + useEffect(() => { async function getInstruction(): Promise { const isValid = await validateInstruction() @@ -100,16 +119,39 @@ const DualVote = ({ form.delegateToken?.governance?.account && wallet?.publicKey ) { - const DUAL_MINT = new PublicKey( - 'DUALa4FC2yREwZ59PHeu1un4wis36vHRv5hWVBmzykCJ' + const proposalPk = new PublicKey(form.proposal) + + const { result: proposal } = await fetchProposalByPubkeyQuery( + connection.current, + proposalPk + ) + if (proposal === undefined) { + throw new Error('Proposal not found') + } + const { result: proposalGovernance } = await fetchGovernanceByPubkey( + connection.current, + proposal.account.governance + ) + if (proposalGovernance === undefined) { + throw new Error('Governance not found') + } + const realmPk = proposalGovernance.account.realm + const { result: realm } = await fetchRealmByPubkey( + connection.current, + realmPk ) - const programId = new PublicKey(form.governanceProgram) + if (realm === undefined) { + throw new Error('Realm not found') + } + const governingMint = proposal.account.governingTokenMint + + const programId = proposal.owner const walletPk = form.delegateToken.governance.nativeTreasuryAddress const payer = form.delegateToken.governance.nativeTreasuryAddress const tokenOwnerRecord = await getTokenOwnerRecordAddress( programId, - new PublicKey(form.realm), - DUAL_MINT, + realmPk, + governingMint, walletPk ) @@ -119,41 +161,53 @@ const DualVote = ({ new EmptyWallet(Keypair.generate()), options ) - const proposal = await getProposal( - connection.current, - new PublicKey(form.proposal) - ) - const vsrClient = await VsrClient.connect(provider, DEFAULT_VSR_ID) - // Explicitly request the version before making RPC calls to work around race conditions in resolving - // the version for RealmInfo - const programVersion = await fetchProgramVersion( + + const { result: realmConfig } = await fetchRealmConfigQuery( connection.current, - programId + realmPk ) + const votingPop = + governingMint.toString() === realm.account.communityMint.toString() + ? 'community' + : 'council' + const pluginPk = + votingPop === 'community' + ? realmConfig?.account.communityTokenConfig.voterWeightAddin + : realmConfig?.account.councilTokenConfig.voterWeightAddin + const pluginName = findPluginName(pluginPk) - const { registrar } = await getRegistrarPDA( - new PublicKey(form.realm), - DUAL_MINT, - DEFAULT_VSR_ID - ) - const { voter } = await getVoterPDA(registrar, walletPk, DEFAULT_VSR_ID) - const { voterWeightPk } = await getVoterWeightPDA( - registrar, - walletPk, - DEFAULT_VSR_ID - ) + // TODO this needs to just make a VotingClient and use it, for any plugin. + // But that code doesn't exist because right now everything is done in stupid hook. + // So currently only [vanilla and] VSR is supported + let voterWeightPk: PublicKey | undefined = undefined + if (pluginName === 'VSR') { + if (pluginPk === undefined) throw new Error('should be impossible') + const vsrClient = await VsrClient.connect(provider, pluginPk) + // Explicitly request the version before making RPC calls to work around race conditions in resolving + // the version for RealmInfo - const updateVoterWeightRecordIx = await vsrClient!.program.methods - .updateVoterWeightRecord() - .accounts({ - registrar, - voter, - voterWeightRecord: voterWeightPk, - systemProgram: SYSTEM_PROGRAM_ID, - }) - .instruction() + const { registrar } = await getRegistrarPDA( + realmPk, + governingMint, + pluginPk + ) + const { voter } = await getVoterPDA(registrar, walletPk, pluginPk) + voterWeightPk = ( + await getVoterWeightPDA(registrar, walletPk, pluginPk) + ).voterWeightPk - instructions.push(updateVoterWeightRecordIx) + const updateVoterWeightRecordIx = await vsrClient.program.methods + .updateVoterWeightRecord() + .accounts({ + registrar, + voter, + voterWeightRecord: voterWeightPk, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .instruction() + + instructions.push(updateVoterWeightRecordIx) + } const vote = form.voteOption === 'Yes' @@ -172,13 +226,18 @@ const DualVote = ({ veto: undefined, }) - const tokenMint = DUAL_MINT + const tokenMint = governingMint + + const programVersion = await fetchProgramVersion( + connection.current, + programId + ) await withCastVote( instructions, programId, programVersion, - new PublicKey(form.realm), + realmPk, proposal.account.governance, proposal.pubkey, proposal.account.tokenOwnerRecord, @@ -205,12 +264,11 @@ const DualVote = ({ return obj } handleSetInstructions( - { governedAccount: governedAccount, getInstruction }, + { governedAccount: form.delegateToken?.governance, getInstruction }, index ) }, [ form, - governedAccount, handleSetInstructions, index, connection, @@ -218,26 +276,10 @@ const DualVote = ({ validateInstruction, ]) - useEffect(() => { - setGovernedAccount(form.delegateToken?.governance) - }, [form.delegateToken]) - // TODO: Include this in the config instruction which can optionally be done // if the project doesnt need to change where the tokens get returned to. return ( <> - - handleSetForm({ - value: evt.target.value, - propertyName: 'realm', - }) - } - error={formErrors['realm']} - /> { [Instructions.Base64]: CustomBase64, [Instructions.None]: Empty, [Instructions.MangoV4TokenRegister]: TokenRegister, + [Instructions.MangoV4TokenRegisterV23]: TokenRegisterV23, [Instructions.MangoV4TokenEdit]: EditToken, + [Instructions.MangoV4TokenEditV23]: EditTokenV23, [Instructions.MangoV4GroupEdit]: GroupEdit, + [Instructions.MangoV4GroupEditV23]: GroupEditV23, [Instructions.MangoV4AdminWithdrawTokenFees]: AdminTokenWithdrawFees, [Instructions.MangoV4WithdrawPerpFees]: WithdrawPerpFees, [Instructions.IdlSetBuffer]: IdlSetBuffer, [Instructions.MangoV4OpenBookEditMarket]: OpenBookEditMarket, [Instructions.MangoV4IxGateSet]: IxGateSet, + [Instructions.MangoV4IxGateSetV23]: IxGateSetV23, [Instructions.MangoV4AltExtend]: AltExtend, [Instructions.MangoV4AltSet]: AltSet, [Instructions.MangoV4StubOracleCreate]: StubOracleCreate, [Instructions.MangoV4StubOracleSet]: StubOracleSet, [Instructions.MangoV4PerpEdit]: PerpEdit, + [Instructions.MangoV4PerpEditV23]: PerpEditV23, [Instructions.MangoV4OpenBookRegisterMarket]: OpenBookRegisterMarket, [Instructions.MangoV4PerpCreate]: PerpCreate, + [Instructions.MangoV4PerpCreateV23]: PerpCreateV23, [Instructions.MangoV4TokenRegisterTrustless]: TokenRegisterTrustless, [Instructions.MangoV4TokenAddBank]: TokenAddBank, [Instructions.Grant]: Grant, @@ -494,7 +506,7 @@ const New = () => { [Instructions.DualFinanceDelegate]: DualDelegate, [Instructions.DualFinanceDelegateWithdraw]: DualVoteDepositWithdraw, [Instructions.DualFinanceVoteDeposit]: DualVoteDeposit, - [Instructions.DualFinanceVote]: DualVote, + [Instructions.DaoVote]: DaoVote, [Instructions.DistributionCloseVaults]: CloseVaults, [Instructions.DistributionFillVaults]: FillVaults, [Instructions.MeanCreateAccount]: MeanCreateAccount, diff --git a/pages/realms/index.tsx b/pages/realms/index.tsx index 5f51d6da93..246d513594 100644 --- a/pages/realms/index.tsx +++ b/pages/realms/index.tsx @@ -12,7 +12,6 @@ import Button from '@components/Button' import { notify } from '@utils/notifications' import { useRouter } from 'next/router' import Input from '@components/inputs/Input' -import dynamic from 'next/dynamic' import { BsLayoutWtf, BsCheck } from 'react-icons/bs' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' @@ -20,8 +19,7 @@ import { PublicKey } from '@solana/web3.js' import { DEFAULT_GOVERNANCE_PROGRAM_ID } from '@components/instructions/tools' import { useRealmsByProgramQuery } from '@hooks/queries/realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' - -const RealmsDashboard = dynamic(() => import('./components/RealmsDashboard')) +import RealmsDashboard from './components/RealmsDashboard' const Realms = () => { const [realms, setRealms] = useState>([]) diff --git a/pages/realms/new/community-token/index.tsx b/pages/realms/new/community-token/index.tsx index fce23256e7..06b23dc2bb 100644 --- a/pages/realms/new/community-token/index.tsx +++ b/pages/realms/new/community-token/index.tsx @@ -72,7 +72,11 @@ const transformFormData2RealmCreation = (formData: CommunityTokenForm) => { formData.transferCommunityMintAuthority ?? true, // COUNCIL INFO createCouncil: formData.addCouncil ?? false, - + communityTokenConfig: new GoverningTokenConfigAccountArgs({ + tokenType: GoverningTokenType.Liquid, + voterWeightAddin: undefined, + maxVoterWeightAddin: undefined, + }), existingCouncilMintPk: formData.councilTokenMintAddress ? new PublicKey(formData.councilTokenMintAddress) : undefined, diff --git a/public/realms/BOHlogo.png b/public/realms/BOHlogo.png new file mode 100644 index 0000000000..f8feb8f741 Binary files /dev/null and b/public/realms/BOHlogo.png differ diff --git a/public/realms/Blockride/banner.png b/public/realms/Blockride/banner.png new file mode 100644 index 0000000000..ec8b2ba0f0 Binary files /dev/null and b/public/realms/Blockride/banner.png differ diff --git a/public/realms/Blockride/logo.png b/public/realms/Blockride/logo.png new file mode 100644 index 0000000000..01e6e1e45c Binary files /dev/null and b/public/realms/Blockride/logo.png differ diff --git a/public/realms/BoH b/public/realms/BoH new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/public/realms/BoH @@ -0,0 +1 @@ + diff --git a/public/realms/ConkDao/conk.png b/public/realms/ConkDao/conk.png new file mode 100644 index 0000000000..4c1826f43d Binary files /dev/null and b/public/realms/ConkDao/conk.png differ diff --git a/public/realms/ConkDao/conk_banner.png b/public/realms/ConkDao/conk_banner.png new file mode 100644 index 0000000000..d619846d4d Binary files /dev/null and b/public/realms/ConkDao/conk_banner.png differ diff --git a/public/realms/Deans-List-Solarplex-State/img/banner-deanslist-solarplex.png b/public/realms/Deans-List-Solarplex-State/img/banner-deanslist-solarplex.png new file mode 100644 index 0000000000..e5ed9605e6 Binary files /dev/null and b/public/realms/Deans-List-Solarplex-State/img/banner-deanslist-solarplex.png differ diff --git a/public/realms/Deans-List-Solarplex-State/img/deans_list_solarplex_state.png b/public/realms/Deans-List-Solarplex-State/img/deans_list_solarplex_state.png new file mode 100644 index 0000000000..077ad4c1a3 Binary files /dev/null and b/public/realms/Deans-List-Solarplex-State/img/deans_list_solarplex_state.png differ diff --git a/public/realms/GARI Network DAO/Gari discord (1).png b/public/realms/GARI Network DAO/Gari discord (1).png new file mode 100644 index 0000000000..4815d5da54 Binary files /dev/null and b/public/realms/GARI Network DAO/Gari discord (1).png differ diff --git a/public/realms/GARI Network DAO/gari.png b/public/realms/GARI Network DAO/gari.png new file mode 100644 index 0000000000..b6d30aa4e7 Binary files /dev/null and b/public/realms/GARI Network DAO/gari.png differ diff --git a/public/realms/MOUTAI/MF.png b/public/realms/MOUTAI/MF.png new file mode 100644 index 0000000000..ecf72c620c Binary files /dev/null and b/public/realms/MOUTAI/MF.png differ diff --git a/public/realms/MOUTAI/mdao.jpg b/public/realms/MOUTAI/mdao.jpg new file mode 100644 index 0000000000..adc3c21104 Binary files /dev/null and b/public/realms/MOUTAI/mdao.jpg differ diff --git a/public/realms/MOUTAI/t b/public/realms/MOUTAI/t new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/public/realms/MOUTAI/t @@ -0,0 +1 @@ + diff --git a/public/realms/MemeCoinDAOai/MemeCoinDAOBanner1_15.png b/public/realms/MemeCoinDAOai/MemeCoinDAOBanner1_15.png new file mode 100644 index 0000000000..c269797d18 Binary files /dev/null and b/public/realms/MemeCoinDAOai/MemeCoinDAOBanner1_15.png differ diff --git a/public/realms/MemeCoinDAOai/MemeCoinDAOFinalLogo.png b/public/realms/MemeCoinDAOai/MemeCoinDAOFinalLogo.png new file mode 100644 index 0000000000..8e1ff1b54d Binary files /dev/null and b/public/realms/MemeCoinDAOai/MemeCoinDAOFinalLogo.png differ diff --git a/public/realms/PAWN/img/pawn.png b/public/realms/PAWN/img/pawn.png new file mode 100644 index 0000000000..b3815c90f7 Binary files /dev/null and b/public/realms/PAWN/img/pawn.png differ diff --git a/public/realms/PAWN/img/pawns-banner.png b/public/realms/PAWN/img/pawns-banner.png new file mode 100644 index 0000000000..9a19f8ba8b Binary files /dev/null and b/public/realms/PAWN/img/pawns-banner.png differ diff --git a/public/realms/Solsaur/solsaur-realms-banner.png b/public/realms/Solsaur/solsaur-realms-banner.png new file mode 100644 index 0000000000..a6f7b7f3e8 Binary files /dev/null and b/public/realms/Solsaur/solsaur-realms-banner.png differ diff --git a/public/realms/Solsaur/solsaur.png b/public/realms/Solsaur/solsaur.png new file mode 100644 index 0000000000..1b74053e51 Binary files /dev/null and b/public/realms/Solsaur/solsaur.png differ diff --git a/public/realms/devnet.json b/public/realms/devnet.json index cf00d616e5..98dde2e720 100644 --- a/public/realms/devnet.json +++ b/public/realms/devnet.json @@ -254,5 +254,20 @@ "website": "https://helium.com", "twitter": "@Helium", "ogImage": "/realms/Helium/img/mobilelogo.png" + }, + { + "symbol": "$GARI", + "displayName": "GARI Network DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "HvDndGYjZNMVQDsrdAJJR7DtnQSB5rXM9BJBdwuxiXDg", + "ogImage": "/realms/GARI Network DAO/Coin.png", + "website": "https://gari.network/", + "twitter": "@TheGariNetwork" + }, + { + "symbol": "agrippa", + "displayName": "agrippa test dao", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "4tvK4JBdTcha81x5jL784sF1aECLbmLT3ScWDZRdz4cd" } -] \ No newline at end of file +] diff --git a/public/realms/mainnet-beta.json b/public/realms/mainnet-beta.json index 1925eefda2..3fd4db4fa2 100644 --- a/public/realms/mainnet-beta.json +++ b/public/realms/mainnet-beta.json @@ -25,6 +25,13 @@ "discord": "@grapedao", "shortDescription": "Frictionless is revolutionizing governance participation, bridging the gap between web2 and web3" }, + { + "symbol": "DED", + "displayName": "DED DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "735Kg6893iFH2KuGy6uJrVXYKwBi6ky3KLLNPmJ4TMCD", + "ogImage": "https://arweave.net/LzLM9GSor6FYeeFv5hv2a5oQuwcoyH3WFGbEq6_xGZk" + }, { "symbol": "GrapeUX", "displayName": "Grape UX", @@ -60,6 +67,17 @@ "github": "https://github.com/Deans-List/", "shortDescription": "A Service DAO turned Network State, consisting of Web3 power users providing feedback sessions. Join us in changing the future of work!" }, + { + "symbol": "Dean's List Solarplex State", + "displayName": "Dean's List Solarplex State", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "4U5tep3h2wFrLskrCJAemvFVyLwGvQ8Xbuc8dBEC6smF", + "bannerImage": "/realms/Deans-List-Solarplex-State/img/banner-deanslist-solarplex.png", + "twitter": "@deanslistDAO", + "ogImage": "/realms/Deans-List-Solarplex-State/img/deans_list_solarplex_state.png", + "github": "https://github.com/Deans-List/", + "shortDescription": "Dean's List Solarplex State oversees feedback incentives on Solarplex." + }, { "symbol": "Ukraine", "displayName": "Ukraine.SOL", @@ -181,7 +199,7 @@ "sortRank": 3, "website": "https://grapes.network/", "twitter": "@grapeprotocol", - "discord": "https://discord.com/invite/greatape", + "discord": "https://discord.com/invite/grapedao", "github": "https://github.com/Grape-Labs" }, { @@ -1442,20 +1460,6 @@ "discord": "https://discord.gg/uniquevcs", "github": "https://uniquevc.gitbook.io/unique-venture-clubs-docs/" }, - { - "symbol": "GARI Network", - "category": "web3", - "bannerImage": "https://i.imgur.com/VfFjhk5.jpeg", - "displayName": "GARI Network", - "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", - "realmId": "uWg5gaTsBnXc5qiVMB8XxBUPYqLAb5bzzgkkpxi6UAY", - "ogImage": "https://i.imgur.com/t5hzoBV.jpg", - "shortDescription": "GARI Network enables everyone to monetize their social media time and activities by leveraging web3 technologies.", - "sortRank": 3, - "website": "https://gari.network/", - "twitter": "@GariToken", - "discord": "https://discord.gg/garitoken" - }, { "symbol": "Dual DAO", "category": "defi", @@ -3227,6 +3231,19 @@ "twitter": "@hntdenver", "ogImage": "/realms/LavaDAO/img/lavalogo.png" }, + { + "symbol": "PAWN", + "displayName": "Pawn DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "shortDescription": "A Pawn in someone's experiment.", + "discord": "https://discord.gg/Td7QFn2ePz", + "bannerImage": "/realms/PAWN/img/pawns-banner.png", + "category": "Memecoin", + "sortRank": 3, + "realmId": "7rvjS4CgRYUZkSLJAXitmeQCybvfZcYcMjpVRhJ9mFHK", + "twitter": "@pawnspl24", + "ogImage": "/realms/PAWN/img/pawn.png" + }, { "symbol": "COMRADE", "displayName": "ComradeDAO", @@ -3343,5 +3360,100 @@ "bannerImage": "/realms/TrustBet/Bannerontransparent.png", "ogImage": "realms/TrustBet/tickerlogo.svg", "communityMint": "xpFbKJa92Ee1NSYEhc3b3BVk4im8YStXRaVW6EoW33w" + }, + { + "symbol": "BLR", + "displayName": "Blockride", + "category": "web3", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "A6ZS5ZdkyAbncb55fKjaUhBcQcovp8XcYT5AEQayv96y", + "bannerImage": "/realms/Blockride/banner.png", + "ogImage": "/realms/Blockride/logo.png", + "twitter": "@blockridenft", + "website": "https://blockride.xyz/", + "sortRank": 3, + "shortDescription": "BLOCKRIDE DAO - Building a modern approach to vehicle financing", + "keywords": "Web3, REALM, Governance, vehicle financing, DAO, Africans, Nigeria, RWA, Solana", + "github": "https://github.com/BlockrideNFT-org" + }, + { + "symbol": "RAAAWR", + "displayName": "Solsaur DAO", + "bannerImage": "/realms/Solsaur/solsaur-realms-banner.png", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "ANqmLV2hQNwFm3jyfqLEBa6KTksosr6uKzcdfg9X6ReR", + "ogImage": "/realms/Solsaur/solsaur.png", + "website": "https://www.solsaur.com", + "twitter": "@solsauras" + }, + { + "symbol": "Conk", + "displayName": "Conk Dao", + "category": "web3", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "A3jzUmuVqbyzqLgHtmMA2igUeACScRiSk71Hy27ehieo", + "bannerImage": "/realms/ConkDao/conk_banner.png", + "ogImage": "/realms/ConkDao/conk.png", + "twitter": "@Conk_Coin", + "website": "https://conkcoin.club", + "sortRank": 3, + "shortDescription": "Conk DAO - The People's Cat Coin", + "keywords": "Web3, REALM, Governance, Meme, DAO, Solana" + }, + { + "symbol": "MEMES", + "displayName": "MemeCoinDAOai", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "Ecar1VyamYnR2UzJzJbQMKR9Zq1U5p1xuUUsnzceDiaH", + "bannerImage": "/realms/MemeCoinDAOai/MemeCoinDAOBanner1_15.png", + "ogImage": "/realms/MemeCoinDAOai/MemeCoinDAOFinalLogo.png", + "website": "https://www.memecoindao.ai", + "twitter": "@MemeCoinDAOai" + }, + { + "symbol": "$GARI", + "displayName": "GARI Network DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "HvDndGYjZNMVQDsrdAJJR7DtnQSB5rXM9BJBdwuxiXDg", + "bannerImage": "https://media1.tenor.com/m/uKCFs6UJgCwAAAAC/gari-gari-token.gif", + "ogImage": "https://gari.network/wp-content/uploads/2023/12/gari-coin-1.png", + "website": "https://gari.network/", + "twitter": "@TheGariNetwork", + "category": "web3" + }, + { + "symbol": "BOHDAO", + "displayName": "Brigade of Honor Dao", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "FSh5XBFUYFMEWP99y4j7W6zERtEnqFVuwfuHgHgJJYWq", + "ogImage": "https://www.brigadeofhonor.com/BOHlogo.png", + "website": "https://www.brigadeofhonor.com/", + "twitter": "@BoHgamingguild" + }, + { + "symbol": "MF", + "displayName": "MOUTAI FUND", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "3JZmKT5xWKESXdC9aVpcv4so2DngpDHqzCm1pzwPU8Jc", + "ogImage": "/realms/MOUTAI/MF.png", + "website": "https://moutaifund.club/", + "twitter": "@MoutaiFund" + }, + { + "symbol": "MOUTAI", + "displayName": "MOUTAI DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "DgsXUhQbGuHxRNcSZJJdVXJcFCeMEFyDNeBYUDS9pHmC", + "ogImage": "/realms/MOUTAI/mdao.jpg", + "website": "https://www.moutaicoin.co/", + "twitter": "@Moutai_Sol" + }, + { + "symbol": "GARBAGE", + "displayName": "GARBAGE DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "GgF6fHb3iM3Um5DtvwbZvpGpYTzYnr1RmZr4NkwHveGp", + "website": "", + "twitter": "" } ] diff --git a/scripts/governance-notifier.ts b/scripts/governance-notifier.ts index 0ce55880af..dbfac98d5c 100644 --- a/scripts/governance-notifier.ts +++ b/scripts/governance-notifier.ts @@ -96,7 +96,11 @@ async function runNotifier() { votingTokenDecimals ) - const minVotesNeeded = 100000000 + const minVotesNeeded = + proposal.account.governance.toBase58() === + '7D6tGmaMyC8i73Q8X2Fec2S1Zb5rkyai6pctdMqHpHWT' + ? 50000000 + : 100000000 const quorumReached = yesVotes >= minVotesNeeded const isSuccess = yesVotes > noVotes && quorumReached diff --git a/stores/useVotePluginsClientStore.tsx b/stores/useVotePluginsClientStore.tsx index d22261a98d..0ad00e6953 100644 --- a/stores/useVotePluginsClientStore.tsx +++ b/stores/useVotePluginsClientStore.tsx @@ -242,12 +242,14 @@ const useVotePluginsClientStore = create( }, handleSetPythClient: async (wallet, connection) => { if (wallet) { - const pythClient = await PythClient.connect(connection.current, wallet as unknown as Wallet) - set((s) => { - s.state.pythClient = pythClient - }) + const pythClient = await PythClient.connect(connection.current, wallet as unknown as Wallet) + const maxVoterWeight = (await pythClient.program.methods.updateMaxVoterWeight().pubkeys()).maxVoterRecord + set((s) => { + s.state.pythClient = pythClient + s.state.maxVoterWeight = maxVoterWeight + }) } - }, + } }) ) diff --git a/tools/feeEstimate.ts b/tools/feeEstimate.ts new file mode 100644 index 0000000000..0c79d874f8 --- /dev/null +++ b/tools/feeEstimate.ts @@ -0,0 +1,55 @@ +import { + Connection, + PublicKey, + RecentPrioritizationFees, +} from '@solana/web3.js' +import { getClient, getGroupForClient } from '@utils/mangoV4Tools' +import { groupBy, mapValues, maxBy, sampleSize } from 'lodash' + +export const getFeeEstimate = async (connection: Connection) => { + const defaultFee = 5000 + try { + //Use mango client to find good fee + const MAINNET_MANGO_GROUP = new PublicKey( + '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' + ) + const MAX_PRIORITY_FEE_KEYS = 128 + const client = await getClient(connection) + const group = await getGroupForClient(client, MAINNET_MANGO_GROUP) + const feeMultiplier = 1.2 + const altResponse = await connection.getAddressLookupTable( + group.addressLookupTables[0] + ) + const altKeys = altResponse.value?.state.addresses + if (!altKeys) return defaultFee + + const addresses = sampleSize(altKeys, MAX_PRIORITY_FEE_KEYS) + const fees = await connection.getRecentPrioritizationFees({ + lockedWritableAccounts: addresses, + }) + + if (fees.length < 1) return defaultFee + + // get max priority fee per slot (and sort by slot from old to new) + const maxFeeBySlot = mapValues(groupBy(fees, 'slot'), (items) => + maxBy(items, 'prioritizationFee') + ) + const maximumFees = Object.values(maxFeeBySlot).sort( + (a, b) => a!.slot - b!.slot + ) as RecentPrioritizationFees[] + + // get median of last 20 fees + const recentFees = maximumFees.slice(Math.max(maximumFees.length - 20, 0)) + const mid = Math.floor(recentFees.length / 2) + const medianFee = + recentFees.length % 2 !== 0 + ? recentFees[mid].prioritizationFee + : (recentFees[mid - 1].prioritizationFee + + recentFees[mid].prioritizationFee) / + 2 + const feeEstimate = Math.ceil(medianFee * feeMultiplier) + return feeEstimate + } catch (e) { + return defaultFee + } +} diff --git a/tools/governance/prepareRealmCreation.ts b/tools/governance/prepareRealmCreation.ts index 0f4951d71b..806e31319b 100644 --- a/tools/governance/prepareRealmCreation.ts +++ b/tools/governance/prepareRealmCreation.ts @@ -68,7 +68,7 @@ interface RealmCreationV2 { transferCouncilMintAuthority: boolean councilWalletPks: PublicKey[] - communityTokenConfig?: GoverningTokenConfigAccountArgs + communityTokenConfig: GoverningTokenConfigAccountArgs skipRealmAuthority?: boolean } type RealmCreationV3 = { @@ -234,6 +234,7 @@ export async function prepareRealmCreation({ // there are incoming council members incomingCouncilMembers > 0) + console.log('Prepare realm - can community govern?', communityCanGovern) if ( !communityCanGovern && nftCollectionCount === 0 && // note this is not the most thorough check possible for nft realms diff --git a/utils/Mango/listingTools.ts b/utils/Mango/listingTools.ts index d623eff2f8..1762f12cae 100644 --- a/utils/Mango/listingTools.ts +++ b/utils/Mango/listingTools.ts @@ -9,11 +9,13 @@ import { toUiDecimalsForQuote, } from '@blockworks-foundation/mango-v4' import { + LISTING_PRESET, LISTING_PRESETS, - LISTING_PRESETS_KEYS, - LISTING_PRESETS_PYTH, - ListingPreset, - getTierWithAdjustedNetBorrows, + LISTING_PRESETS_KEY, + getPresetWithAdjustedNetBorrows, + getPresetWithAdjustedDepositLimit, + getPythPresets, + getSwitchBoardPresets, } from '@blockworks-foundation/mango-v4-settings/lib/helpers/listingTools' import { AnchorProvider, BN, Program, Wallet } from '@coral-xyz/anchor' import { MAINNET_USDC_MINT } from '@foresight-tmp/foresight-sdk/dist/consts' @@ -28,6 +30,7 @@ import { VersionedTransaction, } from '@solana/web3.js' import SwitchboardProgram from '@switchboard-xyz/sbv2-lite' +import { notify } from '@utils/notifications' import Big from 'big.js' import { secondsToHours } from 'date-fns' @@ -45,7 +48,7 @@ export type FlatListingArgs = { name: string tokenIndex: number 'oracleConfig.confFilter': number - 'oracleConfig.maxStalenessSlots': number + 'oracleConfig.maxStalenessSlots': number | null 'interestRateParams.util0': number 'interestRateParams.rate0': number 'interestRateParams.util1': number @@ -127,7 +130,7 @@ export type ListingArgsFormatted = { tokenIndex: number tokenName: string oracleConfidenceFilter: string - oracleMaxStalenessSlots: number + oracleMaxStalenessSlots: number | null interestRateUtilizationPoint1: string interestRateUtilizationPoint0: string interestRatePoint0: string @@ -151,7 +154,7 @@ export type ListingArgsFormatted = { stablePriceGrowthLimit: string tokenConditionalSwapMakerFeeRate: number tokenConditionalSwapTakerFeeRate: number - flashLoanSwapFeeRate: number + flashLoanSwapFeeRate: string reduceOnly: string oracle: string depositLimit: string @@ -169,10 +172,13 @@ export type EditTokenArgsFormatted = ListingArgsFormatted & { setFallbackOracle: boolean } -const transformPresetToProposed = (listingPreset: ListingPreset) => { +const transformPresetToProposed = (listingPreset: LISTING_PRESET) => { const proposedPreset: FormattedListingPreset = { ...listingPreset, - 'oracleConfig.maxStalenessSlots': listingPreset.maxStalenessSlots!, + 'oracleConfig.maxStalenessSlots': + listingPreset.maxStalenessSlots === -1 + ? null + : listingPreset.maxStalenessSlots!, 'oracleConfig.confFilter': listingPreset.oracleConfFilter, 'interestRateParams.adjustmentFactor': listingPreset.adjustmentFactor, 'interestRateParams.util0': listingPreset.util0, @@ -194,26 +200,40 @@ type FormattedListingPreset = Omit< > type ProposedListingPresets = { - [key in LISTING_PRESETS_KEYS]: FormattedListingPreset + [key in LISTING_PRESETS_KEY]: FormattedListingPreset } export const getFormattedListingPresets = ( isPythOracle: boolean, - currentTotalDepositsInUsdc?: number + uiDeposits?: number, + decimals?: number, + tokenPrice?: number ) => { - const PRESETS = isPythOracle ? LISTING_PRESETS_PYTH : LISTING_PRESETS + const PRESETS = !isPythOracle + ? getSwitchBoardPresets(LISTING_PRESETS) + : getPythPresets(LISTING_PRESETS) const PROPOSED_LISTING_PRESETS: ProposedListingPresets = Object.keys( PRESETS ).reduce((accumulator, key) => { - accumulator[key] = transformPresetToProposed( - !currentTotalDepositsInUsdc - ? PRESETS[key] - : getTierWithAdjustedNetBorrows( - PRESETS[key], - currentTotalDepositsInUsdc - ) - ) + let adjustedPreset = PRESETS[key] + if (uiDeposits && tokenPrice) { + adjustedPreset = getPresetWithAdjustedNetBorrows( + PRESETS[key], + uiDeposits, + tokenPrice, + toUiDecimals(PRESETS[key].netBorrowLimitPerWindowQuote, 6) + ) + } + + if (decimals && tokenPrice) { + adjustedPreset = getPresetWithAdjustedDepositLimit( + adjustedPreset, + tokenPrice, + decimals + ) + } + accumulator[key] = transformPresetToProposed(adjustedPreset) return accumulator }, {} as ProposedListingPresets) return PROPOSED_LISTING_PRESETS @@ -228,41 +248,41 @@ const fetchJupiterRoutes = async ( feeBps = 0 ) => { { - const paramsString = new URLSearchParams({ - inputMint: inputMint.toString(), - outputMint: outputMint.toString(), - amount: amount.toString(), - slippageBps: Math.ceil(slippage * 100).toString(), - feeBps: feeBps.toString(), - swapMode, - }).toString() - - const response = await fetch( - `https://quote-api.jup.ag/v4/quote?${paramsString}` - ) - - const res = await response.json() - const data = res.data - - return { - routes: res.data as RouteInfo[], - bestRoute: (data.length ? data[0] : null) as RouteInfo | null, + try { + const paramsString = new URLSearchParams({ + inputMint: inputMint.toString(), + outputMint: outputMint.toString(), + amount: amount.toString(), + slippageBps: Math.ceil(slippage * 100).toString(), + feeBps: feeBps.toString(), + swapMode, + }).toString() + + const response = await fetch( + `https://quote-api.jup.ag/v6/quote?${paramsString}` + ) + + const res = await response.json() + return { + bestRoute: (res ? res : null) as RouteInfo | null, + } + } catch (e) { + console.log(e) + return { + bestRoute: null, + } } } } -export const getSuggestedCoinTier = async ( +export const getSuggestedCoinPresetInfo = async ( outputMint: string, hasPythOracle: boolean ) => { try { - const TIERS: LISTING_PRESETS_KEYS[] = [ - 'ULTRA_PREMIUM', - 'PREMIUM', - 'MID', - 'MEME', - 'SHIT', - ] + const PRESETS = !hasPythOracle + ? getSwitchBoardPresets(LISTING_PRESETS) + : getPythPresets(LISTING_PRESETS) const swaps = await Promise.all([ fetchJupiterRoutes( @@ -280,6 +300,11 @@ export const getSuggestedCoinTier = async ( outputMint, toNative(20000, 6).toNumber() ), + fetchJupiterRoutes( + MAINNET_USDC_MINT.toBase58(), + outputMint, + toNative(10000, 6).toNumber() + ), fetchJupiterRoutes( MAINNET_USDC_MINT.toBase58(), outputMint, @@ -308,6 +333,12 @@ export const getSuggestedCoinTier = async ( toNative(20000, 6).toNumber(), 'ExactOut' ), + fetchJupiterRoutes( + MAINNET_USDC_MINT.toBase58(), + outputMint, + toNative(20000, 6).toNumber(), + 'ExactOut' + ), fetchJupiterRoutes( MAINNET_USDC_MINT.toBase58(), outputMint, @@ -329,13 +360,16 @@ export const getSuggestedCoinTier = async ( (acc: { amount: string; priceImpactPct: number }[], val) => { if (val.swapMode === 'ExactIn') { const exactOutRoute = bestRoutesSwaps.find( - (x) => x.amount === val.amount && x.swapMode === 'ExactOut' + (x) => x.outAmount === val.inAmount && x.swapMode === 'ExactOut' ) + acc.push({ - amount: val.amount.toString(), + amount: val.inAmount.toString(), priceImpactPct: exactOutRoute?.priceImpactPct - ? (val.priceImpactPct + exactOutRoute.priceImpactPct) / 2 - : val.priceImpactPct, + ? (Number(val.priceImpactPct) + + Number(exactOutRoute.priceImpactPct)) / + 2 + : Number(val.priceImpactPct), }) } return acc @@ -343,35 +377,32 @@ export const getSuggestedCoinTier = async ( [] ) - const indexForTierFromSwaps = averageSwaps.findIndex( + const indexForTargetAmount = averageSwaps.findIndex( (x) => x?.priceImpactPct && x?.priceImpactPct * 100 < 1 ) - const tier = - indexForTierFromSwaps > -1 ? TIERS[indexForTierFromSwaps] : 'SHIT' + const targetAmount = + indexForTargetAmount > -1 + ? toUiDecimals(new BN(averageSwaps[indexForTargetAmount].amount), 6) + : 0 - const tierLowerThenCurrent = - tier === 'ULTRA_PREMIUM' || tier === 'PREMIUM' - ? 'MID' - : tier === 'MID' - ? 'MEME' - : tier - const isPythRecommendedTier = - tier === 'MID' || tier === 'PREMIUM' || tier === 'ULTRA_PREMIUM' - const listingTier = - isPythRecommendedTier && !hasPythOracle ? tierLowerThenCurrent : tier + const preset: LISTING_PRESET = + Object.values(PRESETS).find( + (x) => x.preset_target_amount === targetAmount + ) || PRESETS.UNTRUSTED return { - tier: listingTier, - priceImpact: (indexForTierFromSwaps > -1 - ? averageSwaps[indexForTierFromSwaps]!.priceImpactPct + presetKey: preset.preset_key, + priceImpact: (indexForTargetAmount > -1 + ? averageSwaps[indexForTargetAmount]!.priceImpactPct : 100 ).toFixed(2), } } catch (e) { + console.log(e) return { - tier: 'SHIT', - priceImpact: 100, + presetKey: 'UNTRUSTED', + priceImpact: '100', } } } @@ -510,9 +541,6 @@ export const getBestMarket = async ({ if (!markets.length) { return undefined } - if (markets.length === 1) { - return markets[0].publicKey - } const marketsDataJsons = await Promise.all([ ...markets.map((x) => fetch(`/openSerumApi/market/${x.publicKey.toBase58()}`) @@ -521,12 +549,26 @@ export const getBestMarket = async ({ const marketsData = await Promise.all([ ...marketsDataJsons.map((x) => x.json()), ]) - const bestMarket = marketsData.sort((a, b) => b.volume24h - a.volume24h) - return bestMarket.length - ? new PublicKey(bestMarket[0].id) - : markets[0].publicKey + let error = '' + let sortedMarkets = marketsData.sort((a, b) => b.volume24h - a.volume24h) + let firstBestMarket = sortedMarkets[0] + + if (firstBestMarket.volume24h === 0) { + error = 'Openbook market had 0 volume in last 24h check it carefully' + } + sortedMarkets = sortedMarkets.sort( + (a, b) => b.quoteDepositsTotal - a.quoteDepositsTotal + ) + firstBestMarket = sortedMarkets[0] + + return sortedMarkets.length + ? { pubKey: new PublicKey(firstBestMarket.id), error: error } + : undefined } catch (e) { - return null + notify({ + message: 'Openbook market not found', + type: 'error', + }) } } @@ -678,7 +720,7 @@ export const getFormattedBankValues = (group: Group, bank: Bank) => { netBorrowLimitWindowSizeTs: secondsToHours( bank.netBorrowLimitWindowSizeTs.toNumber() ), - depositLimit: bank.depositLimit.toNumber(), + depositLimit: bank.depositLimit.toString(), interestTargetUtilization: bank.interestTargetUtilization, interestCurveScaling: bank.interestCurveScaling, reduceOnly: REDUCE_ONLY_OPTIONS[bank.reduceOnly].name, diff --git a/utils/instructions/Dual/delegate.ts b/utils/instructions/Dual/delegate.ts index f6555c4286..6c9d52e94b 100644 --- a/utils/instructions/Dual/delegate.ts +++ b/utils/instructions/Dual/delegate.ts @@ -40,6 +40,8 @@ import { import { getMintCfgIdx, tryGetVoter } from 'VoteStakeRegistry/sdk/api' import { getPeriod } from 'VoteStakeRegistry/tools/deposits' import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery' +import { fetchRealmByPubkey } from '@hooks/queries/realm' +import { determineVotingPowerType } from '@hooks/queries/governancePower' const govProgramId = new PublicKey( 'GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw' @@ -66,6 +68,7 @@ interface VoteDepositArgs { setFormErrors: any schema: any wallet: WalletAdapter | undefined + realmPk: PublicKey | undefined } export async function getDelegateInstruction({ @@ -123,8 +126,14 @@ export async function getVoteDepositInstruction({ form, schema, setFormErrors, + realmPk, }: VoteDepositArgs): Promise { - const isValid = await validateInstruction({ schema, form, setFormErrors }) + const isValid = + (await validateInstruction({ schema, form, setFormErrors })) && + realmPk !== undefined + if (!realmPk) { + setFormErrors({ realm: 'Realm not found' }) + } const serializedInstruction = '' const additionalSerializedInstructions: string[] = [] @@ -136,9 +145,25 @@ export async function getVoteDepositInstruction({ wallet?.publicKey && form.realm && form.delegateToken && - form.delegateToken.extensions.mint?.publicKey + form.delegateToken.extensions.mint?.publicKey && + realmPk ) { - const realmPk = new PublicKey(form.realm) + const { result: realm } = await fetchRealmByPubkey( + connection.current, + realmPk + ) + if (!realm) { + throw new Error('Realm not found') + } + const plugin = await determineVotingPowerType( + connection.current, + realmPk, + 'community' + ) + if (plugin !== 'VSR') { + throw new Error('this form currently only supports VSR') + } + const communityMintPk = form.delegateToken.extensions.mint?.publicKey const daoWallet = form.delegateToken.governance.nativeTreasuryAddress const amount = getMintNaturalAmountFromDecimalAsBN( @@ -148,10 +173,10 @@ export async function getVoteDepositInstruction({ const programVersion = await fetchProgramVersion( connection.current, - govProgramId // governance program public key + realm.owner // governance program public key ) const tokenOwnerRecordAddress = await getTokenOwnerRecordAddress( - govProgramId, + realm.owner, realmPk, form.delegateToken.extensions.mint.publicKey, daoWallet @@ -204,7 +229,7 @@ export async function getVoteDepositInstruction({ if (!isExisintgTokenOwnerRecord) { await withCreateTokenOwnerRecord( prerequisiteInstructions, - govProgramId, + realm.owner, programVersion, realmPk, daoWallet, diff --git a/utils/instructions/Dual/index.ts b/utils/instructions/Dual/index.ts index 1d46f5a42d..e23e641f57 100644 --- a/utils/instructions/Dual/index.ts +++ b/utils/instructions/Dual/index.ts @@ -141,7 +141,8 @@ export async function getConfigInstruction({ //owner is sol wallet or governance same as baseTokenAccount form.baseTreasury.extensions!.token!.account.owner, [], - form.numTokens + // @ts-ignore + form.numTokens as unknown as bigint ) ) ) @@ -332,7 +333,8 @@ export async function getConfigGsoInstruction({ //owner is sol wallet or governance same as baseTreasury form.baseTreasury.extensions!.token!.account.owner, [], - form.numTokens + // @ts-ignore + form.numTokens as unknown as bigint ) ) ) @@ -362,6 +364,7 @@ export async function getConfigGsoInstruction({ // Set all GSOs to have the same expiration and lockup period. This means // that users will be able to unstake at the same time as option expiration. const lockupPeriodEnd = form.optionExpirationUnixSeconds + const lockupMint = new PublicKey(form.lockupMint); const configInstruction = await gso.createConfigInstruction( optionsPerMillion, lockupPeriodEnd, @@ -371,6 +374,7 @@ export async function getConfigGsoInstruction({ form.soName, strikeAtomsPerLot, form.payer.extensions.transferAddress!, + lockupMint, baseMint, quoteMint, baseAccount, diff --git a/utils/instructions/NftVoter/castNftVote.ts b/utils/instructions/NftVoter/castNftVote.ts index 340a7e6dfe..178aa090af 100644 --- a/utils/instructions/NftVoter/castNftVote.ts +++ b/utils/instructions/NftVoter/castNftVote.ts @@ -12,7 +12,7 @@ import { PROGRAM_ID as ACCOUNT_COMPACTION_PROGRAM_ID } from '@solana/spl-account import { SYSTEM_PROGRAM_ID } from '@solana/spl-governance' import { NftVoter } from 'idls/nft_voter' import { NftVoterV2 } from 'idls/nft_voter_v2' -import { Program } from '@project-serum/anchor' +import { Program } from '@coral-xyz/anchor' import { AccountData, UpdateVoterWeightRecordTypes, @@ -201,8 +201,15 @@ export const getCastNftVoteInstructionV2 = async ( cnft ) + // CreateCnftActionTicket requires a non-null collection, + // but getCnftParamAndProof returns a nullable one + if (!param.collection.key) throw new Error("Collection key not found"); + // Typescript doesn't infer this in its current version, but this is basically + // casting the collection key to non-null. + const typesafeParams = [param as typeof param & { collection: typeof param.collection & { key : PublicKey }}] + const instruction = await program.methods - .createCnftActionTicket({ [type]: {} }, [param]) + .createCnftActionTicket({ [type]: {} }, typesafeParams) .accounts({ registrar, voterWeightRecord: voterWeightPk, diff --git a/utils/instructions/NftVoter/updateVoterWeight.ts b/utils/instructions/NftVoter/updateVoterWeight.ts index 9a11626b47..9e6958bd48 100644 --- a/utils/instructions/NftVoter/updateVoterWeight.ts +++ b/utils/instructions/NftVoter/updateVoterWeight.ts @@ -8,7 +8,7 @@ import { PROGRAM_ID as ACCOUNT_COMPACTION_PROGRAM_ID } from '@solana/spl-account import { SYSTEM_PROGRAM_ID } from '@solana/spl-governance' import { NftVoter } from 'idls/nft_voter' import { NftVoterV2 } from 'idls/nft_voter_v2' -import { Program } from '@project-serum/anchor' +import { Program } from '@coral-xyz/anchor' import { AccountData, UpdateVoterWeightRecordTypes, @@ -130,8 +130,16 @@ export const getUpdateVoterWeightRecordInstructionV2 = async ( program.provider.connection, cnft ) + + // CreateCnftActionTicket requires a non-null collection, + // but getCnftParamAndProof returns a nullable one + if (!param.collection.key) throw new Error("Collection key not found"); + // Typescript doesn't infer this in its current version, but this is basically + // casting the collection key to non-null. + const typesafeParams = [param as typeof param & { collection: typeof param.collection & { key : PublicKey }}] + const instruction = await program.methods - .createCnftActionTicket({ [type]: {} }, [param]) + .createCnftActionTicket({ [type]: {} }, typesafeParams) .accounts({ registrar, voterWeightRecord: voterWeightPk, diff --git a/utils/mangoV4Tools.ts b/utils/mangoV4Tools.ts index 60e30be0f6..295865a4d8 100644 --- a/utils/mangoV4Tools.ts +++ b/utils/mangoV4Tools.ts @@ -1,3 +1,9 @@ +import { MANGO_V4_ID, MangoClient } from '@blockworks-foundation/mango-v4' +import { AnchorProvider } from '@coral-xyz/anchor' +import queryClient from '@hooks/queries/queryClient' +import { Connection, Keypair, PublicKey } from '@solana/web3.js' +import EmptyWallet from './Mango/listingTools' + export function getChangedValues>( originalValues: T, newValues: T, @@ -38,3 +44,38 @@ export function getNullOrTransform( } return null } + +export const getClient = async (connection: Connection) => { + const client = await queryClient.fetchQuery({ + queryKey: ['mangoClient', connection.rpcEndpoint], + queryFn: async () => { + const options = AnchorProvider.defaultOptions() + const adminProvider = new AnchorProvider( + connection, + new EmptyWallet(Keypair.generate()), + options + ) + const client = MangoClient.connect( + adminProvider, + 'mainnet-beta', + MANGO_V4_ID['mainnet-beta'] + ) + + return client + }, + }) + return client +} +export const getGroupForClient = async ( + client: MangoClient, + groupPk: PublicKey +) => { + const group = await queryClient.fetchQuery({ + queryKey: ['mangoGroup', groupPk.toBase58(), client.connection.rpcEndpoint], + queryFn: async () => { + const response = await client.getGroup(groupPk) + return response + }, + }) + return group +} diff --git a/utils/modifiedMangolana.ts b/utils/modifiedMangolana.ts index f39b89bbec..87761fb884 100644 --- a/utils/modifiedMangolana.ts +++ b/utils/modifiedMangolana.ts @@ -27,6 +27,8 @@ import { TransactionInstructionWithSigners, } from '@blockworks-foundation/mangolana/lib/globalTypes' import { WalletSigner } from '@solana/spl-governance' +import { getFeeEstimate } from '@tools/feeEstimate' +import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' interface TransactionInstructionWithType { instructionsSet: TransactionInstructionWithSigners[] @@ -407,7 +409,7 @@ export const sendSignAndConfirmTransactions = async ({ const logger = new Logger({ ...config }) const block = timeoutStrategy?.block ?? (await connection.getLatestBlockhash('confirmed')) - + const fee = await getFeeEstimate(connection) const walletPk = wallet.publicKey if (!walletPk) throw new Error('Wallet not connected!') @@ -438,6 +440,7 @@ export const sendSignAndConfirmTransactions = async ({ } const transaction = new Transaction() + transaction.add(createComputeBudgetIx(fee)) transactionInstruction.instructionsSet.forEach((instruction) => { transaction.add(instruction.transactionInstruction) if (instruction.signers?.length) { diff --git a/utils/plugin/gateway.ts b/utils/plugin/gateway.ts new file mode 100644 index 0000000000..ab9184b325 --- /dev/null +++ b/utils/plugin/gateway.ts @@ -0,0 +1,84 @@ +import {getRegistrarPDA} from "@utils/plugin/accounts"; +import {ProgramAccount, Realm, SYSTEM_PROGRAM_ID} from "@solana/spl-governance"; +import {GatewayClient} from "@solana/governance-program-library"; +import {PublicKey} from "@solana/web3.js"; + +// Get the registrar account for a given realm +export const tryGetRegistar = async ( + realm: ProgramAccount, + gatewayClient: GatewayClient, +) => { + const {registrar} = await getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + gatewayClient.program.programId + ) + try { + return await gatewayClient.program.account.registrar.fetch( + registrar + ) + } catch (e) { + return null + } +}; + +// Create an instruction to create a registrar account for a given realm +export const createCivicRegistrarIx = async ( + realm: ProgramAccount, + payer: PublicKey, + gatewayClient: GatewayClient, + gatekeeperNetwork: PublicKey, + predecessor?: PublicKey +) => { + const { registrar } = await getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + gatewayClient.program.programId + ) + + const remainingAccounts = predecessor + ? [{ pubkey: predecessor, isSigner: false, isWritable: false }] + : [] + + return gatewayClient!.program.methods + .createRegistrar(false) + .accounts({ + registrar, + realm: realm.pubkey, + governanceProgramId: realm.owner, + realmAuthority: realm.account.authority!, + governingTokenMint: realm.account.communityMint!, + gatekeeperNetwork, + payer, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .remainingAccounts(remainingAccounts) + .instruction() +} + +// Create an instruction to configure a registrar account for a given realm +export const configureCivicRegistrarIx = async ( + realm: ProgramAccount, + gatewayClient: GatewayClient, + gatekeeperNetwork: PublicKey, + predecessor?: PublicKey +) => { + const { registrar } = await getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + gatewayClient.program.programId + ) + const remainingAccounts = predecessor + ? [{ pubkey: predecessor, isSigner: false, isWritable: false }] + : [] + return gatewayClient.program.methods + .configureRegistrar(false) + .accounts({ + registrar, + realm: realm.pubkey, + realmAuthority: realm.account.authority!, + gatekeeperNetwork: gatekeeperNetwork, + }) + .remainingAccounts(remainingAccounts) + .instruction() +} \ No newline at end of file diff --git a/utils/send.tsx b/utils/send.tsx index 93c10f875b..7eca40b04a 100644 --- a/utils/send.tsx +++ b/utils/send.tsx @@ -10,6 +10,8 @@ import Wallet from '@project-serum/sol-wallet-adapter' import { sleep } from '@project-serum/common' import { WalletSigner } from '@solana/spl-governance' import { invalidateInstructionAccounts } from '@hooks/queries/queryClient' +import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' +import { getFeeEstimate } from '@tools/feeEstimate' class TransactionError extends Error { public txid: string @@ -69,9 +71,12 @@ export async function signTransaction({ signers?: Array connection: Connection }) { - transaction.recentBlockhash = ( - await connection.getLatestBlockhash('max') - ).blockhash + const [{ blockhash: recentBlockhash }, fee] = await Promise.all([ + connection.getLatestBlockhash('max'), + getFeeEstimate(connection), + ]) + transaction.add(createComputeBudgetIx(fee)) + transaction.recentBlockhash = recentBlockhash transaction.setSigners(wallet!.publicKey!, ...signers.map((s) => s.publicKey)) if (signers.length > 0) { transaction.partialSign(...signers) @@ -91,9 +96,14 @@ export async function signTransactions({ wallet: Wallet connection: Connection }) { - const blockhash = (await connection.getLatestBlockhash('max')).blockhash + const [{ blockhash: recentBlockhash }, fee] = await Promise.all([ + connection.getLatestBlockhash('max'), + getFeeEstimate(connection), + ]) + transactionsAndSigners.forEach(({ transaction, signers = [] }) => { - transaction.recentBlockhash = blockhash + transaction.add(createComputeBudgetIx(fee)) + transaction.recentBlockhash = recentBlockhash transaction.setSigners( wallet!.publicKey!, ...signers.map((s) => s.publicKey) diff --git a/utils/sendTransactions.tsx b/utils/sendTransactions.tsx index f740fa144d..1ddd9d8d16 100644 --- a/utils/sendTransactions.tsx +++ b/utils/sendTransactions.tsx @@ -11,7 +11,11 @@ import { invalidateInstructionAccounts } from '@hooks/queries/queryClient' import { sendSignAndConfirmTransactionsProps, sendSignAndConfirmTransactions, + TransactionInstructionWithType, } from '@blockworks-foundation/mangolana/lib/transactions' +import { getFeeEstimate } from '@tools/feeEstimate' +import { TransactionInstructionWithSigners } from '@blockworks-foundation/mangolana/lib/globalTypes' +import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' export type WalletSigner = Pick< SignerWalletAdapter, @@ -32,7 +36,7 @@ export enum SequenceType { StopOnFailure, } -export const sendTransactionsV3 = ({ +export const sendTransactionsV3 = async ({ connection, wallet, transactionInstructions, @@ -42,6 +46,19 @@ export const sendTransactionsV3 = ({ // eslint-disable-next-line @typescript-eslint/no-unused-vars lookupTableAccounts, }: sendSignAndConfirmTransactionsProps & { lookupTableAccounts?: any }) => { + const transactionInstructionsWithFee: TransactionInstructionWithType[] = [] + const fee = await getFeeEstimate(connection) + for (const tx of transactionInstructions) { + const txObjWithFee = { + ...tx, + instructionSet: [ + new TransactionInstructionWithSigners(createComputeBudgetIx(fee)), + ...tx.instructionsSet, + ], + } + transactionInstructionsWithFee.push(txObjWithFee) + } + const callbacksWithUiComponent = { afterBatchSign: (signedTxnsCount) => { if (callbacks?.afterBatchSign) { @@ -54,7 +71,7 @@ export const sendTransactionsV3 = ({ callbacks?.afterAllTxConfirmed() } closeTransactionProcessUi() - transactionInstructions.forEach((x) => + transactionInstructionsWithFee.forEach((x) => x.instructionsSet.forEach((x) => invalidateInstructionAccounts(x.transactionInstruction) ) @@ -79,7 +96,7 @@ export const sendTransactionsV3 = ({ getErrorMsg(e), e.txid ) - transactionInstructions.forEach((x) => + transactionInstructionsWithFee.forEach((x) => x.instructionsSet.forEach((x) => invalidateInstructionAccounts(x.transactionInstruction) ) @@ -89,7 +106,7 @@ export const sendTransactionsV3 = ({ const cfg = { maxTxesInBatch: - transactionInstructions.filter( + transactionInstructionsWithFee.filter( (x) => x.sequenceType === SequenceType.Sequential ).length > 0 ? 20 @@ -103,7 +120,7 @@ export const sendTransactionsV3 = ({ return sendSignAndConfirmTransactions({ connection, wallet, - transactionInstructions, + transactionInstructions: transactionInstructionsWithFee, timeoutStrategy, callbacks: callbacksWithUiComponent, config: cfg, @@ -137,17 +154,21 @@ export const txBatchesToInstructionSetWithSigners = ( txBatch: TransactionInstruction[], signerBatches: Keypair[][], batchIdx?: number -) => { +): { transactionInstruction: TransactionInstruction; signers: Keypair[] }[] => { return txBatch.map((tx, txIdx) => { + let signers: Keypair[] = [] + + if ( + typeof batchIdx !== 'undefined' && + signerBatches?.length && + signerBatches?.[batchIdx]?.[txIdx] + ) { + signers = [signerBatches[batchIdx][txIdx]] + } + return { transactionInstruction: tx, - signers: - typeof batchIdx !== 'undefined' && - signerBatches.length && - signerBatches[batchIdx] && - signerBatches[batchIdx][txIdx] - ? [signerBatches[batchIdx][txIdx]] - : [], + signers, } }) } diff --git a/utils/services/tokenPrice.tsx b/utils/services/tokenPrice.tsx index f5eca91a93..0f0200c3a8 100644 --- a/utils/services/tokenPrice.tsx +++ b/utils/services/tokenPrice.tsx @@ -85,6 +85,17 @@ class TokenPriceService { vsTokenSymbol: 'USDC', } } + + //override chai price if its broken + const chaiMint = '3jsFX1tx2Z8ewmamiwSU851GzyzM2DJMq7KWW5DM8Py3' + const chaiData = this._tokenPriceToUSDlist[chaiMint] + + if (chaiData?.price && (chaiData.price > 1.3 || chaiData.price < 0.9)) { + this._tokenPriceToUSDlist[chaiMint] = { + ...chaiData, + price: 1, + } + } } } /** diff --git a/utils/uiTypes/NftVoterClient.ts b/utils/uiTypes/NftVoterClient.ts index c9b5369e88..6a2bd59d54 100644 --- a/utils/uiTypes/NftVoterClient.ts +++ b/utils/uiTypes/NftVoterClient.ts @@ -1,4 +1,4 @@ -import { Program, Provider } from '@project-serum/anchor' +import { Program, Provider } from '@coral-xyz/anchor' import { PublicKey } from '@solana/web3.js' import { NftVoter, IDL } from '../../idls/nft_voter' import { NftVoterV2, IDLV2 } from '../../idls/nft_voter_v2' diff --git a/utils/uiTypes/VotePlugin.ts b/utils/uiTypes/VotePlugin.ts index 22da4901e2..1a9f185eec 100644 --- a/utils/uiTypes/VotePlugin.ts +++ b/utils/uiTypes/VotePlugin.ts @@ -50,7 +50,7 @@ import { } from '@utils/instructions/NftVoter/castNftVote' import { NftVoter } from 'idls/nft_voter' import { NftVoterV2 } from 'idls/nft_voter_v2' -import { Program } from '@project-serum/anchor' +import { Program } from '@coral-xyz/anchor' import { fetchTokenOwnerRecordByPubkey } from '@hooks/queries/tokenOwnerRecord' import { StakeConnection as PythClient } from '@pythnetwork/staking' import { getVotingNfts } from '@hooks/queries/plugins/nftVoter' @@ -341,7 +341,7 @@ export class VotingClient { } = await this.client.withUpdateVoterWeight( instructions, stakeAccount!, - { [type]: {} }, + { [type]: {} } as any, pythVoterWeightTarget ) diff --git a/utils/uiTypes/proposalCreationTypes.ts b/utils/uiTypes/proposalCreationTypes.ts index 3880d37716..4de7c00e00 100644 --- a/utils/uiTypes/proposalCreationTypes.ts +++ b/utils/uiTypes/proposalCreationTypes.ts @@ -342,7 +342,7 @@ export enum Instructions { DualFinanceDelegate, DualFinanceDelegateWithdraw, DualFinanceVoteDeposit, - DualFinanceVote, + DaoVote, DistributionCloseVaults, DistributionFillVaults, DelegateStake, @@ -356,15 +356,21 @@ export enum Instructions { InitSolendObligationAccount, JoinDAO, MangoV4PerpCreate, + MangoV4PerpCreateV23, MangoV4PerpEdit, + MangoV4PerpEditV23, MangoV4OpenBookRegisterMarket, MangoV4OpenBookEditMarket, MangoV4TokenEdit, + MangoV4TokenEditV23, MangoV4TokenRegister, + MangoV4TokenRegisterV23, MangoV4TokenRegisterTrustless, MangoV4GroupEdit, + MangoV4GroupEditV23, IdlSetBuffer, MangoV4IxGateSet, + MangoV4IxGateSetV23, MangoV4AltSet, MangoV4AltExtend, MangoV4StubOracleCreate, @@ -488,7 +494,7 @@ export interface DualFinanceStakingOptionForm { strike: number soName: string | undefined optionExpirationUnixSeconds: number - numTokens: number + numTokens: string lotSize: number baseTreasury: AssetAccount | undefined quoteTreasury: AssetAccount | undefined @@ -504,6 +510,7 @@ export interface DualFinanceGsoForm { lotSize: number subscriptionPeriodEnd: number lockupRatio: number + lockupMint: string baseTreasury: AssetAccount | undefined quoteTreasury: AssetAccount | undefined payer: AssetAccount | undefined diff --git a/utils/validations.tsx b/utils/validations.tsx index 4a8bb1f2af..c6a5324220 100644 --- a/utils/validations.tsx +++ b/utils/validations.tsx @@ -510,9 +510,9 @@ export const getDualFinanceGovernanceAirdropSchema = ({ ), treasury: yup.object().typeError('Treasury is required'), amount: yup - .number() + .string() .typeError('Amount is required') - .test('amount', 'amount', async function (val: number) { + .test('amount', 'amount', async function (val: string) { if (!form.treasury) { return this.createError({ message: `Please select a treasury`, @@ -520,8 +520,8 @@ export const getDualFinanceGovernanceAirdropSchema = ({ } const numAtomsInTreasury = new BN( form.treasury.extensions.token.account.amount - ).toNumber() - if (numAtomsInTreasury < val) { + ) + if (numAtomsInTreasury.lt(new BN(val))) { return this.createError({ message: `Not enough tokens`, }) @@ -584,9 +584,9 @@ export const getDualFinanceMerkleAirdropSchema = ({ form }: { form: any }) => { ), treasury: yup.object().typeError('Treasury is required'), amount: yup - .number() + .string() .typeError('Amount is required') - .test('amount', 'amount', async function (val: number) { + .test('amount', 'amount', async function (val: string) { if (!form.treasury) { return this.createError({ message: `Please select a treasury`, @@ -594,8 +594,8 @@ export const getDualFinanceMerkleAirdropSchema = ({ form }: { form: any }) => { } const numAtomsInTreasury = new BN( form.treasury.extensions.token.account.amount - ).toNumber() - if (numAtomsInTreasury < val) { + ) + if (numAtomsInTreasury.lt(new BN(val))) { return this.createError({ message: `Not enough tokens`, }) @@ -634,9 +634,9 @@ export const getDualFinanceLiquidityStakingOptionSchema = ({ } ), numTokens: yup - .number() + .string() .typeError('Num tokens is required') - .test('amount', 'amount', async function (val: number) { + .test('amount', 'amount', async function (val: string) { if (!form.baseTreasury) { return this.createError({ message: `Please select a treasury`, @@ -644,8 +644,8 @@ export const getDualFinanceLiquidityStakingOptionSchema = ({ } const numAtomsInTreasury = new BN( form.baseTreasury.extensions.token.account.amount - ).toNumber() - if (numAtomsInTreasury < val) { + ) + if (numAtomsInTreasury.lt(new BN(val))) { return this.createError({ message: `Not enough tokens`, }) @@ -716,9 +716,9 @@ export const getDualFinanceStakingOptionSchema = ({ } ), numTokens: yup - .number() + .string() .typeError('Num tokens is required') - .test('amount', 'amount', async function (val: number) { + .test('amount', 'amount', async function (val: string) { if (!form.baseTreasury) { return this.createError({ message: `Please select a treasury`, @@ -726,8 +726,8 @@ export const getDualFinanceStakingOptionSchema = ({ } const numAtomsInTreasury = new BN( form.baseTreasury.extensions.token.account.amount - ).toNumber() - if (numAtomsInTreasury < val) { + ) + if (numAtomsInTreasury.lt(new BN(val))) { return this.createError({ message: `Not enough tokens`, }) @@ -775,9 +775,9 @@ export const getDualFinanceGsoSchema = ({ form }: { form: any }) => { } ), numTokens: yup - .number() + .string() .typeError('Num tokens is required') - .test('amount', 'amount', async function (val: number) { + .test('amount', 'amount', async function (val: string) { if (!form.baseTreasury) { return this.createError({ message: `Please select a treasury`, @@ -785,8 +785,8 @@ export const getDualFinanceGsoSchema = ({ form }: { form: any }) => { } const numAtomsInTreasury = new BN( form.baseTreasury.extensions.token.account.amount - ).toNumber() - if (numAtomsInTreasury < val) { + ) + if (numAtomsInTreasury.lt(new BN(val))) { return this.createError({ message: `Not enough tokens`, }) @@ -874,11 +874,7 @@ export const getDualFinanceDelegateWithdrawSchema = () => { export const getDualFinanceVoteDepositSchema = () => { return yup.object().shape({ numTokens: yup.number().typeError('Num tokens is required'), - realm: yup - .string() - .test('is-valid-address1', 'Please enter a valid PublicKey', (value) => - value ? validatePubkey(value) : true - ), + realm: yup.string(), token: yup.object().typeError('Delegate Token is required'), }) } diff --git a/yarn.lock b/yarn.lock index 0150df6a32..00711f2417 100644 --- a/yarn.lock +++ b/yarn.lock @@ -280,10 +280,10 @@ core-js-pure "^3.25.1" regenerator-runtime "^0.13.11" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" - integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.17.2", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.19.4", "@babel/runtime@^7.22.6", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.6.tgz#c05e610dc228855dc92ef1b53d07389ed8ab521d" + integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ== dependencies: regenerator-runtime "^0.14.0" @@ -337,10 +337,32 @@ keccak256 "^1.0.6" merkletreejs "^0.3.11" -"@blockworks-foundation/mango-v4-settings@0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.3.1.tgz#0c1c0458a384346da18d55b1051c910e4cf6bd91" - integrity sha512-dADriziRtDliXOUFs6PdmUOu2trT4KrRHJsmlGw1BolfM5CafoFT85pDutZNHK5Vy1jn1TKqewyATREgTToH+w== +"@blockworks-foundation/mango-v4-rc@npm:@blockworks-foundation/mango-v4@0.23.0-rc1": + version "0.23.0-rc1" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.23.0-rc1.tgz#a4eed291c7ac1e6d02bbad228d917e34ad2149c0" + integrity sha512-U+F1SAr35TVsKz48W5iYanEIFxttfEVYV0uwDUhXz9HWbHctKYuZH0RyUb9y7xyI6vDBn/z/87FmFiV8meVlyQ== + dependencies: + "@blockworks-foundation/mango-v4-settings" "0.14.15" + "@blockworks-foundation/mangolana" "0.0.14" + "@coral-xyz/anchor" "^0.28.1-beta.2" + "@project-serum/serum" "0.13.65" + "@pythnetwork/client" "~2.14.0" + "@solana/spl-token" "0.3.7" + "@solana/web3.js" "^1.78.2" + "@switchboard-xyz/sbv2-lite" "^0.1.6" + big.js "^6.1.1" + binance-api-node "^0.12.0" + bs58 "^5.0.0" + cross-fetch "^3.1.5" + dotenv "^16.0.3" + fast-copy "^3.0.1" + lodash "^4.17.21" + node-kraken-api "^2.2.2" + +"@blockworks-foundation/mango-v4-settings@0.14.15": + version "0.14.15" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.14.15.tgz#0ac04f2cffbd27a4129bc2086ec1418e29393880" + integrity sha512-GBo43KCosdaohbtS3Rtz8e2zsLsiN3JqTfLKVtStRYO3f2tQLzeo/D2Khz07psw2egq6TCNZJH7+v32iGrPq0w== dependencies: bn.js "^5.2.1" eslint-config-prettier "^9.0.0" @@ -353,12 +375,13 @@ bn.js "^5.2.1" eslint-config-prettier "^9.0.0" -"@blockworks-foundation/mango-v4@0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.21.0.tgz#b3959e201817222da60e8a6d3ba84147242e1439" - integrity sha512-UIF+hQGSsLFKoRAPWolZgPef/r5WB1s9wBdTqLHlU1oUAWXcOw1ZzpSvPzyF2RosGm5k/NdYsL1ONwENSWxl6A== +"@blockworks-foundation/mango-v4@0.21.22": + version "0.21.22" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.21.22.tgz#cf399225b995f3d82edc523f5af03c004c9369ec" + integrity sha512-n+aSuqlmv6lofmpkLCs4mNF5E7jBGD4UTKE3XfJNUVeV0Vh6E3dihraT26ZkrHCW+woNPWa+26vmd3X3bk4t+w== dependencies: "@blockworks-foundation/mango-v4-settings" "^0.2.16" + "@blockworks-foundation/mangolana" "0.0.13" "@coral-xyz/anchor" "^0.28.1-beta.2" "@project-serum/serum" "0.13.65" "@pythnetwork/client" "~2.14.0" @@ -370,17 +393,31 @@ bs58 "^5.0.0" cross-fetch "^3.1.5" dotenv "^16.0.3" + fast-copy "^3.0.1" lodash "^4.17.21" node-kraken-api "^2.2.2" -"@blockworks-foundation/mangolana@0.0.1-beta.15": - version "0.0.1-beta.15" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mangolana/-/mangolana-0.0.1-beta.15.tgz#5442044ecb54c2f57128155665c0b1d9ecbdda39" - integrity sha512-VDSRGHhrtR4nyjGEqQGLBLWbQLFn1Kh1SoaqwwV3De0Ls0WDhe8C5aTDQ8k028XKrlHRC5O1QkJrwWskqKvqNw== +"@blockworks-foundation/mangolana@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mangolana/-/mangolana-0.0.13.tgz#82a9b0846e69068de6216d20fcdcd60375d14e1e" + integrity sha512-/QPMHjtPpAYaDPbQVLolp5Lq4cCd77b8gBumws97L3J0DfvsKpZVYeAA0fNmSX6qq+pKqCgCywDjJeYhJ01PsQ== dependencies: - "@solana/web3.js" "^1.63.1" + "@solana/web3.js" "^1.88.0" bs58 "^5.0.0" - node-fetch "^3.2.10" + isomorphic-ws "^5.0.0" + node-fetch "2.6.11" + ws "^8.16.0" + +"@blockworks-foundation/mangolana@0.0.14": + version "0.0.14" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mangolana/-/mangolana-0.0.14.tgz#f2a0e164f2cbe6e0a0db4fc10267e81ef5d2f7ec" + integrity sha512-KuA2+GdeKoHCBmx2HZnVb8IPomUP1w0ZiwQ1F10SLIypYfrylvPa+HSK2ak/+nzZCb8erS9Oub45UPV7cOh5ng== + dependencies: + "@solana/web3.js" "^1.88.0" + bs58 "^5.0.0" + isomorphic-ws "^5.0.0" + node-fetch "2.6.11" + ws "^8.16.0" "@blocto/sdk@^0.2.22": version "0.2.22" @@ -765,7 +802,27 @@ superstruct "^0.15.4" toml "^3.0.0" -"@coral-xyz/borsh@0.27.0", "@coral-xyz/borsh@^0.26.0", "@coral-xyz/borsh@^0.27.0", "@coral-xyz/borsh@^0.28.0": +"@coral-xyz/anchor@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.29.0.tgz#bd0be95bedfb30a381c3e676e5926124c310ff12" + integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + +"@coral-xyz/borsh@0.27.0", "@coral-xyz/borsh@^0.26.0", "@coral-xyz/borsh@^0.27.0", "@coral-xyz/borsh@^0.28.0", "@coral-xyz/borsh@^0.29.0": version "0.27.0" resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.27.0.tgz#700c647ea5262b1488957ac7fb4e8acf72c72b63" integrity sha512-tJKzhLukghTWPLy+n8K8iJKgBq1yLT/AxaNd10yJrX8mI56ao5+OFAKAqW/h0i79KCvb4BK0VGO5ECmmolFz9A== @@ -862,10 +919,10 @@ "@solana/web3.js" "^1.73.2" js-sha3 "^0.8.0" -"@dual-finance/gso@0.0.14": - version "0.0.14" - resolved "https://registry.yarnpkg.com/@dual-finance/gso/-/gso-0.0.14.tgz#48990ae01295453d4428f6dbea2b83e73d0d9232" - integrity sha512-DjnP/VkT64oNaiyyHrtzwuCe4jEiFkt+9XTfJeLs88TmyUPULel/xmt4PQP2gzjCFrKcj160C+Sb7Q3SjaQB4w== +"@dual-finance/gso@0.0.17": + version "0.0.17" + resolved "https://registry.yarnpkg.com/@dual-finance/gso/-/gso-0.0.17.tgz#b547bc722c7e924be20dd424acb048739ccb3bdb" + integrity sha512-SatlyKfQq185FVWfzOu62IDorCiS/5+JMbnNybgZuI9f2/Sz/WU7ybY4Z7MZz4u8fK6ZWkLQEU3Mfmki/opBzA== dependencies: "@dual-finance/staking-options" "^0.0.17" "@project-serum/anchor" "^0.25.0" @@ -1627,6 +1684,11 @@ bs58 "^5.0.0" ramda "^0.27.1" +"@ioredis/commands@^1.1.1": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -1846,13 +1908,13 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" -"@jnwng/walletconnect-solana@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@jnwng/walletconnect-solana/-/walletconnect-solana-0.1.5.tgz#54d71c0667fe317376490c337c36d0d19da95e5a" - integrity sha512-n8YLfF6NIVOqn+YeJEFRaZbbeNTGXL+VPBl+hqMpxLH+Fp+qgdm4CYH+ULH/OSszL2DBO1j+hB/XFDPiswCNeA== +"@jnwng/walletconnect-solana@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@jnwng/walletconnect-solana/-/walletconnect-solana-0.2.0.tgz#aebea64beaa47273b9b9a71c62d88d543900ab96" + integrity sha512-nyRq0xLEj9i2J4UXQ0Mr4KzsooTMbLu0ewHOqdQV7iZE0PfbtKa8poTSF4ZBAQD8hoMHEx+I7zGFCNMI9BTrTA== dependencies: "@walletconnect/qrcode-modal" "^1.8.0" - "@walletconnect/sign-client" "^2.4.5" + "@walletconnect/sign-client" "^2.7.2" "@walletconnect/utils" "^2.4.5" bs58 "^5.0.0" @@ -1873,22 +1935,27 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.13": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -2543,20 +2610,22 @@ dependencies: "@react-spring/web" "9.3.1" -"@noble/ed25519@^1.6.1", "@noble/ed25519@^1.7.0", "@noble/ed25519@^1.7.1": +"@noble/curves@^1.0.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + +"@noble/ed25519@^1.6.1", "@noble/ed25519@^1.7.1": version "1.7.3" resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" integrity sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ== -"@noble/hashes@^1.1.2", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== - -"@noble/secp256k1@^1.6.3": - version "1.7.1" - resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" - integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== +"@noble/hashes@1.3.3", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -2630,6 +2699,98 @@ node-gyp "^7.1.0" read-package-json-fast "^2.0.1" +"@parcel/watcher-android-arm64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.4.0.tgz#9c93763794153e4f76920994a423b6ea3257059d" + integrity sha512-+fPtO/GsbYX1LJnCYCaDVT3EOBjvSFdQN9Mrzh9zWAOOfvidPWyScTrHIZHHfJBvlHzNA0Gy0U3NXFA/M7PHUA== + +"@parcel/watcher-darwin-arm64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.4.0.tgz#2c79c2abde16aa24cac67e555b60802fd13fe210" + integrity sha512-T/At5pansFuQ8VJLRx0C6C87cgfqIYhW2N/kBfLCUvDhCah0EnLLwaD/6MW3ux+rpgkpQAnMELOCTKlbwncwiA== + +"@parcel/watcher-darwin-x64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.4.0.tgz#23d82f198c5d033f047467c68d7c335f3df49b46" + integrity sha512-vZMv9jl+szz5YLsSqEGCMSllBl1gU1snfbRL5ysJU03MEa6gkVy9OMcvXV1j4g0++jHEcvzhs3Z3LpeEbVmY6Q== + +"@parcel/watcher-freebsd-x64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.4.0.tgz#7310cc86abc27dacd57624bcdba1f0ba092e76df" + integrity sha512-dHTRMIplPDT1M0+BkXjtMN+qLtqq24sLDUhmU+UxxLP2TEY2k8GIoqIJiVrGWGomdWsy5IO27aDV1vWyQ6gfHA== + +"@parcel/watcher-linux-arm-glibc@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.4.0.tgz#c31b76e695027eeb1078d3d6f1d641d0b900c335" + integrity sha512-9NQXD+qk46RwATNC3/UB7HWurscY18CnAPMTFcI9Y8CTbtm63/eex1SNt+BHFinEQuLBjaZwR2Lp+n7pmEJPpQ== + +"@parcel/watcher-linux-arm64-glibc@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.4.0.tgz#56e09b86e9d8a4096f606be118b588da6e965080" + integrity sha512-QuJTAQdsd7PFW9jNGaV9Pw+ZMWV9wKThEzzlY3Lhnnwy7iW23qtQFPql8iEaSFMCVI5StNNmONUopk+MFKpiKg== + +"@parcel/watcher-linux-arm64-musl@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.4.0.tgz#27ffd5ca5f510ecd638f9ad22e2e813049db54e7" + integrity sha512-oyN+uA9xcTDo/45bwsd6TFHa7Lc7hKujyMlvwrCLvSckvWogndCEoVYFNfZ6JJ2KNL/6fFiGPcbjp8jJmEh5Ng== + +"@parcel/watcher-linux-x64-glibc@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.4.0.tgz#44cbbb1e5884a1ca900655f47a0775218318f934" + integrity sha512-KphV8awJmxU3q52JQvJot0QMu07CIyEjV+2Tb2ZtbucEgqyRcxOBDMsqp1JNq5nuDXtcCC0uHQICeiEz38dPBQ== + +"@parcel/watcher-linux-x64-musl@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.4.0.tgz#4c33993618c8d5113722852806239cb80360494b" + integrity sha512-7jzcOonpXNWcSijPpKD5IbC6xC7yTibjJw9jviVzZostYLGxbz8LDJLUnLzLzhASPlPGgpeKLtFUMjAAzM+gSA== + +"@parcel/watcher-wasm@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.4.0.tgz#84a3959c8ef1cd67b36b9fec487edbc8f27719f6" + integrity sha512-MNgQ4WCbBybqQ97KwR/hqJGYTg3+s8qHpgIyFWB2qJOBvoJWbXuJGmm4ZkPLq2bMaANqCZqrXwmKYagZTkMKZA== + dependencies: + is-glob "^4.0.3" + micromatch "^4.0.5" + napi-wasm "^1.1.0" + +"@parcel/watcher-win32-arm64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.4.0.tgz#2a172fd2fda95fe5389298ca3e70b5a96316162a" + integrity sha512-NOej2lqlq8bQNYhUMnOD0nwvNql8ToQF+1Zhi9ULZoG+XTtJ9hNnCFfyICxoZLXor4bBPTOnzs/aVVoefYnjIg== + +"@parcel/watcher-win32-ia32@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.4.0.tgz#279225b2ebe1fadd3c5137c9b2365ad422656904" + integrity sha512-IO/nM+K2YD/iwjWAfHFMBPz4Zqn6qBDqZxY4j2n9s+4+OuTSRM/y/irksnuqcspom5DjkSeF9d0YbO+qpys+JA== + +"@parcel/watcher-win32-x64@2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.4.0.tgz#93e0bd0ad1bda2c9a688764b9b30b71dc5b72a71" + integrity sha512-pAUyUVjfFjWaf/pShmJpJmNxZhbMvJASUpdes9jL6bTEJ+gDxPRSpXTIemNyNsb9AtbiGXs9XduP1reThmd+dA== + +"@parcel/watcher@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.4.0.tgz#2d3c4ef8832a5cdfdbb76b914f022489933e664f" + integrity sha512-XJLGVL0DEclX5pcWa2N9SX1jCGTDd8l972biNooLFtjneuGqodupPQh6XseXIBBeVIMaaJ7bTcs3qGvXwsp4vg== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.4.0" + "@parcel/watcher-darwin-arm64" "2.4.0" + "@parcel/watcher-darwin-x64" "2.4.0" + "@parcel/watcher-freebsd-x64" "2.4.0" + "@parcel/watcher-linux-arm-glibc" "2.4.0" + "@parcel/watcher-linux-arm64-glibc" "2.4.0" + "@parcel/watcher-linux-arm64-musl" "2.4.0" + "@parcel/watcher-linux-x64-glibc" "2.4.0" + "@parcel/watcher-linux-x64-musl" "2.4.0" + "@parcel/watcher-win32-arm64" "2.4.0" + "@parcel/watcher-win32-ia32" "2.4.0" + "@parcel/watcher-win32-x64" "2.4.0" + "@particle-network/auth@^0.5.5": version "0.5.6" resolved "https://registry.yarnpkg.com/@particle-network/auth/-/auth-0.5.6.tgz#058e00980511fdf72189b6d4a7576e67934a008a" @@ -2722,26 +2883,6 @@ snake-case "^3.0.4" toml "^3.0.0" -"@project-serum/anchor@0.24.2", "@project-serum/anchor@^0.24.2": - version "0.24.2" - resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.24.2.tgz#a3c52a99605c80735f446ca9b3a4885034731004" - integrity sha512-0/718g8/DnEuwAidUwh5wLYphUYXhUbiClkuRNhvNoa+1Y8a4g2tJyxoae+emV+PG/Gikd/QUBNMkIcimiIRTA== - dependencies: - "@project-serum/borsh" "^0.2.5" - "@solana/web3.js" "^1.36.0" - base64-js "^1.5.1" - bn.js "^5.1.2" - bs58 "^4.0.1" - buffer-layout "^1.2.2" - camelcase "^5.3.1" - cross-fetch "^3.1.5" - crypto-hash "^1.3.0" - eventemitter3 "^4.0.7" - js-sha256 "^0.9.0" - pako "^2.0.3" - snake-case "^3.0.4" - toml "^3.0.0" - "@project-serum/anchor@0.26.0": version "0.26.0" resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.26.0.tgz#99e15a3923a5d10514f8185b2d3909e5699d60d5" @@ -2824,6 +2965,26 @@ snake-case "^3.0.4" toml "^3.0.0" +"@project-serum/anchor@^0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.24.2.tgz#a3c52a99605c80735f446ca9b3a4885034731004" + integrity sha512-0/718g8/DnEuwAidUwh5wLYphUYXhUbiClkuRNhvNoa+1Y8a4g2tJyxoae+emV+PG/Gikd/QUBNMkIcimiIRTA== + dependencies: + "@project-serum/borsh" "^0.2.5" + "@solana/web3.js" "^1.36.0" + base64-js "^1.5.1" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^5.3.1" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + js-sha256 "^0.9.0" + pako "^2.0.3" + snake-case "^3.0.4" + toml "^3.0.0" + "@project-serum/anchor@^0.25.0": version "0.25.0" resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.25.0.tgz#88ee4843336005cf5a64c80636ce626f0996f503" @@ -2961,16 +3122,16 @@ resolved "https://registry.yarnpkg.com/@pythnetwork/staking-wasm/-/staking-wasm-0.3.4.tgz#29c0f47467249a4c66814a8aab9eadf2cc008add" integrity sha512-0ZdaWmueVO5hucdVH4UDfHyBuxtW6UDcrpEFtD/3pq4naQjcgu1u6rK8iL2pgKi8W2UlsB4vwJqay2Sf1sA4mw== -"@pythnetwork/staking@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@pythnetwork/staking/-/staking-2.0.0.tgz#41edcb000a3c2d1db938a3017dae46f54aac061e" - integrity sha512-7RPcsYfEJxGZ12P+OyQ1lfXxgcoe69N0Zftj525GaxUDMBvCXtNSQM+FuskF8y/GKHifZ+CDI8eP3w26gv0ZzQ== +"@pythnetwork/staking@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@pythnetwork/staking/-/staking-2.1.0.tgz#7c38357cf539f7c044f18507971eb9547d955917" + integrity sha512-hw+FJ7TrpJ0X1ixCmKnCUsFitSYgQ3xf9OxFJM5gKp6eHxv5oC/6Thc6dOkCCsw67xTfHC6fOm2WxfwoA6bTVw== dependencies: - "@project-serum/anchor" "0.24.2" + "@coral-xyz/anchor" "^0.29.0" "@pythnetwork/staking-wasm" "*" "@solana/spl-governance" "0.3.26" "@solana/spl-token" "^0.1.8" - "@solana/web3.js" "^1.36.0" + "@solana/web3.js" "^1.87.5" encoding "^0.1.13" ts-node "^10.7.0" typescript "^4.3.5" @@ -4161,6 +4322,18 @@ js-sha3 "^0.8.0" typescript-collections "^1.3.3" +"@solana/spl-account-compression@~0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@solana/spl-account-compression/-/spl-account-compression-0.2.0.tgz#a8a28a3985b50d0391bfd6374345e9d36eb8f792" + integrity sha512-nHpa+hTUpjLdV9x4LXlp7k0WIkr8kUGjY/SPh+vuTUy4SEIIDjrGJ6/B0hUdd8+mFfrq2x4j/tgJvPsm4K5AJw== + dependencies: + "@metaplex-foundation/beet" "^0.7.1" + "@metaplex-foundation/beet-solana" "^0.4.0" + bn.js "^5.2.1" + borsh "^0.7.0" + js-sha3 "^0.8.0" + typescript-collections "^1.3.3" + "@solana/spl-governance@0.3.26": version "0.3.26" resolved "https://registry.yarnpkg.com/@solana/spl-governance/-/spl-governance-0.3.26.tgz#1a6c56037063654d243cc3ee9503b5b3140bbd6f" @@ -4245,7 +4418,7 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.22" -"@solana/wallet-adapter-base@0.9.22", "@solana/wallet-adapter-base@^0.9.17", "@solana/wallet-adapter-base@^0.9.2", "@solana/wallet-adapter-base@^0.9.21", "@solana/wallet-adapter-base@^0.9.22": +"@solana/wallet-adapter-base@0.9.22": version "0.9.22" resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.22.tgz#97812eaf6aebe01e5fe714326b3c9a0614ae6112" integrity sha512-xbLEZPGSJFvgTeldG9D55evhl7QK/3e/F7vhvcA97mEt1eieTgeKMnGlmmjs3yivI3/gtZNZeSk1XZLnhKcQvw== @@ -4255,6 +4428,16 @@ "@wallet-standard/features" "^1.0.3" eventemitter3 "^4.0.7" +"@solana/wallet-adapter-base@^0.9.17", "@solana/wallet-adapter-base@^0.9.2", "@solana/wallet-adapter-base@^0.9.21", "@solana/wallet-adapter-base@^0.9.22", "@solana/wallet-adapter-base@^0.9.23": + version "0.9.23" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.23.tgz#3b17c28afd44e173f44f658bf9700fd637e12a11" + integrity sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw== + dependencies: + "@solana/wallet-standard-features" "^1.1.0" + "@wallet-standard/base" "^1.0.1" + "@wallet-standard/features" "^1.0.3" + eventemitter3 "^4.0.7" + "@solana/wallet-adapter-bitkeep@^0.3.18": version "0.3.18" resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-bitkeep/-/wallet-adapter-bitkeep-0.3.18.tgz#00e500d216b9d363bdb024aeb7eb8d7e33f584af" @@ -4571,13 +4754,13 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.22" -"@solana/wallet-adapter-walletconnect@0.1.14", "@solana/wallet-adapter-walletconnect@^0.1.14", "@solana/wallet-adapter-walletconnect@^0.1.6": - version "0.1.14" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-walletconnect/-/wallet-adapter-walletconnect-0.1.14.tgz#6994077781880b1a86fda27e000e947ed7764609" - integrity sha512-nz8BB1Gs9s2yLuAf1+wDyZoGxCAVi1XWpzVlXMRBD7oL7Bn3kx3SOohzgoOKQltTrye4PF4cl+KCStzY3zQfkg== +"@solana/wallet-adapter-walletconnect@0.1.16", "@solana/wallet-adapter-walletconnect@^0.1.14", "@solana/wallet-adapter-walletconnect@^0.1.6": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-walletconnect/-/wallet-adapter-walletconnect-0.1.16.tgz#c335970ddec1247e546a4811fceb4f5edf9487de" + integrity sha512-jNaQwSho8hT7gF1ifePE8TJc1FULx8jCF16KX3fZPtzXDxKrj0R4VUpHMGcw4MlDknrnZNLOJAVvyiawAkPCRQ== dependencies: - "@jnwng/walletconnect-solana" "^0.1.5" - "@solana/wallet-adapter-base" "^0.9.22" + "@jnwng/walletconnect-solana" "^0.2.0" + "@solana/wallet-adapter-base" "^0.9.23" "@solana/wallet-adapter-wallets@0.19.15": version "0.19.15" @@ -4644,10 +4827,10 @@ dependencies: "@wallet-standard/base" "^1.0.0" -"@solana/wallet-standard-features@^1.0.0", "@solana/wallet-standard-features@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.0.1.tgz#36270a646f74a80e51b9e21fb360edb64f840c68" - integrity sha512-SUfx7KtBJ55XIj0qAhhVcC1I6MklAXqWFEz9hDHW+6YcJIyvfix/EilBhaBik1FJ2JT0zukpOfFv8zpuAbFRbw== +"@solana/wallet-standard-features@^1.0.0", "@solana/wallet-standard-features@^1.0.1", "@solana/wallet-standard-features@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-features/-/wallet-standard-features-1.2.0.tgz#be8b3824abf5ebcfeaa7298445bf53f76a27c935" + integrity sha512-tUd9srDLkRpe1BYg7we+c4UhRQkq+XQWswsr/L1xfGmoRDF47BPSXf4zE7ZU2GRBGvxtGt7lwJVAufQyQYhxTQ== dependencies: "@wallet-standard/base" "^1.0.1" "@wallet-standard/features" "^1.0.3" @@ -4683,25 +4866,24 @@ "@wallet-standard/app" "^1.0.1" "@wallet-standard/base" "^1.0.1" -"@solana/web3.js@1.56.0", "@solana/web3.js@1.73.3", "@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.30.2", "@solana/web3.js@^1.31.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.35.1", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.37.1", "@solana/web3.js@^1.43.4", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.50.1", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.59.1", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.73.0", "@solana/web3.js@^1.73.2", "@solana/web3.js@^1.77.3", "@solana/web3.js@^1.78.2", "@solana/web3.js@^1.78.3", "@solana/web3.js@^1.87.6": - version "1.73.3" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.73.3.tgz#60e6bd68f6f364d4be360b1e0a03a0a68468a029" - integrity sha512-vHRMo589XEIpoujpE2sZZ1aMZvfA1ImKfNxobzEFyMb+H5j6mRRUXfdgWD0qJ0sm11e5BcBC7HPeRXJB+7f3Lg== +"@solana/web3.js@1.56.0", "@solana/web3.js@1.78.2", "@solana/web3.js@^1.17.0", "@solana/web3.js@^1.21.0", "@solana/web3.js@^1.22.0", "@solana/web3.js@^1.30.2", "@solana/web3.js@^1.31.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.35.1", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.37.1", "@solana/web3.js@^1.43.4", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.50.1", "@solana/web3.js@^1.56.2", "@solana/web3.js@^1.59.1", "@solana/web3.js@^1.63.0", "@solana/web3.js@^1.63.1", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.73.0", "@solana/web3.js@^1.73.2", "@solana/web3.js@^1.77.3", "@solana/web3.js@^1.78.2", "@solana/web3.js@^1.78.3", "@solana/web3.js@^1.87.5", "@solana/web3.js@^1.87.6", "@solana/web3.js@^1.88.0": + version "1.78.2" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.78.2.tgz#ae976ce2f793077aa104ab455f9f75be86a3e2a4" + integrity sha512-oF+TmBZCt3eAEl4Meu3GO2p6G8wdyoKgXgTKzQpIUIhpMGA/dVQzyMFpKjCgoTU1Kx+/UF3gXUdsZOxQukGbvQ== dependencies: - "@babel/runtime" "^7.12.5" - "@noble/ed25519" "^1.7.0" - "@noble/hashes" "^1.1.2" - "@noble/secp256k1" "^1.6.3" + "@babel/runtime" "^7.22.6" + "@noble/curves" "^1.0.0" + "@noble/hashes" "^1.3.0" "@solana/buffer-layout" "^4.0.0" agentkeepalive "^4.2.1" bigint-buffer "^1.1.5" - bn.js "^5.0.0" + bn.js "^5.2.1" borsh "^0.7.0" bs58 "^4.0.1" - buffer "6.0.1" + buffer "6.0.3" fast-stable-stringify "^1.0.0" - jayson "^3.4.4" - node-fetch "^2.6.7" + jayson "^4.1.0" + node-fetch "^2.6.12" rpc-websockets "^7.5.1" superstruct "^0.14.2" @@ -5140,9 +5322,9 @@ integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" - integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/aria-query@^4.2.0": version "4.2.2" @@ -5869,26 +6051,27 @@ "@walletconnect/window-metadata" "1.0.0" detect-browser "5.2.0" -"@walletconnect/core@2.4.7": - version "2.4.7" - resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.4.7.tgz#f1e2935eded3b882128a7fa6b56eff25221e6f2c" - integrity sha512-w92NrtziqrWs070HJICGh80Vp60PaXu06OjNvOnVZEorbTipCWx4xxgcC2NhsT4TCQ8r1FOut6ahLe1PILuRsg== - dependencies: - "@walletconnect/heartbeat" "1.2.0" - "@walletconnect/jsonrpc-provider" "^1.0.6" - "@walletconnect/jsonrpc-utils" "^1.0.4" - "@walletconnect/jsonrpc-ws-connection" "^1.0.7" - "@walletconnect/keyvaluestorage" "^1.0.2" +"@walletconnect/core@2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.11.0.tgz#3a4e301077b2f858fd916b7a20b5b984d1afce63" + integrity sha512-2Tjp5BCevI7dbmqo/OrCjX4tqgMqwJNQLlQAlphqPfvwlF9+tIu6pGcVbSN3U9zyXzWIZCeleqEaWUeSeET4Ew== + dependencies: + "@walletconnect/heartbeat" "1.2.1" + "@walletconnect/jsonrpc-provider" "1.0.13" + "@walletconnect/jsonrpc-types" "1.0.3" + "@walletconnect/jsonrpc-utils" "1.0.8" + "@walletconnect/jsonrpc-ws-connection" "1.0.14" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" "@walletconnect/relay-api" "^1.0.9" "@walletconnect/relay-auth" "^1.0.4" - "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.4.7" - "@walletconnect/utils" "2.4.7" + "@walletconnect/types" "2.11.0" + "@walletconnect/utils" "2.11.0" events "^3.3.0" + isomorphic-unfetch "3.1.0" lodash.isequal "4.5.0" - pino "7.11.0" uint8arrays "^3.1.0" "@walletconnect/environment@^1.0.1": @@ -5906,62 +6089,59 @@ keyvaluestorage-interface "^1.0.0" tslib "1.14.1" -"@walletconnect/heartbeat@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.0.tgz#1e87dd234cb72b0587b84f95c4f942f2b4bd0c79" - integrity sha512-0vbzTa/ARrpmMmOD+bQMxPvFYKtOLQZObgZakrYr0aODiMOO71CmPVNV2eAqXnw9rMmcP+z91OybLeIFlwTjjA== +"@walletconnect/heartbeat@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@walletconnect/heartbeat/-/heartbeat-1.2.1.tgz#afaa3a53232ae182d7c9cff41c1084472d8f32e9" + integrity sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q== dependencies: "@walletconnect/events" "^1.0.1" "@walletconnect/time" "^1.0.2" - chai "^4.3.7" - mocha "^10.2.0" - ts-node "^10.9.1" tslib "1.14.1" -"@walletconnect/jsonrpc-provider@^1.0.6": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.8.tgz#d56e5bc95c1ec264748a6911389a3ac80f4bd831" - integrity sha512-M44vzTrF0TeDcxQorm2lJ5klmfqchYOZqmIHb5T9lIPA/rj22643P83j44flZLyzycPqy5UUlIH6foeBPwjxMg== +"@walletconnect/jsonrpc-provider@1.0.13": + version "1.0.13" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.13.tgz#9a74da648d015e1fffc745f0c7d629457f53648b" + integrity sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g== dependencies: - "@walletconnect/jsonrpc-utils" "^1.0.6" - "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/jsonrpc-utils" "^1.0.8" + "@walletconnect/safe-json" "^1.0.2" tslib "1.14.1" -"@walletconnect/jsonrpc-types@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.2.tgz#b79519f679cd6a5fa4a1bea888f27c1916689a20" - integrity sha512-CZe8tjJX73OWdHjrBHy7HtAapJ2tT0Q3TYhPBhRxi3643lwPIQWC9En45ldY14TZwgSewkbZ0FtGBZK0G7Bbyg== +"@walletconnect/jsonrpc-types@1.0.3", "@walletconnect/jsonrpc-types@^1.0.2", "@walletconnect/jsonrpc-types@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.3.tgz#65e3b77046f1a7fa8347ae02bc1b841abe6f290c" + integrity sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw== dependencies: keyvaluestorage-interface "^1.0.0" tslib "1.14.1" -"@walletconnect/jsonrpc-utils@^1.0.4", "@walletconnect/jsonrpc-utils@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.6.tgz#7fa58e6671247e64e189828103282e6258f5330f" - integrity sha512-snp0tfkjPiDLQp/jrBewI+9SM33GPV4+Gjgldod6XQ7rFyQ5FZjnBxUkY4xWH0+arNxzQSi6v5iDXjCjSaorpg== +"@walletconnect/jsonrpc-utils@1.0.8", "@walletconnect/jsonrpc-utils@^1.0.6", "@walletconnect/jsonrpc-utils@^1.0.8": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz#82d0cc6a5d6ff0ecc277cb35f71402c91ad48d72" + integrity sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw== dependencies: "@walletconnect/environment" "^1.0.1" - "@walletconnect/jsonrpc-types" "^1.0.2" + "@walletconnect/jsonrpc-types" "^1.0.3" tslib "1.14.1" -"@walletconnect/jsonrpc-ws-connection@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.9.tgz#38e089818e490cf52cfad9f98300949a74de9fdd" - integrity sha512-x1COaW6hhMLEo+ND5zF/siBGg5SEwC/gHjeRbJtK1CRiq9atkg/XR7JwtSNfMvYX/O3PRCVmuc5SP0RQio9JUw== +"@walletconnect/jsonrpc-ws-connection@1.0.14": + version "1.0.14" + resolved "https://registry.yarnpkg.com/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.14.tgz#eec700e74766c7887de2bd76c91a0206628732aa" + integrity sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA== dependencies: "@walletconnect/jsonrpc-utils" "^1.0.6" - "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/safe-json" "^1.0.2" events "^3.3.0" - tslib "1.14.1" ws "^7.5.1" -"@walletconnect/keyvaluestorage@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.0.2.tgz#92f5ca0f54c1a88a093778842ce0c874d86369c8" - integrity sha512-U/nNG+VLWoPFdwwKx0oliT4ziKQCEoQ27L5Hhw8YOFGA2Po9A9pULUYNWhDgHkrb0gYDNt//X7wABcEWWBd3FQ== +"@walletconnect/keyvaluestorage@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz#dd2caddabfbaf80f6b8993a0704d8b83115a1842" + integrity sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA== dependencies: - safe-json-utils "^1.1.1" - tslib "1.14.1" + "@walletconnect/safe-json" "^1.0.1" + idb-keyval "^6.2.1" + unstorage "^1.9.0" "@walletconnect/logger@^2.0.1": version "2.0.1" @@ -6013,29 +6193,27 @@ resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.0.tgz#12eeb11d43795199c045fafde97e3c91646683b2" integrity sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg== -"@walletconnect/safe-json@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.1.tgz#9813fa0a7a544b16468730c2d7bed046ed160957" - integrity sha512-Fm7e31oSYY15NQr8SsLJheKAy5L744udZf2lJKcz6wFmPJEzf7hOF0866o/rrldRzJnjZ4H2GJ45pFudsnLW5A== +"@walletconnect/safe-json@^1.0.1", "@walletconnect/safe-json@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@walletconnect/safe-json/-/safe-json-1.0.2.tgz#7237e5ca48046e4476154e503c6d3c914126fa77" + integrity sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA== dependencies: tslib "1.14.1" -"@walletconnect/sign-client@^2.4.5": - version "2.4.7" - resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.4.7.tgz#d01e645f189726d5f919724a4145cdd16e4c4044" - integrity sha512-x5uxnHQkNSn0QNXUdPEfwy4o1Vyi2QIWkDGUh+pfSP4s2vN0+IJAcwqBqkPn+zJ1X7eKYLs+v0ih1eieciYMPA== +"@walletconnect/sign-client@^2.7.2": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.11.0.tgz#de10f976cc1b8ab04b7f7c27f6a298e4e083ab25" + integrity sha512-H2ukscibBS+6WrzQWh+WyVBqO5z4F5et12JcwobdwgHnJSlqIoZxqnUYYWNCI5rUR5UKsKWaUyto4AE9N5dw4Q== dependencies: - "@walletconnect/core" "2.4.7" + "@walletconnect/core" "2.11.0" "@walletconnect/events" "^1.0.1" - "@walletconnect/heartbeat" "1.2.0" - "@walletconnect/jsonrpc-provider" "^1.0.6" - "@walletconnect/jsonrpc-utils" "^1.0.4" + "@walletconnect/heartbeat" "1.2.1" + "@walletconnect/jsonrpc-utils" "1.0.8" "@walletconnect/logger" "^2.0.1" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.4.7" - "@walletconnect/utils" "2.4.7" + "@walletconnect/types" "2.11.0" + "@walletconnect/utils" "2.11.0" events "^3.3.0" - pino "7.11.0" "@walletconnect/time@^1.0.2": version "1.0.2" @@ -6044,15 +6222,15 @@ dependencies: tslib "1.14.1" -"@walletconnect/types@2.4.7": - version "2.4.7" - resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.4.7.tgz#9f102b444631149b2cb0d264830860dc5e211dc0" - integrity sha512-1VaPdPJrE+UrEjAhK5bdxq2+MTo3DvUMmQeNUsp3vUGhocQXB9hJQQ1rYBknYYSyDu2rTksGCQ4nv3ZOqfxvHw== +"@walletconnect/types@2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.11.0.tgz#474a009c56faa9ef4063b76ed84415c801dc9f1e" + integrity sha512-AB5b1lrEbCGHxqS2vqfCkIoODieH+ZAUp9rA1O2ftrhnqDJiJK983Df87JhYhECsQUBHHfALphA8ydER0q+9sw== dependencies: "@walletconnect/events" "^1.0.1" - "@walletconnect/heartbeat" "1.2.0" - "@walletconnect/jsonrpc-types" "^1.0.2" - "@walletconnect/keyvaluestorage" "^1.0.2" + "@walletconnect/heartbeat" "1.2.1" + "@walletconnect/jsonrpc-types" "1.0.3" + "@walletconnect/keyvaluestorage" "^1.1.1" "@walletconnect/logger" "^2.0.1" events "^3.3.0" @@ -6061,25 +6239,24 @@ resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-1.8.0.tgz#3f5e85b2d6b149337f727ab8a71b8471d8d9a195" integrity sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg== -"@walletconnect/utils@2.4.7", "@walletconnect/utils@^2.4.5": - version "2.4.7" - resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.4.7.tgz#f9589f3181f5dc3fd3d4e2cb4c41a08af42e2aae" - integrity sha512-t3kW0qLClnejTTKg3y/o/MmJb5ZDGfD13YT9Nw56Up3qq/pwVfTtWjt8vJOQWMIm0hZgjgESivcf6/wuu3/Oqw== +"@walletconnect/utils@2.11.0", "@walletconnect/utils@^2.4.5": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.11.0.tgz#31c95151c823022077883dda61800cdea71879b7" + integrity sha512-hxkHPlTlDQILHfIKXlmzgNJau/YcSBC3XHUSuZuKZbNEw3duFT6h6pm3HT/1+j1a22IG05WDsNBuTCRkwss+BQ== dependencies: "@stablelib/chacha20poly1305" "1.0.1" "@stablelib/hkdf" "1.0.1" "@stablelib/random" "^1.0.2" "@stablelib/sha256" "1.0.1" "@stablelib/x25519" "^1.0.3" - "@walletconnect/jsonrpc-utils" "^1.0.4" "@walletconnect/relay-api" "^1.0.9" - "@walletconnect/safe-json" "^1.0.1" + "@walletconnect/safe-json" "^1.0.2" "@walletconnect/time" "^1.0.2" - "@walletconnect/types" "2.4.7" + "@walletconnect/types" "2.11.0" "@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-metadata" "^1.0.1" detect-browser "5.3.0" - query-string "7.1.1" + query-string "7.1.3" uint8arrays "^3.1.0" "@walletconnect/window-getters@1.0.0": @@ -6160,19 +6337,19 @@ acorn-walk@^7.0.0: integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn-walk@^8.0.0, acorn-walk@^8.0.2, acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== acorn@^7.0.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.1.0, acorn@^8.4.1, acorn@^8.8.0, acorn@^8.8.1: - version "8.8.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" - integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== +acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.3, acorn@^8.4.1, acorn@^8.8.0, acorn@^8.8.1: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== aes-js@3.0.0: version "3.0.0" @@ -6295,7 +6472,7 @@ any-observable@^0.3.0: resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" integrity sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog== -anymatch@^3.0.3, anymatch@~3.1.2: +anymatch@^3.0.3, anymatch@^3.1.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -6622,16 +6799,7 @@ axios@^0.27.2: follow-redirects "^1.14.9" form-data "^4.0.0" -axios@^1.1.3, axios@^1.4.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.1.tgz#11fbaa11fc35f431193a9564109c88c1f27b585f" - integrity sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^1.3.6: +axios@^1.1.3, axios@^1.3.6, axios@^1.4.0: version "1.6.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== @@ -7083,14 +7251,6 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - buffer@6.0.3, buffer@^6.0.1, buffer@^6.0.2, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -7213,19 +7373,6 @@ chai@=4.3.4: pathval "^1.1.1" type-detect "^4.0.5" -chai@^4.3.7: - version "4.3.7" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" - integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^4.1.2" - get-func-name "^2.0.0" - loupe "^2.3.1" - pathval "^1.1.1" - type-detect "^4.0.5" - chalk@3.0.0, chalk@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" @@ -7278,9 +7425,11 @@ chardet@^0.7.0: integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" chokidar@3.5.3, chokidar@^3.5.2, chokidar@^3.5.3: version "3.5.3" @@ -7315,6 +7464,13 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +citty@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.5.tgz#fe37ceae5dc764af75eb2fece99d2bf527ea4e50" + integrity sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ== + dependencies: + consola "^3.2.3" + cjs-module-lexer@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" @@ -7372,6 +7528,15 @@ client-only@^0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +clipboardy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-4.0.0.tgz#e73ced93a76d19dd379ebf1f297565426dffdca1" + integrity sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w== + dependencies: + execa "^8.0.1" + is-wsl "^3.1.0" + is64bit "^2.0.0" + cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -7409,6 +7574,11 @@ clsx@1.2.1, clsx@^1.2.1: resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +cluster-key-slot@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + cmd-shim@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-6.0.1.tgz#a65878080548e1dca760b3aea1e21ed05194da9d" @@ -7534,6 +7704,11 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +consola@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.2.3.tgz#0741857aa88cfa0d6fd53f1cff0375136e98502f" + integrity sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ== + console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" @@ -7549,6 +7724,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +cookie-es@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cookie-es/-/cookie-es-1.0.0.tgz#4759684af168dfc54365b2c2dda0a8d7ee1e4865" + integrity sha512-mWYvfOLrfEc996hlKcdABeIiPHUPC6DM2QYZdGGOvhOTbA3tjm2eBwqlJpoFdjC89NI4Qt6h0Pu06Mp+1Pj5OQ== + copy-to-clipboard@^3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" @@ -7681,6 +7861,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +crossws@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.1.1.tgz#3a85a8140568e4828d9747a884171ea7e6a8bbe2" + integrity sha512-c9c/o7bS3OjsdpSkvexpka0JNlesBF2JU9B2V1yNsYGwRbAafxhJQ7VI9b48D5bpONz/oxbPGMzBojy9sXoQIQ== + crypto-browserify@^3.12.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -8160,11 +8345,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" - integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== - data-urls@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" @@ -8237,7 +8417,7 @@ decode-named-character-reference@^1.0.0: dependencies: character-entities "^2.0.0" -decode-uri-component@^0.2.0: +decode-uri-component@^0.2.0, decode-uri-component@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== @@ -8254,13 +8434,6 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" -deep-eql@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" - integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== - dependencies: - type-detect "^4.0.0" - deep-equal@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.1.0.tgz#5ba60402cf44ab92c2c07f3f3312c3d857a0e1dd" @@ -8312,6 +8485,11 @@ defined@^1.0.0: resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== +defu@^6.1.3, defu@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/defu/-/defu-6.1.4.tgz#4e0c9cf9ff68fe5f3d7f2765cc1a012dfdcb0479" + integrity sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg== + delaunator@5: version "5.0.0" resolved "https://registry.yarnpkg.com/delaunator/-/delaunator-5.0.0.tgz#60f052b28bd91c9b4566850ebf7756efe821d81b" @@ -8334,6 +8512,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== +denque@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== + depd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -8357,6 +8540,11 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +destr@^2.0.1, destr@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/destr/-/destr-2.0.2.tgz#8d3c0ee4ec0a76df54bc8b819bca215592a8c218" + integrity sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg== + detect-browser@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.2.0.tgz#c9cd5afa96a6a19fda0bbe9e9be48a6b6e1e9c97" @@ -8367,6 +8555,11 @@ detect-browser@5.3.0: resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -8436,9 +8629,9 @@ diffie-hellman@^5.0.0: randombytes "^2.0.0" dijkstrajs@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" - integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz#4c8dbdea1f0f6478bff94d9c49c784d623e4fc23" + integrity sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA== dir-glob@^3.0.1: version "3.0.1" @@ -9147,6 +9340,21 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" + integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^8.0.1" + human-signals "^5.0.0" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^4.1.0" + strip-final-newline "^3.0.0" + exenv@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" @@ -9207,6 +9415,11 @@ eyes@^0.1.8: resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== +fast-copy@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-3.0.1.tgz#9e89ef498b8c04c1cd76b33b8e14271658a732aa" + integrity sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -9244,9 +9457,9 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-redact@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.1.2.tgz#d58e69e9084ce9fa4c1a6fa98a3e1ecf5d7839aa" - integrity sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw== + version "3.3.0" + resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.3.0.tgz#7c83ce3a7be4898241a46560d51de10f653f7634" + integrity sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ== fast-safe-stringify@^2.0.6, fast-safe-stringify@^2.1.1: version "2.1.1" @@ -9291,14 +9504,6 @@ fbjs@^2.0.0: setimmediate "^1.0.5" ua-parser-js "^0.7.18" -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.yarnpkg.com/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - fetch-retry@^5.0.6: version "5.0.6" resolved "https://registry.yarnpkg.com/fetch-retry/-/fetch-retry-5.0.6.tgz#17d0bc90423405b7a88b74355bf364acd2a7fa56" @@ -9467,13 +9672,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - fp-ts@2.12.2: version "2.12.2" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.12.2.tgz#a191db2dbbb04f48a0e75050b94f57cc876c7b40" @@ -9506,16 +9704,11 @@ fs.realpath@^1.0.0: integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -function-bind@^1.1.2: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -9564,10 +9757,10 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== +get-func-name@^2.0.0, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: version "1.1.3" @@ -9593,6 +9786,11 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-port-please@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/get-port-please/-/get-port-please-3.1.2.tgz#502795e56217128e4183025c89a48c71652f4e49" + integrity sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ== + get-stream@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -9605,6 +9803,11 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" + integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -9717,6 +9920,21 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" +h3@^1.10.1, h3@^1.8.2: + version "1.10.1" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.10.1.tgz#221634ca9bdb216a6b359bd2915be466a179b8a1" + integrity sha512-UBAUp47hmm4BB5/njB4LrEa9gpuvZj4/Qf/ynSMzO6Ku2RXaouxEfiG2E2IFnv6fxbhAkzjasDxmo6DFdEeXRg== + dependencies: + cookie-es "^1.0.0" + defu "^6.1.4" + destr "^2.0.2" + iron-webcrypto "^1.0.0" + ohash "^1.1.3" + radix3 "^1.1.0" + ufo "^1.3.2" + uncrypto "^0.1.3" + unenv "^1.9.0" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -9885,6 +10103,11 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" +http-shutdown@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/http-shutdown/-/http-shutdown-1.2.2.tgz#41bc78fc767637c4c95179bc492f312c0ae64c5f" + integrity sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw== + http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -9912,6 +10135,11 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" + integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -9943,6 +10171,11 @@ iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +idb-keyval@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/idb-keyval/-/idb-keyval-6.2.1.tgz#94516d625346d16f56f3b33855da11bfded2db33" + integrity sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg== + ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -10097,6 +10330,26 @@ io-ts@2.2.18: resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.18.tgz#dfb41aded5f0e598ccf2a25a483c205444210173" integrity sha512-3JxUUzRtPQPs5sOwB7pW0+Xb54nOzqA6M1sRB1hwgsRmkWMeGTjtOrCynGTJhIj+mBLUj2S37DAq2+BrPh9kTQ== +ioredis@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.3.2.tgz#9139f596f62fc9c72d873353ac5395bcf05709f7" + integrity sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA== + dependencies: + "@ioredis/commands" "^1.1.1" + cluster-key-slot "^1.1.0" + debug "^4.3.4" + denque "^2.1.0" + lodash.defaults "^4.2.0" + lodash.isarguments "^3.1.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +iron-webcrypto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.0.0.tgz#e3b689c0c61b434a0a4cb82d0aeabbc8b672a867" + integrity sha512-anOK1Mktt8U1Xi7fCM3RELTuYbnFikQY5VtrDj7kPgpejV7d43tWKhzgioO0zpkazLEL/j/iayRqnJhrGfqUsg== + is-arguments@^1.0.4, is-arguments@^1.1.0, is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -10159,20 +10412,13 @@ is-color-stop@^1.1.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.13.0: +is-core-module@^2.13.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: hasown "^2.0.0" -is-core-module@^2.8.1, is-core-module@^2.9.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" - integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== - dependencies: - has "^1.0.3" - is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -10180,6 +10426,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -10226,6 +10477,13 @@ is-hex-prefixed@1.0.0: resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -10335,6 +10593,11 @@ is-stream@^2.0.0, is-stream@^2.0.1: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" @@ -10390,6 +10653,20 @@ is-weakset@^2.0.1: call-bind "^1.0.2" get-intrinsic "^1.1.1" +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== + dependencies: + is-inside-container "^1.0.0" + +is64bit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is64bit/-/is64bit-2.0.0.tgz#198c627cbcb198bbec402251f88e5e1a51236c07" + integrity sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw== + dependencies: + system-architecture "^0.1.0" + isarray@^2.0.1, isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" @@ -10413,11 +10690,24 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" +isomorphic-unfetch@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== +isomorphic-ws@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" + integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -10465,10 +10755,10 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jayson@^3.4.4: - version "3.7.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.7.0.tgz#b735b12d06d348639ae8230d7a1e2916cb078f25" - integrity sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ== +jayson@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" + integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== dependencies: "@types/connect" "^3.4.33" "@types/node" "^12.12.54" @@ -10480,7 +10770,6 @@ jayson@^3.4.4: eyes "^0.1.8" isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" - lodash "^4.17.20" uuid "^8.3.2" ws "^7.4.5" @@ -10859,6 +11148,11 @@ jest@29.2.0: import-local "^3.0.2" jest-cli "^29.2.0" +jiti@^1.21.0: + version "1.21.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" + integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== + js-base64@^3.7.2: version "3.7.3" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.3.tgz#2e784bb0851636bf1e99ef12e4f3a8a8c9b7639f" @@ -11007,6 +11301,11 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== +jsonc-parser@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" + integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -11156,6 +11455,30 @@ lint-staged@10.0.10: string-argv "0.3.1" stringify-object "^3.3.0" +listhen@^1.5.5: + version "1.6.0" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.6.0.tgz#df26c527c59b87557be4d0408d4a09626bd946c8" + integrity sha512-z0RcEXVX5oTpY1bO02SKoTU/kmZSrFSngNNzHRM6KICR17PTq7ANush6AE6ztGJwJD4RLpBrVHd9GnV51J7s3w== + dependencies: + "@parcel/watcher" "^2.4.0" + "@parcel/watcher-wasm" "2.4.0" + citty "^0.1.5" + clipboardy "^4.0.0" + consola "^3.2.3" + crossws "^0.1.0" + defu "^6.1.4" + get-port-please "^3.1.2" + h3 "^1.10.1" + http-shutdown "^1.2.2" + jiti "^1.21.0" + mlly "^1.5.0" + node-forge "^1.3.1" + pathe "^1.1.2" + std-env "^3.7.0" + ufo "^1.3.2" + untun "^0.1.3" + uqr "^0.1.2" + listr-silent-renderer@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" @@ -11244,6 +11567,11 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + lodash.flatmap@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz#ef8cbf408f6e48268663345305c6acc0b778702e" @@ -11254,6 +11582,11 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== + lodash.isequal@4.5.0, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -11347,13 +11680,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" - integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== - dependencies: - get-func-name "^2.0.0" - lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -11361,6 +11687,11 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" +lru-cache@^10.0.2: + version "10.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -11876,7 +12207,7 @@ micromark@^3.0.0: micromark-util-types "^1.0.1" uvu "^0.5.0" -micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: +micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -11919,6 +12250,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -11999,6 +12335,16 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mlly@^1.2.0, mlly@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.5.0.tgz#8428a4617d54cc083d3009030ac79739a0e5447a" + integrity sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ== + dependencies: + acorn "^8.11.3" + pathe "^1.1.2" + pkg-types "^1.0.3" + ufo "^1.3.2" + mocha@10.1.0, mocha@^9.1.4, mocha@^9.2.0: version "10.1.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" @@ -12026,39 +12372,12 @@ mocha@10.1.0, mocha@^9.1.4, mocha@^9.2.0: yargs-parser "20.2.4" yargs-unparser "2.0.0" -mocha@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" - integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== - dependencies: - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.4" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "5.0.1" - ms "2.1.3" - nanoid "3.3.3" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - workerpool "6.2.1" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - modern-normalize@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/modern-normalize/-/modern-normalize-1.1.0.tgz#da8e80140d9221426bd4f725c6e11283d34f90b7" integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA== -mri@^1.1.0: +mri@^1.1.0, mri@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== @@ -12126,6 +12445,11 @@ nanoid@^3.3.1, nanoid@^3.3.4: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== +napi-wasm@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/napi-wasm/-/napi-wasm-1.1.0.tgz#bbe617823765ae9c1bc12ff5942370eae7b2ba4e" + integrity sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -12224,10 +12548,10 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== -node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== +node-addon-api@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" + integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== node-emoji@^1.11.0: version "1.11.0" @@ -12236,6 +12560,11 @@ node-emoji@^1.11.0: dependencies: lodash "^4.17.21" +node-fetch-native@^1.4.0, node-fetch-native@^1.4.1, node-fetch-native@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.1.tgz#f95c74917d3cebc794cdae0cd2a9c7594aad0cb4" + integrity sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw== + node-fetch@2.6.1, node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -12243,6 +12572,13 @@ node-fetch@2.6.1, node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@2.6.11: + version "2.6.11" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" + integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: version "2.6.12" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" @@ -12250,14 +12586,10 @@ node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.2.10: - version "3.3.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.3.1.tgz#b3eea7b54b3a48020e46f4f88b9c5a7430d20b2e" - integrity sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" +node-forge@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.6.0" @@ -12336,6 +12668,13 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-run-path@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.2.0.tgz#224cdd22c755560253dd71b83a1ef2f758b2e955" + integrity sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg== + dependencies: + path-key "^4.0.0" + npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -12459,6 +12798,20 @@ oblivious-set@1.1.1: resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.1.1.tgz#d9d38e9491d51f27a5c3ec1681d2ba40aa81e98b" integrity sha512-Oh+8fK09mgGmAshFdH6hSVco6KZmd1tTwNFWj35OvzdmJTMZtAkbn05zar2iG3v6sDs1JLEtOiBGNb6BHwkb2w== +ofetch@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/ofetch/-/ofetch-1.3.3.tgz#588cb806a28e5c66c2c47dd8994f9059a036d8c0" + integrity sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg== + dependencies: + destr "^2.0.1" + node-fetch-native "^1.4.0" + ufo "^1.3.0" + +ohash@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ohash/-/ohash-1.1.3.tgz#f12c3c50bfe7271ce3fd1097d42568122ccdcf07" + integrity sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw== + on-exit-leak-free@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" @@ -12485,6 +12838,13 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -12644,6 +13004,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -12654,6 +13019,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pathe@^1.1.0, pathe@^1.1.1, pathe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" + integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== + pathval@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" @@ -12732,6 +13102,15 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pkg-types@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" + integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== + dependencies: + jsonc-parser "^3.2.0" + mlly "^1.2.0" + pathe "^1.1.0" + please-upgrade-node@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" @@ -13368,12 +13747,12 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -query-string@7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1" - integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w== +query-string@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328" + integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg== dependencies: - decode-uri-component "^0.2.0" + decode-uri-component "^0.2.2" filter-obj "^1.1.0" split-on-first "^1.0.0" strict-uri-encode "^2.0.0" @@ -13403,6 +13782,11 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +radix3@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/radix3/-/radix3-1.1.0.tgz#9745df67a49c522e94a33d0a93cf743f104b6e0d" + integrity sha512-pNsHDxbGORSvuSScqNJ+3Km6QAVqk8CfsCBIEoDgpqLrkD2f3QM4I7d1ozJJ172OmIcoUcerZaNWqtLkRXTV3A== + ramda@0.28.0, ramda@^0.28.0: version "0.28.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.28.0.tgz#acd785690100337e8b063cab3470019be427cc97" @@ -13506,16 +13890,11 @@ react-clientside-effect@^1.2.6: dependencies: "@babel/runtime" "^7.12.13" -react-content-loader@6.2.1: +react-content-loader@6.2.1, react-content-loader@^6.1.0: version "6.2.1" resolved "https://registry.yarnpkg.com/react-content-loader/-/react-content-loader-6.2.1.tgz#8feb733c2d2495002e1b216f13707f2b5f2a8ead" integrity sha512-6ONbFX+Hi3SHuP66JB8CPvJn372pj+qwltJV0J8z/8MFrq98I1cbFdZuhDWeQXu3CFxiiDTXJn7DFxx2ZvrO7g== -react-content-loader@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/react-content-loader/-/react-content-loader-6.2.0.tgz#cd8fee8160b8fda6610d0c69ce5aee7b8094cba6" - integrity sha512-r1dI6S+uHNLW68qraLE2njJYOuy6976PpCExuCZUcABWbfnF3FMcmuESRI8L4Bj45wnZ7n8g71hkPLzbma7/Cw== - react-device-detect@^2.1.2: version "2.2.2" resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.2.tgz#dbabbce798ec359c83f574c3edb24cf1cca641a5" @@ -13580,15 +13959,15 @@ react-hook-form@7.31.3: resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.31.3.tgz#b61bafb9a7435f91695351a7a9f714d8c4df0121" integrity sha512-NVZdCWViIWXXXlQ3jxVQH0NuNfwPf8A/0KvuCxrM9qxtP1qYosfR2ZudarziFrVOC7eTUbWbm1T4OyYCwv9oSQ== -react-icons@4.11.0: +react-icons@4.11.0, react-icons@^4.3.1: version "4.11.0" resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65" integrity sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA== -react-icons@^4.3.1: - version "4.7.1" - resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345" - integrity sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw== +react-intersection-observer@9.5.3: + version "9.5.3" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.5.3.tgz#f47a31ed3a0359cbbfdb91a53d7470ac2ab7b3c7" + integrity sha512-NJzagSdUPS5rPhaLsHXYeJbsvdpbJwL6yCHtMk91hc0ufQ2BnXis+0QQ9NBh6n9n+Q3OyjR6OQLShYbaNBkThQ== react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" @@ -13769,10 +14148,10 @@ react-virtualized-auto-sizer@1.0.6: resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca" integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ== -react-window@1.8.9: - version "1.8.9" - resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.9.tgz#24bc346be73d0468cdf91998aac94e32bc7fa6a8" - integrity sha512-+Eqx/fj1Aa5WnhRfj9dJg4VYATGwIUP2ItwItiJ6zboKWA6EX3lYDAXfGF2hyNqplEprhbtjbipiADEcwQ823Q== +react-window@1.8.10: + version "1.8.10" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.10.tgz#9e6b08548316814b443f7002b1cf8fd3a1bdde03" + integrity sha512-Y0Cx+dnU6NLa5/EvoHukUD0BklJ8qITCtVEPY1C/nL8wwoZ0b5aEw8Ff1dOVHw7fCzMt55XfJDd8S8W8LCaUCg== dependencies: "@babel/runtime" "^7.0.0" memoize-one ">=3.1.1 <6" @@ -13818,9 +14197,9 @@ readable-stream@^2.0.6: util-deprecate "~1.0.1" readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.1.tgz#f9f9b5f536920253b3d26e7660e7da4ccff9bb62" - integrity sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ== + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -13873,6 +14252,18 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== + dependencies: + redis-errors "^1.0.0" + reduce-css-calc@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz#7ef8761a28d614980dc0c982f772c93f7a99de03" @@ -14007,7 +14398,7 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== -resolve@1.22.8: +resolve@1.22.8, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -14016,15 +14407,6 @@ resolve@1.22.8: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.12.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: - version "1.22.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" - integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== - dependencies: - is-core-module "^2.9.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@^2.0.0-next.3: version "2.0.0-next.4" resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" @@ -14192,9 +14574,9 @@ safe-regex-test@^1.0.0: is-regex "^1.1.4" safe-stable-stringify@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz#ec7b037768098bf65310d1d64370de0dc02353aa" - integrity sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA== + version "2.4.3" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" @@ -14347,6 +14729,11 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-swizzle@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" @@ -14461,9 +14848,9 @@ split-on-first@^1.0.0: integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== split2@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" - integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== sprintf-js@~1.0.2: version "1.0.3" @@ -14499,11 +14886,21 @@ stacktrace-parser@^0.1.10: dependencies: type-fest "^0.7.1" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + "statuses@>= 1.5.0 < 2": version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== +std-env@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" + integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== + stream-browserify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -14513,9 +14910,9 @@ stream-browserify@^3.0.0: readable-stream "^3.5.0" stream-shift@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" - integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== stream-transform@^3.2.1: version "3.2.1" @@ -14678,6 +15075,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + strip-hex-prefix@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" @@ -14799,6 +15201,11 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +system-architecture@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/system-architecture/-/system-architecture-0.1.0.tgz#71012b3ac141427d97c67c56bc7921af6bff122d" + integrity sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA== + tailwind-merge@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.6.0.tgz#dd652005544aa0b04628e69688b7108265f0d441" @@ -15104,7 +15511,7 @@ ts-mocha@^9.0.2: optionalDependencies: tsconfig-paths "^3.5.0" -ts-node@10.9.1, ts-node@^10.7.0, ts-node@^10.9.1: +ts-node@10.9.1, ts-node@^10.7.0: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== @@ -15301,6 +15708,11 @@ uc.micro@^1.0.1: resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +ufo@^1.3.0, ufo@^1.3.1, ufo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.2.tgz#c7d719d0628a1c80c006d2240e0d169f6e3c0496" + integrity sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA== + uint8arrays@^3.0.0, uint8arrays@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.1.tgz#2d8762acce159ccd9936057572dade9459f65ae0" @@ -15318,6 +15730,27 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +uncrypto@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b" + integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q== + +unenv@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/unenv/-/unenv-1.9.0.tgz#469502ae85be1bd3a6aa60f810972b1a904ca312" + integrity sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g== + dependencies: + consola "^3.2.3" + defu "^6.1.3" + mime "^3.0.0" + node-fetch-native "^1.6.1" + pathe "^1.1.1" + +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + unified@^10.0.0: version "10.1.2" resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" @@ -15407,6 +15840,32 @@ unstated-next@^1.1.0: resolved "https://registry.yarnpkg.com/unstated-next/-/unstated-next-1.1.0.tgz#7bb4911a12fdf3cc8ad3eb11a0b315e4a8685ea8" integrity sha512-AAn47ZncPvgBGOvMcn8tSRxsrqwf2VdAPxLASTuLJvZt4rhKfDvUkmYZLGfclImSfTVMv7tF4ynaVxin0JjDCA== +unstorage@^1.9.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/unstorage/-/unstorage-1.10.1.tgz#bf8cc00a406e40a6293e893da9807057d95875b0" + integrity sha512-rWQvLRfZNBpF+x8D3/gda5nUCQL2PgXy2jNG4U7/Rc9BGEv9+CAJd0YyGCROUBKs9v49Hg8huw3aih5Bf5TAVw== + dependencies: + anymatch "^3.1.3" + chokidar "^3.5.3" + destr "^2.0.2" + h3 "^1.8.2" + ioredis "^5.3.2" + listhen "^1.5.5" + lru-cache "^10.0.2" + mri "^1.2.0" + node-fetch-native "^1.4.1" + ofetch "^1.3.3" + ufo "^1.3.1" + +untun@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/untun/-/untun-0.1.3.tgz#5d10dee37a3a5737ff03d158be877dae0a0e58a6" + integrity sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ== + dependencies: + citty "^0.1.5" + consola "^3.2.3" + pathe "^1.1.1" + update-browserslist-db@^1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz#0f54b876545726f17d00cd9a2561e6dade943ff3" @@ -15415,6 +15874,11 @@ update-browserslist-db@^1.0.9: escalade "^3.1.1" picocolors "^1.0.0" +uqr@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/uqr/-/uqr-0.1.2.tgz#5c6cd5dcff9581f9bb35b982cb89e2c483a41d7d" + integrity sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA== + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -15615,11 +16079,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-streams-polyfill@^3.0.3: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - web3-utils@^1.3.4: version "1.10.0" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" @@ -15726,9 +16185,9 @@ which-collection@^1.0.1: is-weakset "^2.0.1" which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + version "2.0.1" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" + integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== which-typed-array@^1.1.2, which-typed-array@^1.1.8: version "1.1.9" @@ -15828,10 +16287,10 @@ ws@^7.2.0, ws@^7.3.1, ws@^7.4.0, ws@^7.4.5, ws@^7.5.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.11.0, ws@^8.5.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== +ws@^8.11.0, ws@^8.16.0, ws@^8.5.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== ws@~8.2.3: version "8.2.3"