diff --git a/.env.sample b/.env.sample index 326208b10a..289d0cd4be 100644 --- a/.env.sample +++ b/.env.sample @@ -5,6 +5,7 @@ DEVNET_RPC=https://mango.devnet.rpcpool.com DEFAULT_GOVERNANCE_PROGRAM_ID=GTesTBiEWE32WHXXE2S4XbZvA5CrEc4xs6ZgRe895dP +NEXT_PUBLIC_JUPTER_SWAP_API_ENDPOINT=https://quote-api.jup.ag/v6 NEXT_PUBLIC_API_ENDPOINT=https://api.realms.today/graphql NEXT_PUBLIC_DISCORD_APPLICATION_CLIENT_ID=1042836142560645130 NEXT_PUBLIC_DISCORD_MATCHDAY_CLIENT_ID=1044361939322683442 diff --git a/.github/workflows/ci-main-tests.yml b/.github/workflows/ci-main-tests.yml index e91d40665f..2f471a90a3 100644 --- a/.github/workflows/ci-main-tests.yml +++ b/.github/workflows/ci-main-tests.yml @@ -26,7 +26,7 @@ jobs: - name: Run CodeQL uses: github/codeql-action/analyze@v2 - + sca: name: Dependency Scan runs-on: ubuntu-latest @@ -54,41 +54,41 @@ jobs: format: 'table' severity: 'CRITICAL' exit-code: '1' - + - name: Upload scan results - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif' test: - name: Run Tests - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 + name: Run Tests + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 - - name: Setup Node - uses: actions/setup-node@v4 - with: - node-version: 18 - cache: yarn + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: yarn - - name: Cache dependencies - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: '**/node_modules' + key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - - name: Install dependencies - run: yarn ci + - name: Install dependencies + run: yarn ci - - name: Run tests - run: yarn test-all + - name: Run tests + run: yarn test-all pass: name: All tests pass needs: ['sast', 'sca', 'test'] runs-on: ubuntu-latest steps: - - run: echo ok \ No newline at end of file + - run: echo ok diff --git a/.nvmrc b/.nvmrc index 53d838af21..0a47c855eb 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -lts/gallium +lts/iron \ No newline at end of file diff --git a/.vscode/deploy.txt b/.vscode/deploy.txt new file mode 100644 index 0000000000..7949afce22 --- /dev/null +++ b/.vscode/deploy.txt @@ -0,0 +1 @@ +Please deploy \ No newline at end of file diff --git a/.yarnrc b/.yarnrc index 83f65f98bb..b16a8dd6e3 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,2 @@ ---frozen-lockfile true --add.exact true ignore-scripts true diff --git a/@types/types.ts b/@types/types.ts index 9761f749b8..519b525fb9 100644 --- a/@types/types.ts +++ b/@types/types.ts @@ -4,3 +4,5 @@ export interface EndpointInfo { name: EndpointTypes url: string } + +export type GovernanceRole = 'council' | 'community'; \ No newline at end of file diff --git a/DriftStakeVoterPlugin/DriftVoterClient.ts b/DriftStakeVoterPlugin/DriftVoterClient.ts new file mode 100644 index 0000000000..6a83a5c5f3 --- /dev/null +++ b/DriftStakeVoterPlugin/DriftVoterClient.ts @@ -0,0 +1,259 @@ +import { BN, Program, Provider } from '@coral-xyz/anchor' +import { Client } from '@solana/governance-program-library' +import { + getTokenOwnerRecordAddress, + SYSTEM_PROGRAM_ID, +} from '@solana/spl-governance' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' +import { DriftStakeVoter, IDL } from './idl/driftStakeVoter' +import { IDL as DriftIDL } from './idl/drift' +import { + getInsuranceFundStakeAccountPublicKey, + getInsuranceFundVaultPublicKey, + getSpotMarketPublicKey, + unstakeSharesToAmountWithOpenRequest, +} from './driftSdk' +import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount' +import { DRIFT_STAKE_VOTER_PLUGIN } from './constants' +import { fetchRealmByPubkey } from '@hooks/queries/realm' +import queryClient from '@hooks/queries/queryClient' + +export class DriftVoterClient extends Client { + readonly requiresInputVoterWeight = true + + async _fetchRegistrar(realm: PublicKey, mint: PublicKey) { + const { registrar: registrarPk } = this.getRegistrarPDA(realm, mint) + const registrar = await queryClient.fetchQuery( + ['Drift', 'Plugin Registrar', registrarPk], + () => this.program.account.registrar.fetch(registrarPk) + ) + return registrar + } + + constructor( + public program: Program, + public devnet: boolean + ) { + super(program, devnet) + } + + async calculateMaxVoterWeight( + _realm: PublicKey, + _mint: PublicKey + ): Promise { + console.log( + 'drift voter client was just asked to calculate max voter weight' + ) + const { result: realm } = await fetchRealmByPubkey( + this.program.provider.connection, + _realm + ) + console.log('drift voter client realm', realm) + return realm?.account.config?.communityMintMaxVoteWeightSource.value ?? null // TODO this code should not actually be called because this is not a max voter weight plugin + } + + async calculateVoterWeight( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey, + inputVoterWeight: BN + ): Promise { + const registrar = await this._fetchRegistrar(realm, mint) + const spotMarketIndex = registrar.spotMarketIndex // could just hardcode spotmarket pk + const driftProgramId = registrar.driftProgramId // likewise + const drift = new Program(DriftIDL, driftProgramId, this.program.provider) + const spotMarketPk = await getSpotMarketPublicKey( + driftProgramId, + spotMarketIndex + ) + const insuranceFundVaultPk = await getInsuranceFundVaultPublicKey( + driftProgramId, + spotMarketIndex + ) + const insuranceFundStakePk = await getInsuranceFundStakeAccountPublicKey( + driftProgramId, + voter, + spotMarketIndex + ) + + const insuranceFundStake = await queryClient.fetchQuery({ + queryKey: ['Insurance Fund Stake', insuranceFundStakePk.toString()], + queryFn: async () => + drift.account.insuranceFundStake.fetchNullable(insuranceFundStakePk), + }) + + if (insuranceFundStake === null) { + console.log('drift voter client', 'no insurance fund stake account found') + return inputVoterWeight + } + + const spotMarket = await queryClient.fetchQuery({ + queryKey: ['Drift Spot Market', spotMarketPk.toString()], + queryFn: async () => drift.account.spotMarket.fetchNullable(spotMarketPk), + }) + + if (spotMarket === null) { + console.log('Drift spot market not found: ' + spotMarketPk.toString()) + return inputVoterWeight + } + + const insuranceFundVault = await fetchTokenAccountByPubkey( + this.program.provider.connection, + insuranceFundVaultPk + ) + if (insuranceFundVault.result === undefined) { + console.log( + 'Insurance fund vault not found: ' + insuranceFundVaultPk.toString() + ) + return inputVoterWeight + } + + const nShares = insuranceFundStake.ifShares + const withdrawRequestShares = insuranceFundStake.lastWithdrawRequestShares + const withdrawRequestAmount = insuranceFundStake.lastWithdrawRequestValue + const totalIfShares = spotMarket.insuranceFund.totalShares + const insuranceFundVaultBalance = insuranceFundVault.result?.amount + + const amount = unstakeSharesToAmountWithOpenRequest( + nShares, + withdrawRequestShares, + withdrawRequestAmount, + totalIfShares, + insuranceFundVaultBalance + ) + + return amount.add(inputVoterWeight) + } + + async updateVoterWeightRecord( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey + //action?: VoterWeightAction | undefined, + //inputRecordCallback?: (() => Promise) | undefined + ): Promise<{ + pre: TransactionInstruction[] + post?: TransactionInstruction[] | undefined + }> { + const connection = this.program.provider.connection + const { result: realmAccount } = await fetchRealmByPubkey(connection, realm) + if (!realmAccount) throw new Error('Realm not found') + const tokenOwnerRecordPk = await getTokenOwnerRecordAddress( + realmAccount?.owner, + realm, + mint, + voter + ) + const { voterWeightPk } = await this.getVoterWeightRecordPDA( + realm, + mint, + voter + ) + const { registrar: registrarPk } = this.getRegistrarPDA(realm, mint) + const registrar = await this._fetchRegistrar(realm, mint) + const spotMarketIndex = registrar.spotMarketIndex // could just hardcode spotmarket pk + const driftProgramId = registrar.driftProgramId // likewise + const drift = new Program(DriftIDL, driftProgramId, this.program.provider) + + //const drift = new Program(DriftIDL, driftProgramId, this.program.provider) + const spotMarketPk = await getSpotMarketPublicKey( + driftProgramId, + spotMarketIndex + ) + const insuranceFundVaultPk = await getInsuranceFundVaultPublicKey( + driftProgramId, + spotMarketIndex + ) + const insuranceFundStakePk = await getInsuranceFundStakeAccountPublicKey( + driftProgramId, + voter, + spotMarketIndex + ) + + const spotMarket = await queryClient.fetchQuery({ + queryKey: ['Drift Spot Market', spotMarketPk.toString()], + queryFn: async () => drift.account.spotMarket.fetchNullable(spotMarketPk), + }) + const spotMarketPkOrNull = spotMarket === null ? null : spotMarketPk + + const insuranceFundVault = await fetchTokenAccountByPubkey( + this.program.provider.connection, + insuranceFundVaultPk + ) + const insuranceFundVaultPkOrNull = + insuranceFundVault.found === false ? null : insuranceFundVaultPk + + let insuranceFundStake: + | Awaited> + | undefined + try { + insuranceFundStake = await drift.account.insuranceFundStake.fetch( + insuranceFundStakePk + ) + } catch (e) { + console.log('drift voter client', 'no insurance fund stake account found') + insuranceFundStake = undefined + } + const stakePkOrNull = + insuranceFundStake === undefined ? null : insuranceFundStakePk + + const ix = await this.program.methods + .updateVoterWeightRecord() + .accountsStrict({ + voterWeightRecord: voterWeightPk, + registrar: registrarPk, + driftProgram: driftProgramId, + spotMarket: spotMarketPkOrNull, + insuranceFundStake: stakePkOrNull, + insuranceFundVault: insuranceFundVaultPkOrNull, + tokenOwnerRecord: tokenOwnerRecordPk, + }) + .instruction() + + return { pre: [ix] } + } + + // NO-OP + async createMaxVoterWeightRecord(): Promise { + return null + } + + // NO-OP + async updateMaxVoterWeightRecord(): Promise { + return null + } + + static async connect( + provider: Provider, + programId = new PublicKey(DRIFT_STAKE_VOTER_PLUGIN), + devnet = false + ): Promise { + return new DriftVoterClient( + new Program(IDL, programId, provider), + devnet + ) + } + + async createVoterWeightRecord( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey + ): Promise { + const { voterWeightPk } = await this.getVoterWeightRecordPDA( + realm, + mint, + voter + ) + const { registrar } = this.getRegistrarPDA(realm, mint) + + return this.program.methods + .createVoterWeightRecord(voter) + .accounts({ + voterWeightRecord: voterWeightPk, + registrar, + payer: voter, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .instruction() + } +} diff --git a/DriftStakeVoterPlugin/components/DriftDeposit.tsx b/DriftStakeVoterPlugin/components/DriftDeposit.tsx new file mode 100644 index 0000000000..a17d82ec0e --- /dev/null +++ b/DriftStakeVoterPlugin/components/DriftDeposit.tsx @@ -0,0 +1,57 @@ +import { BigNumber } from 'bignumber.js' +import { useRealmQuery } from '@hooks/queries/realm' +import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' +import useUserGovTokenAccountQuery from '@hooks/useUserGovTokenAccount' +import { DepositTokensButton } from '@components/DepositTokensButton' +import Button from '@components/Button' +import { DRIFT_GOVERNANCE_TICKER } from 'DriftStakeVoterPlugin/constants' + +/** Contextual deposit, shows only if relevant */ +export const DriftDeposit = ({ role }: { role: 'community' | 'council' }) => { + const realm = useRealmQuery().data?.result + const mint = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + + const mintInfo = useMintInfoByPubkeyQuery(mint).data?.result + const userAta = useUserGovTokenAccountQuery(role).data?.result + + const depositAmount = userAta?.amount + ? new BigNumber(userAta.amount.toString()) + : new BigNumber(0) + + return !depositAmount.isGreaterThan(0) ? null : ( + <> +
+ You have{' '} + {mintInfo + ? depositAmount.shiftedBy(-mintInfo.decimals).toFormat() + : depositAmount.toFormat()}{' '} + more {DRIFT_GOVERNANCE_TICKER} in your wallet. You can stake it with + Drift or deposit it into Realms to increase your voting power. +
+
+ + +
+ + ) +} diff --git a/DriftStakeVoterPlugin/components/DriftVotingPower.tsx b/DriftStakeVoterPlugin/components/DriftVotingPower.tsx new file mode 100644 index 0000000000..96509cd95a --- /dev/null +++ b/DriftStakeVoterPlugin/components/DriftVotingPower.tsx @@ -0,0 +1,145 @@ +import classNames from 'classnames' + +import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' +import { useRealmQuery } from '@hooks/queries/realm' +import { BigNumber } from 'bignumber.js' +import clsx from 'clsx' +import { useMemo } from 'react' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { useJoinRealm } from '@hooks/useJoinRealm' +import { Transaction } from '@solana/web3.js' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { useConnection } from '@solana/wallet-adapter-react' +import Button from '@components/Button' +import { sendTransaction } from '@utils/send' +import { DriftDeposit } from './DriftDeposit' +import { BN } from '@coral-xyz/anchor' + +interface Props { + className?: string + role: 'community' | 'council' +} + +export default function DriftVotingPower({ role, className }: Props) { + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + const { connection } = useConnection() + const realm = useRealmQuery().data?.result + const { + userNeedsTokenOwnerRecord, + userNeedsVoterWeightRecords, + handleRegister, + } = useJoinRealm() + const mintInfo = useMintInfoByPubkeyQuery(realm?.account.communityMint).data + ?.result + + const { totalCalculatedVoterWeight, isReady } = useRealmVoterWeightPlugins( + role + ) + + const vanillaValue = totalCalculatedVoterWeight?.initialValue + const stakedValue = totalCalculatedVoterWeight?.value?.sub( + vanillaValue ?? new BN(0) + ) + + const formattedTotal = useMemo( + () => + mintInfo && totalCalculatedVoterWeight?.value + ? new BigNumber(totalCalculatedVoterWeight?.value.toString()) + .shiftedBy(-mintInfo.decimals) + .toFormat(2) + : undefined, + [mintInfo, totalCalculatedVoterWeight?.value] + ) + + const formattedStaked = useMemo( + () => + mintInfo && stakedValue + ? new BigNumber(stakedValue.toString()) + .shiftedBy(-mintInfo.decimals) + .toFormat(2) + : undefined, + [mintInfo, stakedValue] + ) + + const formattedVanilla = useMemo( + () => + mintInfo && vanillaValue + ? new BigNumber(vanillaValue.toString()) + .shiftedBy(-mintInfo.decimals) + .toFormat(2) + : undefined, + [mintInfo, vanillaValue] + ) + + // There are two buttons available on this UI: + // The Deposit button - available if you have tokens to deposit + // The Join button - available if you have already deposited tokens (you have a Token Owner Record) + // but you may not have all your Voter Weight Records yet. + // This latter case may occur if the DAO changes its configuration and new Voter Weight Records are required. + // For example if a new plugin is added. + const showJoinButton = + userNeedsTokenOwnerRecord || userNeedsVoterWeightRecords + + const join = async () => { + const instructions = await handleRegister() + const transaction = new Transaction() + transaction.add(...instructions) + + await sendTransaction({ + transaction: transaction, + wallet: wallet!, + connection, + signers: [], + sendingMessage: `Registering`, + successMessage: `Registered`, + }) + } + + if (!isReady || formattedTotal === undefined) { + return ( +
+ ) + } + + return ( +
+
+
+
+
Votes
+
+ {formattedTotal ?? 0} +
+ {formattedStaked && + stakedValue?.gtn(0) && + formattedVanilla && + vanillaValue?.gtn(0) && ( + <> +
+ {formattedStaked} from Drift insurance staking +
+
+ {formattedVanilla} from Realms deposit +
+ + )} +
+
+
+ {connected && showJoinButton && ( + + )} + +
+
+
+ ) +} diff --git a/DriftStakeVoterPlugin/constants.ts b/DriftStakeVoterPlugin/constants.ts new file mode 100644 index 0000000000..4a48c341f5 --- /dev/null +++ b/DriftStakeVoterPlugin/constants.ts @@ -0,0 +1,8 @@ +export const DRIFT_STAKE_VOTER_PLUGIN = + 'dVoTE1AJqkZVoE1mPbWcqYPmEEvAUBksHY2NiM2UJQe' + +export const DRIFT_PROGRAM_ID = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH' + +//export const DRIFT_GOVERNANCE_PROGRAM_ID = 'dgov7NC8iaumWw3k8TkmLDybvZBCmd1qwxgLAGAsWxf' + +export const DRIFT_GOVERNANCE_TICKER = 'DRFT' diff --git a/DriftStakeVoterPlugin/driftSdk.ts b/DriftStakeVoterPlugin/driftSdk.ts new file mode 100644 index 0000000000..7341b55590 --- /dev/null +++ b/DriftStakeVoterPlugin/driftSdk.ts @@ -0,0 +1,78 @@ +import { PublicKey } from '@solana/web3.js' +import * as anchor from '@coral-xyz/anchor' +import { BN } from '@coral-xyz/anchor' + +export async function getSpotMarketPublicKey( + programId: PublicKey, + marketIndex: number +): Promise { + return ( + await PublicKey.findProgramAddress( + [ + Buffer.from(anchor.utils.bytes.utf8.encode('spot_market')), + new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2), + ], + programId + ) + )[0] +} + +export async function getInsuranceFundVaultPublicKey( + programId: PublicKey, + marketIndex: number +): Promise { + return ( + await PublicKey.findProgramAddress( + [ + Buffer.from(anchor.utils.bytes.utf8.encode('insurance_fund_vault')), + new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2), + ], + programId + ) + )[0] +} + +export function getInsuranceFundStakeAccountPublicKey( + programId: PublicKey, + authority: PublicKey, + marketIndex: number +): PublicKey { + return PublicKey.findProgramAddressSync( + [ + Buffer.from(anchor.utils.bytes.utf8.encode('insurance_fund_stake')), + authority.toBuffer(), + new anchor.BN(marketIndex).toArrayLike(Buffer, 'le', 2), + ], + programId + )[0] +} + +const ZERO = new BN(0) +export function unstakeSharesToAmountWithOpenRequest( + nShares: BN, + withdrawRequestShares: BN, + withdrawRequestAmount: BN, + totalIfShares: BN, + insuranceFundVaultBalance: BN +): BN { + let stakedAmount: BN + if (totalIfShares.gt(ZERO)) { + stakedAmount = BN.max( + ZERO, + nShares + .sub(withdrawRequestShares) + .mul(insuranceFundVaultBalance) + .div(totalIfShares) + ) + } else { + stakedAmount = ZERO + } + + const withdrawAmount = BN.min( + withdrawRequestAmount, + withdrawRequestShares.mul(insuranceFundVaultBalance).div(totalIfShares) + ) + const amount = withdrawAmount.add(stakedAmount) + + return amount +} diff --git a/DriftStakeVoterPlugin/idl/drift.ts b/DriftStakeVoterPlugin/idl/drift.ts new file mode 100644 index 0000000000..541e857a0c --- /dev/null +++ b/DriftStakeVoterPlugin/idl/drift.ts @@ -0,0 +1,25907 @@ +export type Drift = { + "version": "2.92.0", + "name": "drift", + "instructions": [ + { + "name": "initializeUser", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "initializeUserStats", + "accounts": [ + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeReferrerName", + "accounts": [ + { + "name": "referrerName", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "deposit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "withdraw", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "transferDeposit", + "accounts": [ + { + "name": "fromUser", + "isMut": true, + "isSigner": false + }, + { + "name": "toUser", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "placePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + } + ] + }, + { + "name": "cancelOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "cancelOrderByUserId", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "userOrderId", + "type": "u8" + } + ] + }, + { + "name": "cancelOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketType", + "type": { + "option": { + "defined": "MarketType" + } + } + }, + { + "name": "marketIndex", + "type": { + "option": "u16" + } + }, + { + "name": "direction", + "type": { + "option": { + "defined": "PositionDirection" + } + } + } + ] + }, + { + "name": "cancelOrdersByIds", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderIds", + "type": { + "vec": "u32" + } + } + ] + }, + { + "name": "modifyOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "modifyOrderParams", + "type": { + "defined": "ModifyOrderParams" + } + } + ] + }, + { + "name": "modifyOrderByUserId", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "userOrderId", + "type": "u8" + }, + { + "name": "modifyOrderParams", + "type": { + "defined": "ModifyOrderParams" + } + } + ] + }, + { + "name": "placeAndTakePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "placeAndMakePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "taker", + "isMut": true, + "isSigner": false + }, + { + "name": "takerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "takerOrderId", + "type": "u32" + } + ] + }, + { + "name": "placeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + } + ] + }, + { + "name": "placeAndTakeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "placeAndMakeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "taker", + "isMut": true, + "isSigner": false + }, + { + "name": "takerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "takerOrderId", + "type": "u32" + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + } + ] + }, + { + "name": "placeOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "vec": { + "defined": "OrderParams" + } + } + } + ] + }, + { + "name": "beginSwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "outSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "inSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "outTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "inTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "instructions", + "isMut": false, + "isSigner": false, + "docs": [ + "Instructions Sysvar for instruction introspection" + ] + } + ], + "args": [ + { + "name": "inMarketIndex", + "type": "u16" + }, + { + "name": "outMarketIndex", + "type": "u16" + }, + { + "name": "amountIn", + "type": "u64" + } + ] + }, + { + "name": "endSwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "outSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "inSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "outTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "inTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "instructions", + "isMut": false, + "isSigner": false, + "docs": [ + "Instructions Sysvar for instruction introspection" + ] + } + ], + "args": [ + { + "name": "inMarketIndex", + "type": "u16" + }, + { + "name": "outMarketIndex", + "type": "u16" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + }, + { + "name": "reduceOnly", + "type": { + "option": { + "defined": "SwapReduceOnly" + } + } + } + ] + }, + { + "name": "addPerpLpShares", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "nShares", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removePerpLpShares", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "sharesToBurn", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removePerpLpSharesInExpiringMarket", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "sharesToBurn", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateUserName", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updateUserCustomMarginRatio", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "marginRatio", + "type": "u32" + } + ] + }, + { + "name": "updateUserMarginTradingEnabled", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "marginTradingEnabled", + "type": "bool" + } + ] + }, + { + "name": "updateUserDelegate", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "delegate", + "type": "publicKey" + } + ] + }, + { + "name": "updateUserReduceOnly", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "updateUserAdvancedLp", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "advancedLp", + "type": "bool" + } + ] + }, + { + "name": "deleteUser", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "reclaimRent", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "fillPerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "revertFill", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "fillSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "triggerOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": "u32" + } + ] + }, + { + "name": "forceCancelOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserIdle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserOpenOrdersCount", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "adminDisableUpdatePerpBidAskTwap", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "disable", + "type": "bool" + } + ] + }, + { + "name": "settlePnl", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleMultiplePnls", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndexes", + "type": { + "vec": "u16" + } + }, + { + "name": "mode", + "type": { + "defined": "SettlePnlMode" + } + } + ] + }, + { + "name": "settleFundingPayment", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "settleLp", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleExpiredMarket", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "liquidatePerp", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxBaseAssetAmount", + "type": "u64" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidatePerpWithFill", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "liquidateSpot", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxLiabilityTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidateBorrowForPerpPnl", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxLiabilityTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidatePerpPnlForDeposit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxPnlTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "setUserStatusToBeingLiquidated", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "resolvePerpPnlDeficit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "perpMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "resolvePerpBankruptcy", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "quoteSpotMarketIndex", + "type": "u16" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "resolveSpotBankruptcy", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleRevenueToInsuranceFund", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateFundingRate", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updatePrelaunchOracle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updatePerpBidAskTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "keeperStats", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "updateSpotMarketCumulativeInterest", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateAmms", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketIndexes", + "type": { + "array": [ + "u16", + 5 + ] + } + } + ] + }, + { + "name": "updateSpotMarketExpiry", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "expiryTs", + "type": "i64" + } + ] + }, + { + "name": "updateUserQuoteAssetInsuranceStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserGovTokenInsuranceStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "addInsuranceFundStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "requestRemoveInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "cancelRequestRemoveInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removeInsuranceFundStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "transferProtocolIfShares", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "transferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "shares", + "type": "u128" + } + ] + }, + { + "name": "updatePythPullOracle", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "encodedVaa", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "postPythPullOracleUpdateAtomic", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "guardianSet", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "postMultiPythPullOracleUpdatesAtomic", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "guardianSet", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "initialize", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "quoteAssetMint", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeSpotMarket", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketMint", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "optimalUtilization", + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "type": "u32" + }, + { + "name": "maxBorrowRate", + "type": "u32" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "initialAssetWeight", + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + }, + { + "name": "activeStatus", + "type": "bool" + }, + { + "name": "assetTier", + "type": { + "defined": "AssetTier" + } + }, + { + "name": "scaleInitialAssetWeightStart", + "type": "u64" + }, + { + "name": "withdrawGuardThreshold", + "type": "u64" + }, + { + "name": "orderTickSize", + "type": "u64" + }, + { + "name": "orderStepSize", + "type": "u64" + }, + { + "name": "ifTotalFactor", + "type": "u32" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "deleteInitializedSpotMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "initializeSerumFulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "serumProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "serumMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "serumOpenOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "serumFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateSerumFulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "serumFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "initializeOpenbookV2FulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "openbookV2Program", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2Market", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2FulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "openbookV2FulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2FulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "initializePhoenixFulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "phoenixProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "phoenixFulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "updateSerumVault", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "srmVault", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializePerpMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "ammBaseAssetReserve", + "type": "u128" + }, + { + "name": "ammQuoteAssetReserve", + "type": "u128" + }, + { + "name": "ammPeriodicity", + "type": "i64" + }, + { + "name": "ammPegMultiplier", + "type": "u128" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "contractTier", + "type": { + "defined": "ContractTier" + } + }, + { + "name": "marginRatioInitial", + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "type": "u32" + }, + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "activeStatus", + "type": "bool" + }, + { + "name": "baseSpread", + "type": "u32" + }, + { + "name": "maxSpread", + "type": "u32" + }, + { + "name": "maxOpenInterest", + "type": "u128" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "type": "u64" + }, + { + "name": "orderStepSize", + "type": "u64" + }, + { + "name": "orderTickSize", + "type": "u64" + }, + { + "name": "minOrderSize", + "type": "u64" + }, + { + "name": "concentrationCoefScale", + "type": "u128" + }, + { + "name": "curveUpdateIntensity", + "type": "u8" + }, + { + "name": "ammJitIntensity", + "type": "u8" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "initializePredictionMarket", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "deleteInitializedPerpMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "moveAmmPrice", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "baseAssetReserve", + "type": "u128" + }, + { + "name": "quoteAssetReserve", + "type": "u128" + }, + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "recenterPerpMarketAmm", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pegMultiplier", + "type": "u128" + }, + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketAmmSummaryStats", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdatePerpMarketSummaryStatsParams" + } + } + ] + }, + { + "name": "updatePerpMarketExpiry", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "expiryTs", + "type": "i64" + } + ] + }, + { + "name": "settleExpiredMarketPoolsToRevenuePool", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "depositIntoPerpMarketFeePool", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "sourceVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "depositIntoSpotMarketVault", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "sourceVault", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "depositIntoSpotMarketRevenuePool", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "repegAmmCurve", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "newPegCandidate", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketAmmOracleTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "resetPerpMarketAmmOracleTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "updateK", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketMarginRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marginRatioInitial", + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketFundingPeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fundingPeriod", + "type": "i64" + } + ] + }, + { + "name": "updatePerpMarketMaxImbalances", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "unrealizedMaxImbalance", + "type": "u64" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketLiquidationFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + } + ] + }, + { + "name": "updateInsuranceFundUnstakingPeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "insuranceFundUnstakingPeriod", + "type": "i64" + } + ] + }, + { + "name": "updateSpotMarketLiquidationFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + } + ] + }, + { + "name": "updateWithdrawGuardThreshold", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "withdrawGuardThreshold", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketIfFactor", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "userIfFactor", + "type": "u32" + }, + { + "name": "totalIfFactor", + "type": "u32" + } + ] + }, + { + "name": "updateSpotMarketRevenueSettlePeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "revenueSettlePeriod", + "type": "i64" + } + ] + }, + { + "name": "updateSpotMarketStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + } + ] + }, + { + "name": "updateSpotMarketPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updateSpotMarketAssetTier", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "assetTier", + "type": { + "defined": "AssetTier" + } + } + ] + }, + { + "name": "updateSpotMarketMarginWeights", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "initialAssetWeight", + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + } + ] + }, + { + "name": "updateSpotMarketBorrowRate", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "optimalUtilization", + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "type": "u32" + }, + { + "name": "maxBorrowRate", + "type": "u32" + }, + { + "name": "minBorrowRate", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "updateSpotMarketMaxTokenDeposits", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxTokenDeposits", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketMaxTokenBorrows", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxTokenBorrowsFraction", + "type": "u16" + } + ] + }, + { + "name": "updateSpotMarketScaleInitialAssetWeightStart", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "scaleInitialAssetWeightStart", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketOracle", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "oracle", + "type": "publicKey" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + } + ] + }, + { + "name": "updateSpotMarketStepSizeAndTickSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "stepSize", + "type": "u64" + }, + { + "name": "tickSize", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketMinOrderSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderSize", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketOrdersEnabled", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "ordersEnabled", + "type": "bool" + } + ] + }, + { + "name": "updateSpotMarketIfPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updateSpotMarketName", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updatePerpMarketStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + } + ] + }, + { + "name": "updatePerpMarketPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketContractTier", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "contractTier", + "type": { + "defined": "ContractTier" + } + } + ] + }, + { + "name": "updatePerpMarketImfFactor", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "unrealizedPnlImfFactor", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketUnrealizedAssetWeight", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "unrealizedInitialAssetWeight", + "type": "u32" + }, + { + "name": "unrealizedMaintenanceAssetWeight", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketConcentrationCoef", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "concentrationScale", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketCurveUpdateIntensity", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "curveUpdateIntensity", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketTargetBaseAssetAmountPerLp", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "targetBaseAssetAmountPerLp", + "type": "i32" + } + ] + }, + { + "name": "updatePerpMarketPerLpBase", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perLpBase", + "type": "i8" + } + ] + }, + { + "name": "updateLpCooldownTime", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "lpCooldownTime", + "type": "u64" + } + ] + }, + { + "name": "updatePerpFeeStructure", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } + } + ] + }, + { + "name": "updateSpotFeeStructure", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } + } + ] + }, + { + "name": "updateInitialPctToLiquidate", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "initialPctToLiquidate", + "type": "u16" + } + ] + }, + { + "name": "updateLiquidationDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidationDuration", + "type": "u8" + } + ] + }, + { + "name": "updateLiquidationMarginBufferRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidationMarginBufferRatio", + "type": "u32" + } + ] + }, + { + "name": "updateOracleGuardRails", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "oracleGuardRails", + "type": { + "defined": "OracleGuardRails" + } + } + ] + }, + { + "name": "updateStateSettlementDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "settlementDuration", + "type": "u16" + } + ] + }, + { + "name": "updateStateMaxNumberOfSubAccounts", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxNumberOfSubAccounts", + "type": "u16" + } + ] + }, + { + "name": "updateStateMaxInitializeUserFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxInitializeUserFee", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketOracle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "oracle", + "type": "publicKey" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + } + ] + }, + { + "name": "updatePerpMarketBaseSpread", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "baseSpread", + "type": "u32" + } + ] + }, + { + "name": "updateAmmJitIntensity", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "ammJitIntensity", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketMaxSpread", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxSpread", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketStepSizeAndTickSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "stepSize", + "type": "u64" + }, + { + "name": "tickSize", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketName", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updatePerpMarketMinOrderSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderSize", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketMaxSlippageRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxSlippageRatio", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketMaxFillReserveFraction", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxFillReserveFraction", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketMaxOpenInterest", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxOpenInterest", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketNumberOfUsers", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "numberOfUsers", + "type": { + "option": "u32" + } + }, + { + "name": "numberOfUsersWithBase", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "updatePerpMarketFeeAdjustment", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeAdjustment", + "type": "i16" + } + ] + }, + { + "name": "updateSpotMarketFeeAdjustment", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeAdjustment", + "type": "i16" + } + ] + }, + { + "name": "updatePerpMarketFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostPosition", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "updateSpotMarketFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostDeposits", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostBorrows", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostInsurance", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "initUserFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostDeposits", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostBorrows", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostTaker", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostInsurance", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "updateAdmin", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "admin", + "type": "publicKey" + } + ] + }, + { + "name": "updateWhitelistMint", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "whitelistMint", + "type": "publicKey" + } + ] + }, + { + "name": "updateDiscountMint", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "discountMint", + "type": "publicKey" + } + ] + }, + { + "name": "updateExchangeStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "exchangeStatus", + "type": "u8" + } + ] + }, + { + "name": "updatePerpAuctionDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "minPerpAuctionDuration", + "type": "u8" + } + ] + }, + { + "name": "updateSpotAuctionDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "defaultSpotAuctionDuration", + "type": "u8" + } + ] + }, + { + "name": "initializeProtocolIfSharesTransferConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "protocolIfSharesTransferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateProtocolIfSharesTransferConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "protocolIfSharesTransferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "whitelistedSigners", + "type": { + "option": { + "array": [ + "publicKey", + 4 + ] + } + } + }, + { + "name": "maxTransferPerEpoch", + "type": { + "option": "u128" + } + } + ] + }, + { + "name": "initializePrelaunchOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } + } + ] + }, + { + "name": "updatePrelaunchOracleParams", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } + } + ] + }, + { + "name": "deletePrelaunchOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "initializePythPullOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + ], + "accounts": [ + { + "name": "OpenbookV2FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "openbookV2ProgramId", + "type": "publicKey" + }, + { + "name": "openbookV2Market", + "type": "publicKey" + }, + { + "name": "openbookV2MarketAuthority", + "type": "publicKey" + }, + { + "name": "openbookV2EventHeap", + "type": "publicKey" + }, + { + "name": "openbookV2Bids", + "type": "publicKey" + }, + { + "name": "openbookV2Asks", + "type": "publicKey" + }, + { + "name": "openbookV2BaseVault", + "type": "publicKey" + }, + { + "name": "openbookV2QuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "PhoenixV1FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "phoenixProgramId", + "type": "publicKey" + }, + { + "name": "phoenixLogAuthority", + "type": "publicKey" + }, + { + "name": "phoenixMarket", + "type": "publicKey" + }, + { + "name": "phoenixBaseVault", + "type": "publicKey" + }, + { + "name": "phoenixQuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "SerumV3FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "serumProgramId", + "type": "publicKey" + }, + { + "name": "serumMarket", + "type": "publicKey" + }, + { + "name": "serumRequestQueue", + "type": "publicKey" + }, + { + "name": "serumEventQueue", + "type": "publicKey" + }, + { + "name": "serumBids", + "type": "publicKey" + }, + { + "name": "serumAsks", + "type": "publicKey" + }, + { + "name": "serumBaseVault", + "type": "publicKey" + }, + { + "name": "serumQuoteVault", + "type": "publicKey" + }, + { + "name": "serumOpenOrders", + "type": "publicKey" + }, + { + "name": "serumSignerNonce", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "insuranceFundStake", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "ifShares", + "type": "u128" + }, + { + "name": "lastWithdrawRequestShares", + "type": "u128" + }, + { + "name": "ifBase", + "type": "u128" + }, + { + "name": "lastValidTs", + "type": "i64" + }, + { + "name": "lastWithdrawRequestValue", + "type": "u64" + }, + { + "name": "lastWithdrawRequestTs", + "type": "i64" + }, + { + "name": "costBasis", + "type": "i64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 14 + ] + } + } + ] + } + }, + { + "name": "ProtocolIfSharesTransferConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "whitelistedSigners", + "type": { + "array": [ + "publicKey", + 4 + ] + } + }, + { + "name": "maxTransferPerEpoch", + "type": "u128" + }, + { + "name": "currentEpochTransfer", + "type": "u128" + }, + { + "name": "nextEpochTs", + "type": "i64" + }, + { + "name": "padding", + "type": { + "array": [ + "u128", + 8 + ] + } + } + ] + } + }, + { + "name": "PrelaunchOracle", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "maxPrice", + "type": "i64" + }, + { + "name": "confidence", + "type": "u64" + }, + { + "name": "lastUpdateSlot", + "type": "u64" + }, + { + "name": "ammLastUpdateSlot", + "type": "u64" + }, + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 70 + ] + } + } + ] + } + }, + { + "name": "PerpMarket", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "docs": [ + "The perp market's address. It is a pda of the market index" + ], + "type": "publicKey" + }, + { + "name": "amm", + "docs": [ + "The automated market maker" + ], + "type": { + "defined": "AMM" + } + }, + { + "name": "pnlPool", + "docs": [ + "The market's pnl pool. When users settle negative pnl, the balance increases.", + "When users settle positive pnl, the balance decreases. Can not go negative." + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "name", + "docs": [ + "Encoded display name for the perp market e.g. SOL-PERP" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "insuranceClaim", + "docs": [ + "The perp market's claim on the insurance fund" + ], + "type": { + "defined": "InsuranceClaim" + } + }, + { + "name": "unrealizedPnlMaxImbalance", + "docs": [ + "The max pnl imbalance before positive pnl asset weight is discounted", + "pnl imbalance is the difference between long and short pnl. When it's greater than 0,", + "the amm has negative pnl and the initial asset weight for positive pnl is discounted", + "precision = QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "expiryTs", + "docs": [ + "The ts when the market will be expired. Only set if market is in reduce only mode" + ], + "type": "i64" + }, + { + "name": "expiryPrice", + "docs": [ + "The price at which positions will be settled. Only set if market is expired", + "precision = PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "nextFillRecordId", + "docs": [ + "Every trade has a fill record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "nextFundingRateRecordId", + "docs": [ + "Every funding rate update has a record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "nextCurveRecordId", + "docs": [ + "Every amm k updated has a record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "imfFactor", + "docs": [ + "The initial margin fraction factor. Used to increase margin ratio for large positions", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlImfFactor", + "docs": [ + "The imf factor for unrealized pnl. Used to discount asset weight for large positive pnl", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "The fee the liquidator is paid for taking over perp position", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "docs": [ + "The fee the insurance fund receives from liquidation", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "marginRatioInitial", + "docs": [ + "The margin ratio which determines how much collateral is required to open a position", + "e.g. margin ratio of .1 means a user must have $100 of total collateral to open a $1000 position", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "docs": [ + "The margin ratio which determines when a user will be liquidated", + "e.g. margin ratio of .05 means a user must have $50 of total collateral to maintain a $1000 position", + "else they will be liquidated", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlInitialAssetWeight", + "docs": [ + "The initial asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlMaintenanceAssetWeight", + "docs": [ + "The maintenance asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "numberOfUsersWithBase", + "docs": [ + "number of users in a position (base)" + ], + "type": "u32" + }, + { + "name": "numberOfUsers", + "docs": [ + "number of users in a position (pnl) or pnl (quote)" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether a market is active, reduce only, expired, etc", + "Affects whether users can open/close positions" + ], + "type": { + "defined": "MarketStatus" + } + }, + { + "name": "contractType", + "docs": [ + "Currently only Perpetual markets are supported" + ], + "type": { + "defined": "ContractType" + } + }, + { + "name": "contractTier", + "docs": [ + "The contract tier determines how much insurance a market can receive, with more speculative markets receiving less insurance", + "It also influences the order perp markets can be liquidated, with less speculative markets being liquidated first" + ], + "type": { + "defined": "ContractTier" + } + }, + { + "name": "pausedOperations", + "type": "u8" + }, + { + "name": "quoteSpotMarketIndex", + "docs": [ + "The spot market that pnl is settled in" + ], + "type": "u16" + }, + { + "name": "feeAdjustment", + "docs": [ + "Between -100 and 100, represents what % to increase/decrease the fee by", + "E.g. if this is -50 and the fee is 5bps, the new fee will be 2.5bps", + "if this is 50 and the fee is 5bps, the new fee will be 7.5bps" + ], + "type": "i16" + }, + { + "name": "fuelBoostPosition", + "docs": [ + "fuel multiplier for perp funding", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for perp taker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for perp maker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 43 + ] + } + } + ] + } + }, + { + "name": "spotMarket", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "docs": [ + "The address of the spot market. It is a pda of the market index" + ], + "type": "publicKey" + }, + { + "name": "oracle", + "docs": [ + "The oracle used to price the markets deposits/borrows" + ], + "type": "publicKey" + }, + { + "name": "mint", + "docs": [ + "The token mint of the market" + ], + "type": "publicKey" + }, + { + "name": "vault", + "docs": [ + "The vault used to store the market's deposits", + "The amount in the vault should be equal to or greater than deposits - borrows" + ], + "type": "publicKey" + }, + { + "name": "name", + "docs": [ + "The encoded display name for the market e.g. SOL" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "historicalOracleData", + "type": { + "defined": "HistoricalOracleData" + } + }, + { + "name": "historicalIndexData", + "type": { + "defined": "HistoricalIndexData" + } + }, + { + "name": "revenuePool", + "docs": [ + "Revenue the protocol has collected in this markets token", + "e.g. for SOL-PERP, funds can be settled in usdc and will flow into the USDC revenue pool" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "spotFeePool", + "docs": [ + "The fees collected from swaps between this market and the quote market", + "Is settled to the quote markets revenue pool" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "insuranceFund", + "docs": [ + "Details on the insurance fund covering bankruptcies in this markets token", + "Covers bankruptcies for borrows with this markets token and perps settling in this markets token" + ], + "type": { + "defined": "InsuranceFund" + } + }, + { + "name": "totalSpotFee", + "docs": [ + "The total spot fees collected for this market", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "depositBalance", + "docs": [ + "The sum of the scaled balances for deposits across users and pool balances", + "To convert to the deposit token amount, multiply by the cumulative deposit interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "borrowBalance", + "docs": [ + "The sum of the scaled balances for borrows across users and pool balances", + "To convert to the borrow token amount, multiply by the cumulative borrow interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeDepositInterest", + "docs": [ + "The cumulative interest earned by depositors", + "Used to calculate the deposit token amount from the deposit balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeBorrowInterest", + "docs": [ + "The cumulative interest earned by borrowers", + "Used to calculate the borrow token amount from the borrow balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the mint's token", + "precision: token mint precision" + ], + "type": "u128" + }, + { + "name": "totalQuoteSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the quote market's token", + "preicision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "withdrawGuardThreshold", + "docs": [ + "no withdraw limits/guards when deposits below this threshold", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "maxTokenDeposits", + "docs": [ + "The max amount of token deposits in this market", + "0 if there is no limit", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "depositTokenTwap", + "docs": [ + "24hr average of deposit token amount", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "borrowTokenTwap", + "docs": [ + "24hr average of borrow token amount", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "utilizationTwap", + "docs": [ + "24hr average of utilization", + "which is borrow amount over token amount", + "precision: SPOT_UTILIZATION_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastInterestTs", + "docs": [ + "Last time the cumulative deposit and borrow interest was updated" + ], + "type": "u64" + }, + { + "name": "lastTwapTs", + "docs": [ + "Last time the deposit/borrow/utilization averages were updated" + ], + "type": "u64" + }, + { + "name": "expiryTs", + "docs": [ + "The time the market is set to expire. Only set if market is in reduce only mode" + ], + "type": "i64" + }, + { + "name": "orderStepSize", + "docs": [ + "Spot orders must be a multiple of the step size", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "orderTickSize", + "docs": [ + "Spot orders must be a multiple of the tick size", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minOrderSize", + "docs": [ + "The minimum order size", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "maxPositionSize", + "docs": [ + "The maximum spot position size", + "if the limit is 0, there is no limit", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "nextFillRecordId", + "docs": [ + "Every spot trade has a fill record id. This is the next id to use" + ], + "type": "u64" + }, + { + "name": "nextDepositRecordId", + "docs": [ + "Every deposit has a deposit record id. This is the next id to use" + ], + "type": "u64" + }, + { + "name": "initialAssetWeight", + "docs": [ + "The initial asset weight used to calculate a deposits contribution to a users initial total collateral", + "e.g. if the asset weight is .8, $100 of deposits contributes $80 to the users initial total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "docs": [ + "The maintenance asset weight used to calculate a deposits contribution to a users maintenance total collateral", + "e.g. if the asset weight is .9, $100 of deposits contributes $90 to the users maintenance total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "docs": [ + "The initial liability weight used to calculate a borrows contribution to a users initial margin requirement", + "e.g. if the liability weight is .9, $100 of borrows contributes $90 to the users initial margin requirement", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "docs": [ + "The maintenance liability weight used to calculate a borrows contribution to a users maintenance margin requirement", + "e.g. if the liability weight is .8, $100 of borrows contributes $80 to the users maintenance margin requirement", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "imfFactor", + "docs": [ + "The initial margin fraction factor. Used to increase liability weight/decrease asset weight for large positions", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "The fee the liquidator is paid for taking over borrow/deposit", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "docs": [ + "The fee the insurance fund receives from liquidation", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "optimalUtilization", + "docs": [ + "The optimal utilization rate for this market.", + "Used to determine the markets borrow rate", + "precision: SPOT_UTILIZATION_PRECISION" + ], + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "docs": [ + "The borrow rate for this market when the market has optimal utilization", + "precision: SPOT_RATE_PRECISION" + ], + "type": "u32" + }, + { + "name": "maxBorrowRate", + "docs": [ + "The borrow rate for this market when the market has 1000 utilization", + "precision: SPOT_RATE_PRECISION" + ], + "type": "u32" + }, + { + "name": "decimals", + "docs": [ + "The market's token mint's decimals. To from decimals to a precision, 10^decimals" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "ordersEnabled", + "docs": [ + "Whether or not spot trading is enabled" + ], + "type": "bool" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + }, + { + "name": "assetTier", + "docs": [ + "The asset tier affects how a deposit can be used as collateral and the priority for a borrow being liquidated" + ], + "type": { + "defined": "AssetTier" + } + }, + { + "name": "pausedOperations", + "type": "u8" + }, + { + "name": "ifPausedOperations", + "type": "u8" + }, + { + "name": "feeAdjustment", + "type": "i16" + }, + { + "name": "maxTokenBorrowsFraction", + "docs": [ + "What fraction of max_token_deposits", + "disabled when 0, 1 => 1/10000 => .01% of max_token_deposits", + "precision: X/10000" + ], + "type": "u16" + }, + { + "name": "flashLoanAmount", + "docs": [ + "For swaps, the amount of token loaned out in the begin_swap ix", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "flashLoanInitialTokenAmount", + "docs": [ + "For swaps, the amount in the users token account in the begin_swap ix", + "Used to calculate how much of the token left the system in end_swap ix", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "totalSwapFee", + "docs": [ + "The total fees received from swaps", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "scaleInitialAssetWeightStart", + "docs": [ + "When to begin scaling down the initial asset weight", + "disabled when 0", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minBorrowRate", + "docs": [ + "The min borrow rate for this market when the market regardless of utilization", + "1 => 1/200 => .5%", + "precision: X/200" + ], + "type": "u8" + }, + { + "name": "fuelBoostDeposits", + "docs": [ + "fuel multiplier for spot deposits", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostBorrows", + "docs": [ + "fuel multiplier for spot borrows", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for spot taker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for spot maker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostInsurance", + "docs": [ + "fuel multiplier for spot insurance stake", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "tokenProgram", + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 41 + ] + } + } + ] + } + }, + { + "name": "State", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "publicKey" + }, + { + "name": "whitelistMint", + "type": "publicKey" + }, + { + "name": "discountMint", + "type": "publicKey" + }, + { + "name": "signer", + "type": "publicKey" + }, + { + "name": "srmVault", + "type": "publicKey" + }, + { + "name": "perpFeeStructure", + "type": { + "defined": "FeeStructure" + } + }, + { + "name": "spotFeeStructure", + "type": { + "defined": "FeeStructure" + } + }, + { + "name": "oracleGuardRails", + "type": { + "defined": "OracleGuardRails" + } + }, + { + "name": "numberOfAuthorities", + "type": "u64" + }, + { + "name": "numberOfSubAccounts", + "type": "u64" + }, + { + "name": "lpCooldownTime", + "type": "u64" + }, + { + "name": "liquidationMarginBufferRatio", + "type": "u32" + }, + { + "name": "settlementDuration", + "type": "u16" + }, + { + "name": "numberOfMarkets", + "type": "u16" + }, + { + "name": "numberOfSpotMarkets", + "type": "u16" + }, + { + "name": "signerNonce", + "type": "u8" + }, + { + "name": "minPerpAuctionDuration", + "type": "u8" + }, + { + "name": "defaultMarketOrderTimeInForce", + "type": "u8" + }, + { + "name": "defaultSpotAuctionDuration", + "type": "u8" + }, + { + "name": "exchangeStatus", + "type": "u8" + }, + { + "name": "liquidationDuration", + "type": "u8" + }, + { + "name": "initialPctToLiquidate", + "type": "u16" + }, + { + "name": "maxNumberOfSubAccounts", + "type": "u16" + }, + { + "name": "maxInitializeUserFee", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 10 + ] + } + } + ] + } + }, + { + "name": "User", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "docs": [ + "The owner/authority of the account" + ], + "type": "publicKey" + }, + { + "name": "delegate", + "docs": [ + "An addresses that can control the account on the authority's behalf. Has limited power, cant withdraw" + ], + "type": "publicKey" + }, + { + "name": "name", + "docs": [ + "Encoded display name e.g. \"toly\"" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "spotPositions", + "docs": [ + "The user's spot positions" + ], + "type": { + "array": [ + { + "defined": "SpotPosition" + }, + 8 + ] + } + }, + { + "name": "perpPositions", + "docs": [ + "The user's perp positions" + ], + "type": { + "array": [ + { + "defined": "PerpPosition" + }, + 8 + ] + } + }, + { + "name": "orders", + "docs": [ + "The user's orders" + ], + "type": { + "array": [ + { + "defined": "Order" + }, + 32 + ] + } + }, + { + "name": "lastAddPerpLpSharesTs", + "docs": [ + "The last time the user added perp lp positions" + ], + "type": "i64" + }, + { + "name": "totalDeposits", + "docs": [ + "The total values of deposits the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalWithdraws", + "docs": [ + "The total values of withdrawals the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss the users has incurred upon the protocol", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "settledPerpPnl", + "docs": [ + "Fees (taker fees, maker rebate, referrer reward, filler reward) and pnl for perps", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "cumulativeSpotFees", + "docs": [ + "Fees (taker fees, maker rebate, filler reward) for spot", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "cumulativePerpFunding", + "docs": [ + "Cumulative funding paid/received for perps", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "liquidationMarginFreed", + "docs": [ + "The amount of margin freed during liquidation. Used to force the liquidation to occur over a period of time", + "Defaults to zero when not being liquidated", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastActiveSlot", + "docs": [ + "The last slot a user was active. Used to determine if a user is idle" + ], + "type": "u64" + }, + { + "name": "nextOrderId", + "docs": [ + "Every user order has an order id. This is the next order id to be used" + ], + "type": "u32" + }, + { + "name": "maxMarginRatio", + "docs": [ + "Custom max initial margin ratio for the user" + ], + "type": "u32" + }, + { + "name": "nextLiquidationId", + "docs": [ + "The next liquidation id to be used for user" + ], + "type": "u16" + }, + { + "name": "subAccountId", + "docs": [ + "The sub account id for this user" + ], + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether the user is active, being liquidated or bankrupt" + ], + "type": "u8" + }, + { + "name": "isMarginTradingEnabled", + "docs": [ + "Whether the user has enabled margin trading" + ], + "type": "bool" + }, + { + "name": "idle", + "docs": [ + "User is idle if they haven't interacted with the protocol in 1 week and they have no orders, perp positions or borrows", + "Off-chain keeper bots can ignore users that are idle" + ], + "type": "bool" + }, + { + "name": "openOrders", + "docs": [ + "number of open orders" + ], + "type": "u8" + }, + { + "name": "hasOpenOrder", + "docs": [ + "Whether or not user has open order" + ], + "type": "bool" + }, + { + "name": "openAuctions", + "docs": [ + "number of open orders with auction" + ], + "type": "u8" + }, + { + "name": "hasOpenAuction", + "docs": [ + "Whether or not user has open order with auction" + ], + "type": "bool" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 5 + ] + } + }, + { + "name": "lastFuelBonusUpdateTs", + "type": "u32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "UserStats", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "docs": [ + "The authority for all of a users sub accounts" + ], + "type": "publicKey" + }, + { + "name": "referrer", + "docs": [ + "The address that referred this user" + ], + "type": "publicKey" + }, + { + "name": "fees", + "docs": [ + "Stats on the fees paid by the user" + ], + "type": { + "defined": "UserFees" + } + }, + { + "name": "nextEpochTs", + "docs": [ + "The timestamp of the next epoch", + "Epoch is used to limit referrer rewards earned in single epoch" + ], + "type": "i64" + }, + { + "name": "makerVolume30d", + "docs": [ + "Rolling 30day maker volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "takerVolume30d", + "docs": [ + "Rolling 30day taker volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "fillerVolume30d", + "docs": [ + "Rolling 30day filler volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMakerVolume30dTs", + "docs": [ + "last time the maker volume was updated" + ], + "type": "i64" + }, + { + "name": "lastTakerVolume30dTs", + "docs": [ + "last time the taker volume was updated" + ], + "type": "i64" + }, + { + "name": "lastFillerVolume30dTs", + "docs": [ + "last time the filler volume was updated" + ], + "type": "i64" + }, + { + "name": "ifStakedQuoteAssetAmount", + "docs": [ + "The amount of tokens staked in the quote spot markets if" + ], + "type": "u64" + }, + { + "name": "numberOfSubAccounts", + "docs": [ + "The current number of sub accounts" + ], + "type": "u16" + }, + { + "name": "numberOfSubAccountsCreated", + "docs": [ + "The number of sub accounts created. Can be greater than the number of sub accounts if user", + "has deleted sub accounts" + ], + "type": "u16" + }, + { + "name": "isReferrer", + "docs": [ + "Whether the user is a referrer. Sub account 0 can not be deleted if user is a referrer" + ], + "type": "bool" + }, + { + "name": "disableUpdatePerpBidAskTwap", + "type": "bool" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 2 + ] + } + }, + { + "name": "fuelInsurance", + "docs": [ + "accumulated fuel for token amounts of insurance" + ], + "type": "u32" + }, + { + "name": "fuelDeposits", + "docs": [ + "accumulated fuel for notional of deposits" + ], + "type": "u32" + }, + { + "name": "fuelBorrows", + "docs": [ + "accumulate fuel bonus for notional of borrows" + ], + "type": "u32" + }, + { + "name": "fuelPositions", + "docs": [ + "accumulated fuel for perp open interest" + ], + "type": "u32" + }, + { + "name": "fuelTaker", + "docs": [ + "accumulate fuel bonus for taker volume" + ], + "type": "u32" + }, + { + "name": "fuelMaker", + "docs": [ + "accumulate fuel bonus for maker volume" + ], + "type": "u32" + }, + { + "name": "ifStakedGovTokenAmount", + "docs": [ + "The amount of tokens staked in the governance spot markets if" + ], + "type": "u64" + }, + { + "name": "lastFuelIfBonusUpdateTs", + "docs": [ + "last unix ts user stats data was used to update if fuel (u32 to save space)" + ], + "type": "u32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "ReferrerName", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "user", + "type": "publicKey" + }, + { + "name": "userStats", + "type": "publicKey" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "UpdatePerpMarketSummaryStatsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quoteAssetAmountWithUnsettledLp", + "type": { + "option": "i64" + } + }, + { + "name": "netUnsettledFundingPnl", + "type": { + "option": "i64" + } + }, + { + "name": "updateAmmSummaryStats", + "type": { + "option": "bool" + } + } + ] + } + }, + { + "name": "LiquidatePerpRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "oraclePrice", + "type": "i64" + }, + { + "name": "baseAssetAmount", + "type": "i64" + }, + { + "name": "quoteAssetAmount", + "type": "i64" + }, + { + "name": "lpShares", + "docs": [ + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u64" + }, + { + "name": "fillRecordId", + "type": "u64" + }, + { + "name": "userOrderId", + "type": "u32" + }, + { + "name": "liquidatorOrderId", + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "ifFee", + "docs": [ + "precision: QUOTE_PRECISION" + ], + "type": "u64" + } + ] + } + }, + { + "name": "LiquidateSpotRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "assetPrice", + "type": "i64" + }, + { + "name": "assetTransfer", + "type": "u128" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liabilityPrice", + "type": "i64" + }, + { + "name": "liabilityTransfer", + "docs": [ + "precision: token mint precision" + ], + "type": "u128" + }, + { + "name": "ifFee", + "docs": [ + "precision: token mint precision" + ], + "type": "u64" + } + ] + } + }, + { + "name": "LiquidateBorrowForPerpPnlRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "marketOraclePrice", + "type": "i64" + }, + { + "name": "pnlTransfer", + "type": "u128" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liabilityPrice", + "type": "i64" + }, + { + "name": "liabilityTransfer", + "type": "u128" + } + ] + } + }, + { + "name": "LiquidatePerpPnlForDepositRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "marketOraclePrice", + "type": "i64" + }, + { + "name": "pnlTransfer", + "type": "u128" + }, + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "assetPrice", + "type": "i64" + }, + { + "name": "assetTransfer", + "type": "u128" + } + ] + } + }, + { + "name": "PerpBankruptcyRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "pnl", + "type": "i128" + }, + { + "name": "ifPayment", + "type": "u128" + }, + { + "name": "clawbackUser", + "type": { + "option": "publicKey" + } + }, + { + "name": "clawbackUserPayment", + "type": { + "option": "u128" + } + }, + { + "name": "cumulativeFundingRateDelta", + "type": "i128" + } + ] + } + }, + { + "name": "SpotBankruptcyRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "borrowAmount", + "type": "u128" + }, + { + "name": "ifPayment", + "type": "u128" + }, + { + "name": "cumulativeDepositInterestDelta", + "type": "u128" + } + ] + } + }, + { + "name": "MarketIdentifier", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketType", + "type": { + "defined": "MarketType" + } + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + } + }, + { + "name": "HistoricalOracleData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastOraclePrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOracleConf", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastOracleDelay", + "docs": [ + "number of slots since last update" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwap", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwap5min", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwapTs", + "docs": [ + "unix_timestamp of last snapshot" + ], + "type": "i64" + } + ] + } + }, + { + "name": "HistoricalIndexData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastIndexBidPrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexAskPrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwap", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwap5min", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwapTs", + "docs": [ + "unix_timestamp of last snapshot" + ], + "type": "i64" + } + ] + } + }, + { + "name": "PrelaunchOracleParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "price", + "type": { + "option": "i64" + } + }, + { + "name": "maxPrice", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "OrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "orderType", + "type": { + "defined": "OrderType" + } + }, + { + "name": "marketType", + "type": { + "defined": "MarketType" + } + }, + { + "name": "direction", + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "userOrderId", + "type": "u8" + }, + { + "name": "baseAssetAmount", + "type": "u64" + }, + { + "name": "price", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "reduceOnly", + "type": "bool" + }, + { + "name": "postOnly", + "type": { + "defined": "PostOnlyParam" + } + }, + { + "name": "immediateOrCancel", + "type": "bool" + }, + { + "name": "maxTs", + "type": { + "option": "i64" + } + }, + { + "name": "triggerPrice", + "type": { + "option": "u64" + } + }, + { + "name": "triggerCondition", + "type": { + "defined": "OrderTriggerCondition" + } + }, + { + "name": "oraclePriceOffset", + "type": { + "option": "i32" + } + }, + { + "name": "auctionDuration", + "type": { + "option": "u8" + } + }, + { + "name": "auctionStartPrice", + "type": { + "option": "i64" + } + }, + { + "name": "auctionEndPrice", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "ModifyOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "direction", + "type": { + "option": { + "defined": "PositionDirection" + } + } + }, + { + "name": "baseAssetAmount", + "type": { + "option": "u64" + } + }, + { + "name": "price", + "type": { + "option": "u64" + } + }, + { + "name": "reduceOnly", + "type": { + "option": "bool" + } + }, + { + "name": "postOnly", + "type": { + "option": { + "defined": "PostOnlyParam" + } + } + }, + { + "name": "immediateOrCancel", + "type": { + "option": "bool" + } + }, + { + "name": "maxTs", + "type": { + "option": "i64" + } + }, + { + "name": "triggerPrice", + "type": { + "option": "u64" + } + }, + { + "name": "triggerCondition", + "type": { + "option": { + "defined": "OrderTriggerCondition" + } + } + }, + { + "name": "oraclePriceOffset", + "type": { + "option": "i32" + } + }, + { + "name": "auctionDuration", + "type": { + "option": "u8" + } + }, + { + "name": "auctionStartPrice", + "type": { + "option": "i64" + } + }, + { + "name": "auctionEndPrice", + "type": { + "option": "i64" + } + }, + { + "name": "policy", + "type": { + "option": { + "defined": "ModifyOrderPolicy" + } + } + } + ] + } + }, + { + "name": "InsuranceClaim", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revenueWithdrawSinceLastSettle", + "docs": [ + "The amount of revenue last settled", + "Positive if funds left the perp market,", + "negative if funds were pulled into the perp market", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "docs": [ + "The max amount of revenue that can be withdrawn per period", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "docs": [ + "The max amount of insurance that perp market can use to resolve bankruptcy and pnl deficits", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "quoteSettledInsurance", + "docs": [ + "The amount of insurance that has been used to resolve bankruptcy and pnl deficits", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastRevenueWithdrawTs", + "docs": [ + "The last time revenue was settled in/out of market" + ], + "type": "i64" + } + ] + } + }, + { + "name": "PoolBalance", + "type": { + "kind": "struct", + "fields": [ + { + "name": "scaledBalance", + "docs": [ + "To get the pool's token amount, you must multiply the scaled balance by the market's cumulative", + "deposit interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "marketIndex", + "docs": [ + "The spot market the pool is for" + ], + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 6 + ] + } + } + ] + } + }, + { + "name": "AMM", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oracle", + "docs": [ + "oracle price data public key" + ], + "type": "publicKey" + }, + { + "name": "historicalOracleData", + "docs": [ + "stores historically witnessed oracle data" + ], + "type": { + "defined": "HistoricalOracleData" + } + }, + { + "name": "baseAssetAmountPerLp", + "docs": [ + "accumulated base asset amount since inception per lp share", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteAssetAmountPerLp", + "docs": [ + "accumulated quote asset amount since inception per lp share", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "feePool", + "docs": [ + "partition of fees from perp market trading moved from pnl settlements" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "baseAssetReserve", + "docs": [ + "`x` reserves for constant product mm formula (x * y = k)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "quoteAssetReserve", + "docs": [ + "`y` reserves for constant product mm formula (x * y = k)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "concentrationCoef", + "docs": [ + "determines how close the min/max base asset reserve sit vs base reserves", + "allow for decreasing slippage without increasing liquidity and v.v.", + "precision: PERCENTAGE_PRECISION" + ], + "type": "u128" + }, + { + "name": "minBaseAssetReserve", + "docs": [ + "minimum base_asset_reserve allowed before AMM is unavailable", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "maxBaseAssetReserve", + "docs": [ + "maximum base_asset_reserve allowed before AMM is unavailable", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "sqrtK", + "docs": [ + "`sqrt(k)` in constant product mm formula (x * y = k). stored to avoid drift caused by integer math issues", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "pegMultiplier", + "docs": [ + "normalizing numerical factor for y, its use offers lowest slippage in cp-curve when market is balanced", + "precision: PEG_PRECISION" + ], + "type": "u128" + }, + { + "name": "terminalQuoteAssetReserve", + "docs": [ + "y when market is balanced. stored to save computation", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "baseAssetAmountLong", + "docs": [ + "always non-negative. tracks number of total longs in market (regardless of counterparty)", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountShort", + "docs": [ + "always non-positive. tracks number of total shorts in market (regardless of counterparty)", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountWithAmm", + "docs": [ + "tracks net position (longs-shorts) in market with AMM as counterparty", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountWithUnsettledLp", + "docs": [ + "tracks net position (longs-shorts) in market with LPs as counterparty", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "maxOpenInterest", + "docs": [ + "max allowed open interest, blocks trades that breach this value", + "precision: BASE_PRECISION" + ], + "type": "u128" + }, + { + "name": "quoteAssetAmount", + "docs": [ + "sum of all user's perp quote_asset_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteEntryAmountLong", + "docs": [ + "sum of all long user's quote_entry_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteEntryAmountShort", + "docs": [ + "sum of all short user's quote_entry_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteBreakEvenAmountLong", + "docs": [ + "sum of all long user's quote_break_even_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteBreakEvenAmountShort", + "docs": [ + "sum of all short user's quote_break_even_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "userLpShares", + "docs": [ + "total user lp shares of sqrt_k (protocol owned liquidity = sqrt_k - last_funding_rate)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "lastFundingRate", + "docs": [ + "last funding rate in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateLong", + "docs": [ + "last funding rate for longs in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateShort", + "docs": [ + "last funding rate for shorts in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "last24hAvgFundingRate", + "docs": [ + "estimate of last 24h of funding rate perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "totalFee", + "docs": [ + "total fees collected by this perp market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalMmFee", + "docs": [ + "total fees collected by the vAMM's bid/ask spread", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalExchangeFee", + "docs": [ + "total fees collected by exchange fee schedule", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalFeeMinusDistributions", + "docs": [ + "total fees minus any recognized upnl and pool withdraws", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalFeeWithdrawn", + "docs": [ + "sum of all fees from fee pool withdrawn to revenue pool", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalLiquidationFee", + "docs": [ + "all fees collected by market for liquidations", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeFundingRateLong", + "docs": [ + "accumulated funding rate for longs since inception in market" + ], + "type": "i128" + }, + { + "name": "cumulativeFundingRateShort", + "docs": [ + "accumulated funding rate for shorts since inception in market" + ], + "type": "i128" + }, + { + "name": "totalSocialLoss", + "docs": [ + "accumulated social loss paid by users since inception in market" + ], + "type": "u128" + }, + { + "name": "askBaseAssetReserve", + "docs": [ + "transformed base_asset_reserve for users going long", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "askQuoteAssetReserve", + "docs": [ + "transformed quote_asset_reserve for users going long", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "bidBaseAssetReserve", + "docs": [ + "transformed base_asset_reserve for users going short", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "bidQuoteAssetReserve", + "docs": [ + "transformed quote_asset_reserve for users going short", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "lastOracleNormalisedPrice", + "docs": [ + "the last seen oracle price partially shrunk toward the amm reserve price", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOracleReservePriceSpreadPct", + "docs": [ + "the gap between the oracle price and the reserve price = y * peg_multiplier / x" + ], + "type": "i64" + }, + { + "name": "lastBidPriceTwap", + "docs": [ + "average estimate of bid price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastAskPriceTwap", + "docs": [ + "average estimate of ask price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwap", + "docs": [ + "average estimate of (bid+ask)/2 price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwap5min", + "docs": [ + "average estimate of (bid+ask)/2 price over FIVE_MINUTES" + ], + "type": "u64" + }, + { + "name": "lastUpdateSlot", + "docs": [ + "the last blockchain slot the amm was updated" + ], + "type": "u64" + }, + { + "name": "lastOracleConfPct", + "docs": [ + "the pct size of the oracle confidence interval", + "precision: PERCENTAGE_PRECISION" + ], + "type": "u64" + }, + { + "name": "netRevenueSinceLastFunding", + "docs": [ + "the total_fee_minus_distribution change since the last funding update", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateTs", + "docs": [ + "the last funding rate update unix_timestamp" + ], + "type": "i64" + }, + { + "name": "fundingPeriod", + "docs": [ + "the peridocity of the funding rate updates" + ], + "type": "i64" + }, + { + "name": "orderStepSize", + "docs": [ + "the base step size (increment) of orders", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "orderTickSize", + "docs": [ + "the price tick size of orders", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minOrderSize", + "docs": [ + "the minimum base size of an order", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "maxPositionSize", + "docs": [ + "the max base size a single user can have", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "volume24h", + "docs": [ + "estimated total of volume in market", + "QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "longIntensityVolume", + "docs": [ + "the volume intensity of long fills against AMM" + ], + "type": "u64" + }, + { + "name": "shortIntensityVolume", + "docs": [ + "the volume intensity of short fills against AMM" + ], + "type": "u64" + }, + { + "name": "lastTradeTs", + "docs": [ + "the blockchain unix timestamp at the time of the last trade" + ], + "type": "i64" + }, + { + "name": "markStd", + "docs": [ + "estimate of standard deviation of the fill (mark) prices", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "oracleStd", + "docs": [ + "estimate of standard deviation of the oracle price at each update", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwapTs", + "docs": [ + "the last unix_timestamp the mark twap was updated" + ], + "type": "i64" + }, + { + "name": "baseSpread", + "docs": [ + "the minimum spread the AMM can quote. also used as step size for some spread logic increases." + ], + "type": "u32" + }, + { + "name": "maxSpread", + "docs": [ + "the maximum spread the AMM can quote" + ], + "type": "u32" + }, + { + "name": "longSpread", + "docs": [ + "the spread for asks vs the reserve price" + ], + "type": "u32" + }, + { + "name": "shortSpread", + "docs": [ + "the spread for bids vs the reserve price" + ], + "type": "u32" + }, + { + "name": "longIntensityCount", + "docs": [ + "the count intensity of long fills against AMM" + ], + "type": "u32" + }, + { + "name": "shortIntensityCount", + "docs": [ + "the count intensity of short fills against AMM" + ], + "type": "u32" + }, + { + "name": "maxFillReserveFraction", + "docs": [ + "the fraction of total available liquidity a single fill on the AMM can consume" + ], + "type": "u16" + }, + { + "name": "maxSlippageRatio", + "docs": [ + "the maximum slippage a single fill on the AMM can push" + ], + "type": "u16" + }, + { + "name": "curveUpdateIntensity", + "docs": [ + "the update intensity of AMM formulaic updates (adjusting k). 0-100" + ], + "type": "u8" + }, + { + "name": "ammJitIntensity", + "docs": [ + "the jit intensity of AMM. larger intensity means larger participation in jit. 0 means no jit participation.", + "(0, 100] is intensity for protocol-owned AMM. (100, 200] is intensity for user LP-owned AMM." + ], + "type": "u8" + }, + { + "name": "oracleSource", + "docs": [ + "the oracle provider information. used to decode/scale the oracle public key" + ], + "type": { + "defined": "OracleSource" + } + }, + { + "name": "lastOracleValid", + "docs": [ + "tracks whether the oracle was considered valid at the last AMM update" + ], + "type": "bool" + }, + { + "name": "targetBaseAssetAmountPerLp", + "docs": [ + "the target value for `base_asset_amount_per_lp`, used during AMM JIT with LP split", + "precision: BASE_PRECISION" + ], + "type": "i32" + }, + { + "name": "perLpBase", + "docs": [ + "expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)" + ], + "type": "i8" + }, + { + "name": "padding1", + "type": "u8" + }, + { + "name": "padding2", + "type": "u16" + }, + { + "name": "totalFeeEarnedPerLp", + "type": "u64" + }, + { + "name": "netUnsettledFundingPnl", + "type": "i64" + }, + { + "name": "quoteAssetAmountWithUnsettledLp", + "type": "i64" + }, + { + "name": "referencePriceOffset", + "type": "i32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "InsuranceFund", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "totalShares", + "type": "u128" + }, + { + "name": "userShares", + "type": "u128" + }, + { + "name": "sharesBase", + "type": "u128" + }, + { + "name": "unstakingPeriod", + "type": "i64" + }, + { + "name": "lastRevenueSettleTs", + "type": "i64" + }, + { + "name": "revenueSettlePeriod", + "type": "i64" + }, + { + "name": "totalFactor", + "type": "u32" + }, + { + "name": "userFactor", + "type": "u32" + } + ] + } + }, + { + "name": "OracleGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "priceDivergence", + "type": { + "defined": "PriceDivergenceGuardRails" + } + }, + { + "name": "validity", + "type": { + "defined": "ValidityGuardRails" + } + } + ] + } + }, + { + "name": "PriceDivergenceGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "markOraclePercentDivergence", + "type": "u64" + }, + { + "name": "oracleTwap5minPercentDivergence", + "type": "u64" + } + ] + } + }, + { + "name": "ValidityGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "slotsBeforeStaleForAmm", + "type": "i64" + }, + { + "name": "slotsBeforeStaleForMargin", + "type": "i64" + }, + { + "name": "confidenceIntervalMaxSize", + "type": "u64" + }, + { + "name": "tooVolatileRatio", + "type": "i64" + } + ] + } + }, + { + "name": "FeeStructure", + "type": { + "kind": "struct", + "fields": [ + { + "name": "feeTiers", + "type": { + "array": [ + { + "defined": "FeeTier" + }, + 10 + ] + } + }, + { + "name": "fillerRewardStructure", + "type": { + "defined": "OrderFillerRewardStructure" + } + }, + { + "name": "referrerRewardEpochUpperBound", + "type": "u64" + }, + { + "name": "flatFillerFee", + "type": "u64" + } + ] + } + }, + { + "name": "FeeTier", + "type": { + "kind": "struct", + "fields": [ + { + "name": "feeNumerator", + "type": "u32" + }, + { + "name": "feeDenominator", + "type": "u32" + }, + { + "name": "makerRebateNumerator", + "type": "u32" + }, + { + "name": "makerRebateDenominator", + "type": "u32" + }, + { + "name": "referrerRewardNumerator", + "type": "u32" + }, + { + "name": "referrerRewardDenominator", + "type": "u32" + }, + { + "name": "refereeFeeNumerator", + "type": "u32" + }, + { + "name": "refereeFeeDenominator", + "type": "u32" + } + ] + } + }, + { + "name": "OrderFillerRewardStructure", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rewardNumerator", + "type": "u32" + }, + { + "name": "rewardDenominator", + "type": "u32" + }, + { + "name": "timeBasedRewardLowerBound", + "type": "u128" + } + ] + } + }, + { + "name": "UserFees", + "type": { + "kind": "struct", + "fields": [ + { + "name": "totalFeePaid", + "docs": [ + "Total taker fee paid", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalFeeRebate", + "docs": [ + "Total maker fee rebate", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalTokenDiscount", + "docs": [ + "Total discount from holding token", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalRefereeDiscount", + "docs": [ + "Total discount from being referred", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalReferrerReward", + "docs": [ + "Total reward to referrer", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "currentEpochReferrerReward", + "docs": [ + "Total reward to referrer this epoch", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + } + ] + } + }, + { + "name": "SpotPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "scaledBalance", + "docs": [ + "The scaled balance of the position. To get the token amount, multiply by the cumulative deposit/borrow", + "interest of corresponding market.", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u64" + }, + { + "name": "openBids", + "docs": [ + "How many spot bids the user has open", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "openAsks", + "docs": [ + "How many spot asks the user has open", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "cumulativeDeposits", + "docs": [ + "The cumulative deposits/borrows a user has made into a market", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "marketIndex", + "docs": [ + "The market index of the corresponding spot market" + ], + "type": "u16" + }, + { + "name": "balanceType", + "docs": [ + "Whether the position is deposit or borrow" + ], + "type": { + "defined": "SpotBalanceType" + } + }, + { + "name": "openOrders", + "docs": [ + "Number of open orders" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "PerpPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastCumulativeFundingRate", + "docs": [ + "The perp market's last cumulative funding rate. Used to calculate the funding payment owed to user", + "precision: FUNDING_RATE_PRECISION" + ], + "type": "i64" + }, + { + "name": "baseAssetAmount", + "docs": [ + "the size of the users perp position", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteAssetAmount", + "docs": [ + "Used to calculate the users pnl. Upon entry, is equal to base_asset_amount * avg entry price - fees", + "Updated when the user open/closes position or settles pnl. Includes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteBreakEvenAmount", + "docs": [ + "The amount of quote the user would need to exit their position at to break even", + "Updated when the user open/closes position or settles pnl. Includes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteEntryAmount", + "docs": [ + "The amount quote the user entered the position with. Equal to base asset amount * avg entry price", + "Updated when the user open/closes position. Excludes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "openBids", + "docs": [ + "The amount of open bids the user has in this perp market", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "openAsks", + "docs": [ + "The amount of open asks the user has in this perp market", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "settledPnl", + "docs": [ + "The amount of pnl settled in this market since opening the position", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lpShares", + "docs": [ + "The number of lp (liquidity provider) shares the user has in this perp market", + "LP shares allow users to provide liquidity via the AMM", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastBaseAssetAmountPerLp", + "docs": [ + "The last base asset amount per lp the amm had", + "Used to settle the users lp position", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastQuoteAssetAmountPerLp", + "docs": [ + "The last quote asset amount per lp the amm had", + "Used to settle the users lp position", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "remainderBaseAssetAmount", + "docs": [ + "Settling LP position can lead to a small amount of base asset being left over smaller than step size", + "This records that remainder so it can be settled later on", + "precision: BASE_PRECISION" + ], + "type": "i32" + }, + { + "name": "marketIndex", + "docs": [ + "The market index for the perp market" + ], + "type": "u16" + }, + { + "name": "openOrders", + "docs": [ + "The number of open orders" + ], + "type": "u8" + }, + { + "name": "perLpBase", + "type": "i8" + } + ] + } + }, + { + "name": "Order", + "type": { + "kind": "struct", + "fields": [ + { + "name": "slot", + "docs": [ + "The slot the order was placed" + ], + "type": "u64" + }, + { + "name": "price", + "docs": [ + "The limit price for the order (can be 0 for market orders)", + "For orders with an auction, this price isn't used until the auction is complete", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "baseAssetAmount", + "docs": [ + "The size of the order", + "precision for perps: BASE_PRECISION", + "precision for spot: token mint precision" + ], + "type": "u64" + }, + { + "name": "baseAssetAmountFilled", + "docs": [ + "The amount of the order filled", + "precision for perps: BASE_PRECISION", + "precision for spot: token mint precision" + ], + "type": "u64" + }, + { + "name": "quoteAssetAmountFilled", + "docs": [ + "The amount of quote filled for the order", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "triggerPrice", + "docs": [ + "At what price the order will be triggered. Only relevant for trigger orders", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "auctionStartPrice", + "docs": [ + "The start price for the auction. Only relevant for market/oracle orders", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "auctionEndPrice", + "docs": [ + "The end price for the auction. Only relevant for market/oracle orders", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "maxTs", + "docs": [ + "The time when the order will expire" + ], + "type": "i64" + }, + { + "name": "oraclePriceOffset", + "docs": [ + "If set, the order limit price is the oracle price + this offset", + "precision: PRICE_PRECISION" + ], + "type": "i32" + }, + { + "name": "orderId", + "docs": [ + "The id for the order. Each users has their own order id space" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "docs": [ + "The perp/spot market index" + ], + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether the order is open or unused" + ], + "type": { + "defined": "OrderStatus" + } + }, + { + "name": "orderType", + "docs": [ + "The type of order" + ], + "type": { + "defined": "OrderType" + } + }, + { + "name": "marketType", + "docs": [ + "Whether market is spot or perp" + ], + "type": { + "defined": "MarketType" + } + }, + { + "name": "userOrderId", + "docs": [ + "User generated order id. Can make it easier to place/cancel orders" + ], + "type": "u8" + }, + { + "name": "existingPositionDirection", + "docs": [ + "What the users position was when the order was placed" + ], + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "direction", + "docs": [ + "Whether the user is going long or short. LONG = bid, SHORT = ask" + ], + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "reduceOnly", + "docs": [ + "Whether the order is allowed to only reduce position size" + ], + "type": "bool" + }, + { + "name": "postOnly", + "docs": [ + "Whether the order must be a maker" + ], + "type": "bool" + }, + { + "name": "immediateOrCancel", + "docs": [ + "Whether the order must be canceled the same slot it is placed" + ], + "type": "bool" + }, + { + "name": "triggerCondition", + "docs": [ + "Whether the order is triggered above or below the trigger price. Only relevant for trigger orders" + ], + "type": { + "defined": "OrderTriggerCondition" + } + }, + { + "name": "auctionDuration", + "docs": [ + "How many slots the auction lasts" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 3 + ] + } + } + ] + } + }, + { + "name": "SwapDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Add" + }, + { + "name": "Remove" + } + ] + } + }, + { + "name": "ModifyOrderId", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UserOrderId", + "fields": [ + "u8" + ] + }, + { + "name": "OrderId", + "fields": [ + "u32" + ] + } + ] + } + }, + { + "name": "PositionDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Long" + }, + { + "name": "Short" + } + ] + } + }, + { + "name": "SpotFulfillmentType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "SerumV3" + }, + { + "name": "Match" + }, + { + "name": "PhoenixV1" + }, + { + "name": "OpenbookV2" + } + ] + } + }, + { + "name": "SwapReduceOnly", + "type": { + "kind": "enum", + "variants": [ + { + "name": "In" + }, + { + "name": "Out" + } + ] + } + }, + { + "name": "TwapPeriod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "FundingPeriod" + }, + { + "name": "FiveMin" + } + ] + } + }, + { + "name": "LiquidationMultiplierType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Discount" + }, + { + "name": "Premium" + } + ] + } + }, + { + "name": "MarginRequirementType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Initial" + }, + { + "name": "Fill" + }, + { + "name": "Maintenance" + } + ] + } + }, + { + "name": "OracleValidity", + "type": { + "kind": "enum", + "variants": [ + { + "name": "NonPositive" + }, + { + "name": "TooVolatile" + }, + { + "name": "TooUncertain" + }, + { + "name": "StaleForMargin" + }, + { + "name": "InsufficientDataPoints" + }, + { + "name": "StaleForAMM" + }, + { + "name": "Valid" + } + ] + } + }, + { + "name": "DriftAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateFunding" + }, + { + "name": "SettlePnl" + }, + { + "name": "TriggerOrder" + }, + { + "name": "FillOrderMatch" + }, + { + "name": "FillOrderAmm" + }, + { + "name": "Liquidate" + }, + { + "name": "MarginCalc" + }, + { + "name": "UpdateTwap" + }, + { + "name": "UpdateAMMCurve" + }, + { + "name": "OracleOrderPrice" + } + ] + } + }, + { + "name": "PositionUpdateType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Open" + }, + { + "name": "Increase" + }, + { + "name": "Reduce" + }, + { + "name": "Close" + }, + { + "name": "Flip" + } + ] + } + }, + { + "name": "DepositExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "Transfer" + }, + { + "name": "Borrow" + }, + { + "name": "RepayBorrow" + } + ] + } + }, + { + "name": "DepositDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Deposit" + }, + { + "name": "Withdraw" + } + ] + } + }, + { + "name": "OrderAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Place" + }, + { + "name": "Cancel" + }, + { + "name": "Fill" + }, + { + "name": "Trigger" + }, + { + "name": "Expire" + } + ] + } + }, + { + "name": "OrderActionExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "InsufficientFreeCollateral" + }, + { + "name": "OraclePriceBreachedLimitPrice" + }, + { + "name": "MarketOrderFilledToLimitPrice" + }, + { + "name": "OrderExpired" + }, + { + "name": "Liquidation" + }, + { + "name": "OrderFilledWithAMM" + }, + { + "name": "OrderFilledWithAMMJit" + }, + { + "name": "OrderFilledWithMatch" + }, + { + "name": "OrderFilledWithMatchJit" + }, + { + "name": "MarketExpired" + }, + { + "name": "RiskingIncreasingOrder" + }, + { + "name": "ReduceOnlyOrderIncreasedPosition" + }, + { + "name": "OrderFillWithSerum" + }, + { + "name": "NoBorrowLiquidity" + }, + { + "name": "OrderFillWithPhoenix" + }, + { + "name": "OrderFilledWithAMMJitLPSplit" + }, + { + "name": "OrderFilledWithLPJit" + }, + { + "name": "DeriskLp" + }, + { + "name": "OrderFilledWithOpenbookV2" + } + ] + } + }, + { + "name": "LPAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AddLiquidity" + }, + { + "name": "RemoveLiquidity" + }, + { + "name": "SettleLiquidity" + }, + { + "name": "RemoveLiquidityDerisk" + } + ] + } + }, + { + "name": "LiquidationType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "LiquidatePerp" + }, + { + "name": "LiquidateSpot" + }, + { + "name": "LiquidateBorrowForPerpPnl" + }, + { + "name": "LiquidatePerpPnlForDeposit" + }, + { + "name": "PerpBankruptcy" + }, + { + "name": "SpotBankruptcy" + } + ] + } + }, + { + "name": "SettlePnlExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "ExpiredPosition" + } + ] + } + }, + { + "name": "StakeAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Stake" + }, + { + "name": "UnstakeRequest" + }, + { + "name": "UnstakeCancelRequest" + }, + { + "name": "Unstake" + }, + { + "name": "UnstakeTransfer" + }, + { + "name": "StakeTransfer" + } + ] + } + }, + { + "name": "FillMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Fill" + }, + { + "name": "PlaceAndMake" + }, + { + "name": "PlaceAndTake" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "PerpFulfillmentMethod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AMM", + "fields": [ + { + "option": "u64" + } + ] + }, + { + "name": "Match", + "fields": [ + "publicKey", + "u16" + ] + } + ] + } + }, + { + "name": "SpotFulfillmentMethod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ExternalMarket" + }, + { + "name": "Match", + "fields": [ + "publicKey", + "u16" + ] + } + ] + } + }, + { + "name": "MarginCalculationMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Standard", + "fields": [ + { + "name": "trackOpenOrdersFraction", + "type": "bool" + } + ] + }, + { + "name": "Liquidation", + "fields": [ + { + "name": "marketToTrackMarginRequirement", + "type": { + "option": { + "defined": "MarketIdentifier" + } + } + } + ] + } + ] + } + }, + { + "name": "OracleSource", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Pyth" + }, + { + "name": "Switchboard" + }, + { + "name": "QuoteAsset" + }, + { + "name": "Pyth1K" + }, + { + "name": "Pyth1M" + }, + { + "name": "PythStableCoin" + }, + { + "name": "Prelaunch" + }, + { + "name": "PythPull" + }, + { + "name": "Pyth1KPull" + }, + { + "name": "Pyth1MPull" + }, + { + "name": "PythStableCoinPull" + }, + { + "name": "SwitchboardOnDemand" + } + ] + } + }, + { + "name": "PostOnlyParam", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "MustPostOnly" + }, + { + "name": "TryPostOnly" + }, + { + "name": "Slide" + } + ] + } + }, + { + "name": "ModifyOrderPolicy", + "type": { + "kind": "enum", + "variants": [ + { + "name": "TryModify" + }, + { + "name": "MustModify" + } + ] + } + }, + { + "name": "PerpOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateFunding" + }, + { + "name": "AmmFill" + }, + { + "name": "Fill" + }, + { + "name": "SettlePnl" + }, + { + "name": "SettlePnlWithPosition" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "SpotOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateCumulativeInterest" + }, + { + "name": "Fill" + }, + { + "name": "Deposit" + }, + { + "name": "Withdraw" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "InsuranceFundOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Init" + }, + { + "name": "Add" + }, + { + "name": "RequestRemove" + }, + { + "name": "Remove" + } + ] + } + }, + { + "name": "MarketStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Initialized" + }, + { + "name": "Active" + }, + { + "name": "FundingPaused" + }, + { + "name": "AmmPaused" + }, + { + "name": "FillPaused" + }, + { + "name": "WithdrawPaused" + }, + { + "name": "ReduceOnly" + }, + { + "name": "Settlement" + }, + { + "name": "Delisted" + } + ] + } + }, + { + "name": "ContractType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Perpetual" + }, + { + "name": "Future" + }, + { + "name": "Prediction" + } + ] + } + }, + { + "name": "ContractTier", + "type": { + "kind": "enum", + "variants": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "C" + }, + { + "name": "Speculative" + }, + { + "name": "HighlySpeculative" + }, + { + "name": "Isolated" + } + ] + } + }, + { + "name": "AMMLiquiditySplit", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ProtocolOwned" + }, + { + "name": "LPOwned" + }, + { + "name": "Shared" + } + ] + } + }, + { + "name": "SettlePnlMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "MustSettle" + }, + { + "name": "TrySettle" + } + ] + } + }, + { + "name": "SpotBalanceType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Deposit" + }, + { + "name": "Borrow" + } + ] + } + }, + { + "name": "SpotFulfillmentConfigStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Enabled" + }, + { + "name": "Disabled" + } + ] + } + }, + { + "name": "AssetTier", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Collateral" + }, + { + "name": "Protected" + }, + { + "name": "Cross" + }, + { + "name": "Isolated" + }, + { + "name": "Unlisted" + } + ] + } + }, + { + "name": "ExchangeStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "DepositPaused" + }, + { + "name": "WithdrawPaused" + }, + { + "name": "AmmPaused" + }, + { + "name": "FillPaused" + }, + { + "name": "LiqPaused" + }, + { + "name": "FundingPaused" + }, + { + "name": "SettlePnlPaused" + } + ] + } + }, + { + "name": "UserStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "BeingLiquidated" + }, + { + "name": "Bankrupt" + }, + { + "name": "ReduceOnly" + }, + { + "name": "AdvancedLp" + } + ] + } + }, + { + "name": "AssetType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Base" + }, + { + "name": "Quote" + } + ] + } + }, + { + "name": "OrderStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Init" + }, + { + "name": "Open" + }, + { + "name": "Filled" + }, + { + "name": "Canceled" + } + ] + } + }, + { + "name": "OrderType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Market" + }, + { + "name": "Limit" + }, + { + "name": "TriggerMarket" + }, + { + "name": "TriggerLimit" + }, + { + "name": "Oracle" + } + ] + } + }, + { + "name": "OrderTriggerCondition", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Above" + }, + { + "name": "Below" + }, + { + "name": "TriggeredAbove" + }, + { + "name": "TriggeredBelow" + } + ] + } + }, + { + "name": "MarketType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Spot" + }, + { + "name": "Perp" + } + ] + } + } + ], + "events": [ + { + "name": "NewUserRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "subAccountId", + "type": "u16", + "index": false + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + }, + "index": false + }, + { + "name": "referrer", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "DepositRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "direction", + "type": { + "defined": "DepositDirection" + }, + "index": false + }, + { + "name": "depositRecordId", + "type": "u64", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + }, + { + "name": "marketDepositBalance", + "type": "u128", + "index": false + }, + { + "name": "marketWithdrawBalance", + "type": "u128", + "index": false + }, + { + "name": "marketCumulativeDepositInterest", + "type": "u128", + "index": false + }, + { + "name": "marketCumulativeBorrowInterest", + "type": "u128", + "index": false + }, + { + "name": "totalDepositsAfter", + "type": "u64", + "index": false + }, + { + "name": "totalWithdrawsAfter", + "type": "u64", + "index": false + }, + { + "name": "explanation", + "type": { + "defined": "DepositExplanation" + }, + "index": false + }, + { + "name": "transferUser", + "type": { + "option": "publicKey" + }, + "index": false + } + ] + }, + { + "name": "SpotInterestRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "depositBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterest", + "type": "u128", + "index": false + }, + { + "name": "borrowBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeBorrowInterest", + "type": "u128", + "index": false + }, + { + "name": "optimalUtilization", + "type": "u32", + "index": false + }, + { + "name": "optimalBorrowRate", + "type": "u32", + "index": false + }, + { + "name": "maxBorrowRate", + "type": "u32", + "index": false + } + ] + }, + { + "name": "FundingPaymentRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "fundingPayment", + "type": "i64", + "index": false + }, + { + "name": "baseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "userLastCumulativeFunding", + "type": "i64", + "index": false + }, + { + "name": "ammCumulativeFundingLong", + "type": "i128", + "index": false + }, + { + "name": "ammCumulativeFundingShort", + "type": "i128", + "index": false + } + ] + }, + { + "name": "FundingRateRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "recordId", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "fundingRate", + "type": "i64", + "index": false + }, + { + "name": "fundingRateLong", + "type": "i128", + "index": false + }, + { + "name": "fundingRateShort", + "type": "i128", + "index": false + }, + { + "name": "cumulativeFundingRateLong", + "type": "i128", + "index": false + }, + { + "name": "cumulativeFundingRateShort", + "type": "i128", + "index": false + }, + { + "name": "oraclePriceTwap", + "type": "i64", + "index": false + }, + { + "name": "markPriceTwap", + "type": "u64", + "index": false + }, + { + "name": "periodRevenue", + "type": "i64", + "index": false + }, + { + "name": "baseAssetAmountWithAmm", + "type": "i128", + "index": false + }, + { + "name": "baseAssetAmountWithUnsettledLp", + "type": "i128", + "index": false + } + ] + }, + { + "name": "CurveRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "recordId", + "type": "u64", + "index": false + }, + { + "name": "pegMultiplierBefore", + "type": "u128", + "index": false + }, + { + "name": "baseAssetReserveBefore", + "type": "u128", + "index": false + }, + { + "name": "quoteAssetReserveBefore", + "type": "u128", + "index": false + }, + { + "name": "sqrtKBefore", + "type": "u128", + "index": false + }, + { + "name": "pegMultiplierAfter", + "type": "u128", + "index": false + }, + { + "name": "baseAssetReserveAfter", + "type": "u128", + "index": false + }, + { + "name": "quoteAssetReserveAfter", + "type": "u128", + "index": false + }, + { + "name": "sqrtKAfter", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountLong", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountShort", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountWithAmm", + "type": "i128", + "index": false + }, + { + "name": "totalFee", + "type": "i128", + "index": false + }, + { + "name": "totalFeeMinusDistributions", + "type": "i128", + "index": false + }, + { + "name": "adjustmentCost", + "type": "i128", + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + }, + { + "name": "fillRecord", + "type": "u128", + "index": false + }, + { + "name": "numberOfUsers", + "type": "u32", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + } + ] + }, + { + "name": "OrderRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "order", + "type": { + "defined": "Order" + }, + "index": false + } + ] + }, + { + "name": "OrderActionRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "action", + "type": { + "defined": "OrderAction" + }, + "index": false + }, + { + "name": "actionExplanation", + "type": { + "defined": "OrderActionExplanation" + }, + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "marketType", + "type": { + "defined": "MarketType" + }, + "index": false + }, + { + "name": "filler", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "fillerReward", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "fillRecordId", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "baseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "quoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerFee", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerFee", + "type": { + "option": "i64" + }, + "index": false + }, + { + "name": "referrerReward", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "quoteAssetAmountSurplus", + "type": { + "option": "i64" + }, + "index": false + }, + { + "name": "spotFulfillmentMethodFee", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "taker", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "takerOrderId", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "takerOrderDirection", + "type": { + "option": { + "defined": "PositionDirection" + } + }, + "index": false + }, + { + "name": "takerOrderBaseAssetAmount", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerOrderCumulativeBaseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerOrderCumulativeQuoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "maker", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "makerOrderDirection", + "type": { + "option": { + "defined": "PositionDirection" + } + }, + "index": false + }, + { + "name": "makerOrderBaseAssetAmount", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerOrderCumulativeBaseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerOrderCumulativeQuoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LPRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "action", + "type": { + "defined": "LPAction" + }, + "index": false + }, + { + "name": "nShares", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "deltaBaseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "deltaQuoteAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "pnl", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LiquidationRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "liquidationType", + "type": { + "defined": "LiquidationType" + }, + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "liquidator", + "type": "publicKey", + "index": false + }, + { + "name": "marginRequirement", + "type": "u128", + "index": false + }, + { + "name": "totalCollateral", + "type": "i128", + "index": false + }, + { + "name": "marginFreed", + "type": "u64", + "index": false + }, + { + "name": "liquidationId", + "type": "u16", + "index": false + }, + { + "name": "bankrupt", + "type": "bool", + "index": false + }, + { + "name": "canceledOrderIds", + "type": { + "vec": "u32" + }, + "index": false + }, + { + "name": "liquidatePerp", + "type": { + "defined": "LiquidatePerpRecord" + }, + "index": false + }, + { + "name": "liquidateSpot", + "type": { + "defined": "LiquidateSpotRecord" + }, + "index": false + }, + { + "name": "liquidateBorrowForPerpPnl", + "type": { + "defined": "LiquidateBorrowForPerpPnlRecord" + }, + "index": false + }, + { + "name": "liquidatePerpPnlForDeposit", + "type": { + "defined": "LiquidatePerpPnlForDepositRecord" + }, + "index": false + }, + { + "name": "perpBankruptcy", + "type": { + "defined": "PerpBankruptcyRecord" + }, + "index": false + }, + { + "name": "spotBankruptcy", + "type": { + "defined": "SpotBankruptcyRecord" + }, + "index": false + } + ] + }, + { + "name": "SettlePnlRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "pnl", + "type": "i128", + "index": false + }, + { + "name": "baseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "quoteAssetAmountAfter", + "type": "i64", + "index": false + }, + { + "name": "quoteEntryAmount", + "type": "i64", + "index": false + }, + { + "name": "settlePrice", + "type": "i64", + "index": false + }, + { + "name": "explanation", + "type": { + "defined": "SettlePnlExplanation" + }, + "index": false + } + ] + }, + { + "name": "InsuranceFundRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "spotMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "perpMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "userIfFactor", + "type": "u32", + "index": false + }, + { + "name": "totalIfFactor", + "type": "u32", + "index": false + }, + { + "name": "vaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "insuranceVaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "totalIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "amount", + "type": "i64", + "index": false + } + ] + }, + { + "name": "InsuranceFundStakeRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "action", + "type": { + "defined": "StakeAction" + }, + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "insuranceVaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "ifSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "userIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "ifSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "userIfSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesAfter", + "type": "u128", + "index": false + } + ] + }, + { + "name": "SwapRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "amountOut", + "type": "u64", + "index": false + }, + { + "name": "amountIn", + "type": "u64", + "index": false + }, + { + "name": "outMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "inMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "outOraclePrice", + "type": "i64", + "index": false + }, + { + "name": "inOraclePrice", + "type": "i64", + "index": false + }, + { + "name": "fee", + "type": "u64", + "index": false + } + ] + }, + { + "name": "SpotMarketVaultDepositRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "depositBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterestBefore", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterestAfter", + "type": "u128", + "index": false + }, + { + "name": "depositTokenAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "InvalidSpotMarketAuthority", + "msg": "Invalid Spot Market Authority" + }, + { + "code": 6001, + "name": "InvalidInsuranceFundAuthority", + "msg": "Clearing house not insurance fund authority" + }, + { + "code": 6002, + "name": "InsufficientDeposit", + "msg": "Insufficient deposit" + }, + { + "code": 6003, + "name": "InsufficientCollateral", + "msg": "Insufficient collateral" + }, + { + "code": 6004, + "name": "SufficientCollateral", + "msg": "Sufficient collateral" + }, + { + "code": 6005, + "name": "MaxNumberOfPositions", + "msg": "Max number of positions taken" + }, + { + "code": 6006, + "name": "AdminControlsPricesDisabled", + "msg": "Admin Controls Prices Disabled" + }, + { + "code": 6007, + "name": "MarketDelisted", + "msg": "Market Delisted" + }, + { + "code": 6008, + "name": "MarketIndexAlreadyInitialized", + "msg": "Market Index Already Initialized" + }, + { + "code": 6009, + "name": "UserAccountAndUserPositionsAccountMismatch", + "msg": "User Account And User Positions Account Mismatch" + }, + { + "code": 6010, + "name": "UserHasNoPositionInMarket", + "msg": "User Has No Position In Market" + }, + { + "code": 6011, + "name": "InvalidInitialPeg", + "msg": "Invalid Initial Peg" + }, + { + "code": 6012, + "name": "InvalidRepegRedundant", + "msg": "AMM repeg already configured with amt given" + }, + { + "code": 6013, + "name": "InvalidRepegDirection", + "msg": "AMM repeg incorrect repeg direction" + }, + { + "code": 6014, + "name": "InvalidRepegProfitability", + "msg": "AMM repeg out of bounds pnl" + }, + { + "code": 6015, + "name": "SlippageOutsideLimit", + "msg": "Slippage Outside Limit Price" + }, + { + "code": 6016, + "name": "OrderSizeTooSmall", + "msg": "Order Size Too Small" + }, + { + "code": 6017, + "name": "InvalidUpdateK", + "msg": "Price change too large when updating K" + }, + { + "code": 6018, + "name": "AdminWithdrawTooLarge", + "msg": "Admin tried to withdraw amount larger than fees collected" + }, + { + "code": 6019, + "name": "MathError", + "msg": "Math Error" + }, + { + "code": 6020, + "name": "BnConversionError", + "msg": "Conversion to u128/u64 failed with an overflow or underflow" + }, + { + "code": 6021, + "name": "ClockUnavailable", + "msg": "Clock unavailable" + }, + { + "code": 6022, + "name": "UnableToLoadOracle", + "msg": "Unable To Load Oracles" + }, + { + "code": 6023, + "name": "PriceBandsBreached", + "msg": "Price Bands Breached" + }, + { + "code": 6024, + "name": "ExchangePaused", + "msg": "Exchange is paused" + }, + { + "code": 6025, + "name": "InvalidWhitelistToken", + "msg": "Invalid whitelist token" + }, + { + "code": 6026, + "name": "WhitelistTokenNotFound", + "msg": "Whitelist token not found" + }, + { + "code": 6027, + "name": "InvalidDiscountToken", + "msg": "Invalid discount token" + }, + { + "code": 6028, + "name": "DiscountTokenNotFound", + "msg": "Discount token not found" + }, + { + "code": 6029, + "name": "ReferrerNotFound", + "msg": "Referrer not found" + }, + { + "code": 6030, + "name": "ReferrerStatsNotFound", + "msg": "ReferrerNotFound" + }, + { + "code": 6031, + "name": "ReferrerMustBeWritable", + "msg": "ReferrerMustBeWritable" + }, + { + "code": 6032, + "name": "ReferrerStatsMustBeWritable", + "msg": "ReferrerMustBeWritable" + }, + { + "code": 6033, + "name": "ReferrerAndReferrerStatsAuthorityUnequal", + "msg": "ReferrerAndReferrerStatsAuthorityUnequal" + }, + { + "code": 6034, + "name": "InvalidReferrer", + "msg": "InvalidReferrer" + }, + { + "code": 6035, + "name": "InvalidOracle", + "msg": "InvalidOracle" + }, + { + "code": 6036, + "name": "OracleNotFound", + "msg": "OracleNotFound" + }, + { + "code": 6037, + "name": "LiquidationsBlockedByOracle", + "msg": "Liquidations Blocked By Oracle" + }, + { + "code": 6038, + "name": "MaxDeposit", + "msg": "Can not deposit more than max deposit" + }, + { + "code": 6039, + "name": "CantDeleteUserWithCollateral", + "msg": "Can not delete user that still has collateral" + }, + { + "code": 6040, + "name": "InvalidFundingProfitability", + "msg": "AMM funding out of bounds pnl" + }, + { + "code": 6041, + "name": "CastingFailure", + "msg": "Casting Failure" + }, + { + "code": 6042, + "name": "InvalidOrder", + "msg": "InvalidOrder" + }, + { + "code": 6043, + "name": "InvalidOrderMaxTs", + "msg": "InvalidOrderMaxTs" + }, + { + "code": 6044, + "name": "InvalidOrderMarketType", + "msg": "InvalidOrderMarketType" + }, + { + "code": 6045, + "name": "InvalidOrderForInitialMarginReq", + "msg": "InvalidOrderForInitialMarginReq" + }, + { + "code": 6046, + "name": "InvalidOrderNotRiskReducing", + "msg": "InvalidOrderNotRiskReducing" + }, + { + "code": 6047, + "name": "InvalidOrderSizeTooSmall", + "msg": "InvalidOrderSizeTooSmall" + }, + { + "code": 6048, + "name": "InvalidOrderNotStepSizeMultiple", + "msg": "InvalidOrderNotStepSizeMultiple" + }, + { + "code": 6049, + "name": "InvalidOrderBaseQuoteAsset", + "msg": "InvalidOrderBaseQuoteAsset" + }, + { + "code": 6050, + "name": "InvalidOrderIOC", + "msg": "InvalidOrderIOC" + }, + { + "code": 6051, + "name": "InvalidOrderPostOnly", + "msg": "InvalidOrderPostOnly" + }, + { + "code": 6052, + "name": "InvalidOrderIOCPostOnly", + "msg": "InvalidOrderIOCPostOnly" + }, + { + "code": 6053, + "name": "InvalidOrderTrigger", + "msg": "InvalidOrderTrigger" + }, + { + "code": 6054, + "name": "InvalidOrderAuction", + "msg": "InvalidOrderAuction" + }, + { + "code": 6055, + "name": "InvalidOrderOracleOffset", + "msg": "InvalidOrderOracleOffset" + }, + { + "code": 6056, + "name": "InvalidOrderMinOrderSize", + "msg": "InvalidOrderMinOrderSize" + }, + { + "code": 6057, + "name": "PlacePostOnlyLimitFailure", + "msg": "Failed to Place Post-Only Limit Order" + }, + { + "code": 6058, + "name": "UserHasNoOrder", + "msg": "User has no order" + }, + { + "code": 6059, + "name": "OrderAmountTooSmall", + "msg": "Order Amount Too Small" + }, + { + "code": 6060, + "name": "MaxNumberOfOrders", + "msg": "Max number of orders taken" + }, + { + "code": 6061, + "name": "OrderDoesNotExist", + "msg": "Order does not exist" + }, + { + "code": 6062, + "name": "OrderNotOpen", + "msg": "Order not open" + }, + { + "code": 6063, + "name": "FillOrderDidNotUpdateState", + "msg": "FillOrderDidNotUpdateState" + }, + { + "code": 6064, + "name": "ReduceOnlyOrderIncreasedRisk", + "msg": "Reduce only order increased risk" + }, + { + "code": 6065, + "name": "UnableToLoadAccountLoader", + "msg": "Unable to load AccountLoader" + }, + { + "code": 6066, + "name": "TradeSizeTooLarge", + "msg": "Trade Size Too Large" + }, + { + "code": 6067, + "name": "UserCantReferThemselves", + "msg": "User cant refer themselves" + }, + { + "code": 6068, + "name": "DidNotReceiveExpectedReferrer", + "msg": "Did not receive expected referrer" + }, + { + "code": 6069, + "name": "CouldNotDeserializeReferrer", + "msg": "Could not deserialize referrer" + }, + { + "code": 6070, + "name": "CouldNotDeserializeReferrerStats", + "msg": "Could not deserialize referrer stats" + }, + { + "code": 6071, + "name": "UserOrderIdAlreadyInUse", + "msg": "User Order Id Already In Use" + }, + { + "code": 6072, + "name": "NoPositionsLiquidatable", + "msg": "No positions liquidatable" + }, + { + "code": 6073, + "name": "InvalidMarginRatio", + "msg": "Invalid Margin Ratio" + }, + { + "code": 6074, + "name": "CantCancelPostOnlyOrder", + "msg": "Cant Cancel Post Only Order" + }, + { + "code": 6075, + "name": "InvalidOracleOffset", + "msg": "InvalidOracleOffset" + }, + { + "code": 6076, + "name": "CantExpireOrders", + "msg": "CantExpireOrders" + }, + { + "code": 6077, + "name": "CouldNotLoadMarketData", + "msg": "CouldNotLoadMarketData" + }, + { + "code": 6078, + "name": "PerpMarketNotFound", + "msg": "PerpMarketNotFound" + }, + { + "code": 6079, + "name": "InvalidMarketAccount", + "msg": "InvalidMarketAccount" + }, + { + "code": 6080, + "name": "UnableToLoadPerpMarketAccount", + "msg": "UnableToLoadMarketAccount" + }, + { + "code": 6081, + "name": "MarketWrongMutability", + "msg": "MarketWrongMutability" + }, + { + "code": 6082, + "name": "UnableToCastUnixTime", + "msg": "UnableToCastUnixTime" + }, + { + "code": 6083, + "name": "CouldNotFindSpotPosition", + "msg": "CouldNotFindSpotPosition" + }, + { + "code": 6084, + "name": "NoSpotPositionAvailable", + "msg": "NoSpotPositionAvailable" + }, + { + "code": 6085, + "name": "InvalidSpotMarketInitialization", + "msg": "InvalidSpotMarketInitialization" + }, + { + "code": 6086, + "name": "CouldNotLoadSpotMarketData", + "msg": "CouldNotLoadSpotMarketData" + }, + { + "code": 6087, + "name": "SpotMarketNotFound", + "msg": "SpotMarketNotFound" + }, + { + "code": 6088, + "name": "InvalidSpotMarketAccount", + "msg": "InvalidSpotMarketAccount" + }, + { + "code": 6089, + "name": "UnableToLoadSpotMarketAccount", + "msg": "UnableToLoadSpotMarketAccount" + }, + { + "code": 6090, + "name": "SpotMarketWrongMutability", + "msg": "SpotMarketWrongMutability" + }, + { + "code": 6091, + "name": "SpotMarketInterestNotUpToDate", + "msg": "SpotInterestNotUpToDate" + }, + { + "code": 6092, + "name": "SpotMarketInsufficientDeposits", + "msg": "SpotMarketInsufficientDeposits" + }, + { + "code": 6093, + "name": "UserMustSettleTheirOwnPositiveUnsettledPNL", + "msg": "UserMustSettleTheirOwnPositiveUnsettledPNL" + }, + { + "code": 6094, + "name": "CantUpdatePoolBalanceType", + "msg": "CantUpdatePoolBalanceType" + }, + { + "code": 6095, + "name": "InsufficientCollateralForSettlingPNL", + "msg": "InsufficientCollateralForSettlingPNL" + }, + { + "code": 6096, + "name": "AMMNotUpdatedInSameSlot", + "msg": "AMMNotUpdatedInSameSlot" + }, + { + "code": 6097, + "name": "AuctionNotComplete", + "msg": "AuctionNotComplete" + }, + { + "code": 6098, + "name": "MakerNotFound", + "msg": "MakerNotFound" + }, + { + "code": 6099, + "name": "MakerStatsNotFound", + "msg": "MakerNotFound" + }, + { + "code": 6100, + "name": "MakerMustBeWritable", + "msg": "MakerMustBeWritable" + }, + { + "code": 6101, + "name": "MakerStatsMustBeWritable", + "msg": "MakerMustBeWritable" + }, + { + "code": 6102, + "name": "MakerOrderNotFound", + "msg": "MakerOrderNotFound" + }, + { + "code": 6103, + "name": "CouldNotDeserializeMaker", + "msg": "CouldNotDeserializeMaker" + }, + { + "code": 6104, + "name": "CouldNotDeserializeMakerStats", + "msg": "CouldNotDeserializeMaker" + }, + { + "code": 6105, + "name": "AuctionPriceDoesNotSatisfyMaker", + "msg": "AuctionPriceDoesNotSatisfyMaker" + }, + { + "code": 6106, + "name": "MakerCantFulfillOwnOrder", + "msg": "MakerCantFulfillOwnOrder" + }, + { + "code": 6107, + "name": "MakerOrderMustBePostOnly", + "msg": "MakerOrderMustBePostOnly" + }, + { + "code": 6108, + "name": "CantMatchTwoPostOnlys", + "msg": "CantMatchTwoPostOnlys" + }, + { + "code": 6109, + "name": "OrderBreachesOraclePriceLimits", + "msg": "OrderBreachesOraclePriceLimits" + }, + { + "code": 6110, + "name": "OrderMustBeTriggeredFirst", + "msg": "OrderMustBeTriggeredFirst" + }, + { + "code": 6111, + "name": "OrderNotTriggerable", + "msg": "OrderNotTriggerable" + }, + { + "code": 6112, + "name": "OrderDidNotSatisfyTriggerCondition", + "msg": "OrderDidNotSatisfyTriggerCondition" + }, + { + "code": 6113, + "name": "PositionAlreadyBeingLiquidated", + "msg": "PositionAlreadyBeingLiquidated" + }, + { + "code": 6114, + "name": "PositionDoesntHaveOpenPositionOrOrders", + "msg": "PositionDoesntHaveOpenPositionOrOrders" + }, + { + "code": 6115, + "name": "AllOrdersAreAlreadyLiquidations", + "msg": "AllOrdersAreAlreadyLiquidations" + }, + { + "code": 6116, + "name": "CantCancelLiquidationOrder", + "msg": "CantCancelLiquidationOrder" + }, + { + "code": 6117, + "name": "UserIsBeingLiquidated", + "msg": "UserIsBeingLiquidated" + }, + { + "code": 6118, + "name": "LiquidationsOngoing", + "msg": "LiquidationsOngoing" + }, + { + "code": 6119, + "name": "WrongSpotBalanceType", + "msg": "WrongSpotBalanceType" + }, + { + "code": 6120, + "name": "UserCantLiquidateThemself", + "msg": "UserCantLiquidateThemself" + }, + { + "code": 6121, + "name": "InvalidPerpPositionToLiquidate", + "msg": "InvalidPerpPositionToLiquidate" + }, + { + "code": 6122, + "name": "InvalidBaseAssetAmountForLiquidatePerp", + "msg": "InvalidBaseAssetAmountForLiquidatePerp" + }, + { + "code": 6123, + "name": "InvalidPositionLastFundingRate", + "msg": "InvalidPositionLastFundingRate" + }, + { + "code": 6124, + "name": "InvalidPositionDelta", + "msg": "InvalidPositionDelta" + }, + { + "code": 6125, + "name": "UserBankrupt", + "msg": "UserBankrupt" + }, + { + "code": 6126, + "name": "UserNotBankrupt", + "msg": "UserNotBankrupt" + }, + { + "code": 6127, + "name": "UserHasInvalidBorrow", + "msg": "UserHasInvalidBorrow" + }, + { + "code": 6128, + "name": "DailyWithdrawLimit", + "msg": "DailyWithdrawLimit" + }, + { + "code": 6129, + "name": "DefaultError", + "msg": "DefaultError" + }, + { + "code": 6130, + "name": "InsufficientLPTokens", + "msg": "Insufficient LP tokens" + }, + { + "code": 6131, + "name": "CantLPWithPerpPosition", + "msg": "Cant LP with a market position" + }, + { + "code": 6132, + "name": "UnableToBurnLPTokens", + "msg": "Unable to burn LP tokens" + }, + { + "code": 6133, + "name": "TryingToRemoveLiquidityTooFast", + "msg": "Trying to remove liqudity too fast after adding it" + }, + { + "code": 6134, + "name": "InvalidSpotMarketVault", + "msg": "Invalid Spot Market Vault" + }, + { + "code": 6135, + "name": "InvalidSpotMarketState", + "msg": "Invalid Spot Market State" + }, + { + "code": 6136, + "name": "InvalidSerumProgram", + "msg": "InvalidSerumProgram" + }, + { + "code": 6137, + "name": "InvalidSerumMarket", + "msg": "InvalidSerumMarket" + }, + { + "code": 6138, + "name": "InvalidSerumBids", + "msg": "InvalidSerumBids" + }, + { + "code": 6139, + "name": "InvalidSerumAsks", + "msg": "InvalidSerumAsks" + }, + { + "code": 6140, + "name": "InvalidSerumOpenOrders", + "msg": "InvalidSerumOpenOrders" + }, + { + "code": 6141, + "name": "FailedSerumCPI", + "msg": "FailedSerumCPI" + }, + { + "code": 6142, + "name": "FailedToFillOnExternalMarket", + "msg": "FailedToFillOnExternalMarket" + }, + { + "code": 6143, + "name": "InvalidFulfillmentConfig", + "msg": "InvalidFulfillmentConfig" + }, + { + "code": 6144, + "name": "InvalidFeeStructure", + "msg": "InvalidFeeStructure" + }, + { + "code": 6145, + "name": "InsufficientIFShares", + "msg": "Insufficient IF shares" + }, + { + "code": 6146, + "name": "MarketActionPaused", + "msg": "the Market has paused this action" + }, + { + "code": 6147, + "name": "MarketPlaceOrderPaused", + "msg": "the Market status doesnt allow placing orders" + }, + { + "code": 6148, + "name": "MarketFillOrderPaused", + "msg": "the Market status doesnt allow filling orders" + }, + { + "code": 6149, + "name": "MarketWithdrawPaused", + "msg": "the Market status doesnt allow withdraws" + }, + { + "code": 6150, + "name": "ProtectedAssetTierViolation", + "msg": "Action violates the Protected Asset Tier rules" + }, + { + "code": 6151, + "name": "IsolatedAssetTierViolation", + "msg": "Action violates the Isolated Asset Tier rules" + }, + { + "code": 6152, + "name": "UserCantBeDeleted", + "msg": "User Cant Be Deleted" + }, + { + "code": 6153, + "name": "ReduceOnlyWithdrawIncreasedRisk", + "msg": "Reduce Only Withdraw Increased Risk" + }, + { + "code": 6154, + "name": "MaxOpenInterest", + "msg": "Max Open Interest" + }, + { + "code": 6155, + "name": "CantResolvePerpBankruptcy", + "msg": "Cant Resolve Perp Bankruptcy" + }, + { + "code": 6156, + "name": "LiquidationDoesntSatisfyLimitPrice", + "msg": "Liquidation Doesnt Satisfy Limit Price" + }, + { + "code": 6157, + "name": "MarginTradingDisabled", + "msg": "Margin Trading Disabled" + }, + { + "code": 6158, + "name": "InvalidMarketStatusToSettlePnl", + "msg": "Invalid Market Status to Settle Perp Pnl" + }, + { + "code": 6159, + "name": "PerpMarketNotInSettlement", + "msg": "PerpMarketNotInSettlement" + }, + { + "code": 6160, + "name": "PerpMarketNotInReduceOnly", + "msg": "PerpMarketNotInReduceOnly" + }, + { + "code": 6161, + "name": "PerpMarketSettlementBufferNotReached", + "msg": "PerpMarketSettlementBufferNotReached" + }, + { + "code": 6162, + "name": "PerpMarketSettlementUserHasOpenOrders", + "msg": "PerpMarketSettlementUserHasOpenOrders" + }, + { + "code": 6163, + "name": "PerpMarketSettlementUserHasActiveLP", + "msg": "PerpMarketSettlementUserHasActiveLP" + }, + { + "code": 6164, + "name": "UnableToSettleExpiredUserPosition", + "msg": "UnableToSettleExpiredUserPosition" + }, + { + "code": 6165, + "name": "UnequalMarketIndexForSpotTransfer", + "msg": "UnequalMarketIndexForSpotTransfer" + }, + { + "code": 6166, + "name": "InvalidPerpPositionDetected", + "msg": "InvalidPerpPositionDetected" + }, + { + "code": 6167, + "name": "InvalidSpotPositionDetected", + "msg": "InvalidSpotPositionDetected" + }, + { + "code": 6168, + "name": "InvalidAmmDetected", + "msg": "InvalidAmmDetected" + }, + { + "code": 6169, + "name": "InvalidAmmForFillDetected", + "msg": "InvalidAmmForFillDetected" + }, + { + "code": 6170, + "name": "InvalidAmmLimitPriceOverride", + "msg": "InvalidAmmLimitPriceOverride" + }, + { + "code": 6171, + "name": "InvalidOrderFillPrice", + "msg": "InvalidOrderFillPrice" + }, + { + "code": 6172, + "name": "SpotMarketBalanceInvariantViolated", + "msg": "SpotMarketBalanceInvariantViolated" + }, + { + "code": 6173, + "name": "SpotMarketVaultInvariantViolated", + "msg": "SpotMarketVaultInvariantViolated" + }, + { + "code": 6174, + "name": "InvalidPDA", + "msg": "InvalidPDA" + }, + { + "code": 6175, + "name": "InvalidPDASigner", + "msg": "InvalidPDASigner" + }, + { + "code": 6176, + "name": "RevenueSettingsCannotSettleToIF", + "msg": "RevenueSettingsCannotSettleToIF" + }, + { + "code": 6177, + "name": "NoRevenueToSettleToIF", + "msg": "NoRevenueToSettleToIF" + }, + { + "code": 6178, + "name": "NoAmmPerpPnlDeficit", + "msg": "NoAmmPerpPnlDeficit" + }, + { + "code": 6179, + "name": "SufficientPerpPnlPool", + "msg": "SufficientPerpPnlPool" + }, + { + "code": 6180, + "name": "InsufficientPerpPnlPool", + "msg": "InsufficientPerpPnlPool" + }, + { + "code": 6181, + "name": "PerpPnlDeficitBelowThreshold", + "msg": "PerpPnlDeficitBelowThreshold" + }, + { + "code": 6182, + "name": "MaxRevenueWithdrawPerPeriodReached", + "msg": "MaxRevenueWithdrawPerPeriodReached" + }, + { + "code": 6183, + "name": "MaxIFWithdrawReached", + "msg": "InvalidSpotPositionDetected" + }, + { + "code": 6184, + "name": "NoIFWithdrawAvailable", + "msg": "NoIFWithdrawAvailable" + }, + { + "code": 6185, + "name": "InvalidIFUnstake", + "msg": "InvalidIFUnstake" + }, + { + "code": 6186, + "name": "InvalidIFUnstakeSize", + "msg": "InvalidIFUnstakeSize" + }, + { + "code": 6187, + "name": "InvalidIFUnstakeCancel", + "msg": "InvalidIFUnstakeCancel" + }, + { + "code": 6188, + "name": "InvalidIFForNewStakes", + "msg": "InvalidIFForNewStakes" + }, + { + "code": 6189, + "name": "InvalidIFRebase", + "msg": "InvalidIFRebase" + }, + { + "code": 6190, + "name": "InvalidInsuranceUnstakeSize", + "msg": "InvalidInsuranceUnstakeSize" + }, + { + "code": 6191, + "name": "InvalidOrderLimitPrice", + "msg": "InvalidOrderLimitPrice" + }, + { + "code": 6192, + "name": "InvalidIFDetected", + "msg": "InvalidIFDetected" + }, + { + "code": 6193, + "name": "InvalidAmmMaxSpreadDetected", + "msg": "InvalidAmmMaxSpreadDetected" + }, + { + "code": 6194, + "name": "InvalidConcentrationCoef", + "msg": "InvalidConcentrationCoef" + }, + { + "code": 6195, + "name": "InvalidSrmVault", + "msg": "InvalidSrmVault" + }, + { + "code": 6196, + "name": "InvalidVaultOwner", + "msg": "InvalidVaultOwner" + }, + { + "code": 6197, + "name": "InvalidMarketStatusForFills", + "msg": "InvalidMarketStatusForFills" + }, + { + "code": 6198, + "name": "IFWithdrawRequestInProgress", + "msg": "IFWithdrawRequestInProgress" + }, + { + "code": 6199, + "name": "NoIFWithdrawRequestInProgress", + "msg": "NoIFWithdrawRequestInProgress" + }, + { + "code": 6200, + "name": "IFWithdrawRequestTooSmall", + "msg": "IFWithdrawRequestTooSmall" + }, + { + "code": 6201, + "name": "IncorrectSpotMarketAccountPassed", + "msg": "IncorrectSpotMarketAccountPassed" + }, + { + "code": 6202, + "name": "BlockchainClockInconsistency", + "msg": "BlockchainClockInconsistency" + }, + { + "code": 6203, + "name": "InvalidIFSharesDetected", + "msg": "InvalidIFSharesDetected" + }, + { + "code": 6204, + "name": "NewLPSizeTooSmall", + "msg": "NewLPSizeTooSmall" + }, + { + "code": 6205, + "name": "MarketStatusInvalidForNewLP", + "msg": "MarketStatusInvalidForNewLP" + }, + { + "code": 6206, + "name": "InvalidMarkTwapUpdateDetected", + "msg": "InvalidMarkTwapUpdateDetected" + }, + { + "code": 6207, + "name": "MarketSettlementAttemptOnActiveMarket", + "msg": "MarketSettlementAttemptOnActiveMarket" + }, + { + "code": 6208, + "name": "MarketSettlementRequiresSettledLP", + "msg": "MarketSettlementRequiresSettledLP" + }, + { + "code": 6209, + "name": "MarketSettlementAttemptTooEarly", + "msg": "MarketSettlementAttemptTooEarly" + }, + { + "code": 6210, + "name": "MarketSettlementTargetPriceInvalid", + "msg": "MarketSettlementTargetPriceInvalid" + }, + { + "code": 6211, + "name": "UnsupportedSpotMarket", + "msg": "UnsupportedSpotMarket" + }, + { + "code": 6212, + "name": "SpotOrdersDisabled", + "msg": "SpotOrdersDisabled" + }, + { + "code": 6213, + "name": "MarketBeingInitialized", + "msg": "Market Being Initialized" + }, + { + "code": 6214, + "name": "InvalidUserSubAccountId", + "msg": "Invalid Sub Account Id" + }, + { + "code": 6215, + "name": "InvalidTriggerOrderCondition", + "msg": "Invalid Trigger Order Condition" + }, + { + "code": 6216, + "name": "InvalidSpotPosition", + "msg": "Invalid Spot Position" + }, + { + "code": 6217, + "name": "CantTransferBetweenSameUserAccount", + "msg": "Cant transfer between same user account" + }, + { + "code": 6218, + "name": "InvalidPerpPosition", + "msg": "Invalid Perp Position" + }, + { + "code": 6219, + "name": "UnableToGetLimitPrice", + "msg": "Unable To Get Limit Price" + }, + { + "code": 6220, + "name": "InvalidLiquidation", + "msg": "Invalid Liquidation" + }, + { + "code": 6221, + "name": "SpotFulfillmentConfigDisabled", + "msg": "Spot Fulfillment Config Disabled" + }, + { + "code": 6222, + "name": "InvalidMaker", + "msg": "Invalid Maker" + }, + { + "code": 6223, + "name": "FailedUnwrap", + "msg": "Failed Unwrap" + }, + { + "code": 6224, + "name": "MaxNumberOfUsers", + "msg": "Max Number Of Users" + }, + { + "code": 6225, + "name": "InvalidOracleForSettlePnl", + "msg": "InvalidOracleForSettlePnl" + }, + { + "code": 6226, + "name": "MarginOrdersOpen", + "msg": "MarginOrdersOpen" + }, + { + "code": 6227, + "name": "TierViolationLiquidatingPerpPnl", + "msg": "TierViolationLiquidatingPerpPnl" + }, + { + "code": 6228, + "name": "CouldNotLoadUserData", + "msg": "CouldNotLoadUserData" + }, + { + "code": 6229, + "name": "UserWrongMutability", + "msg": "UserWrongMutability" + }, + { + "code": 6230, + "name": "InvalidUserAccount", + "msg": "InvalidUserAccount" + }, + { + "code": 6231, + "name": "CouldNotLoadUserStatsData", + "msg": "CouldNotLoadUserData" + }, + { + "code": 6232, + "name": "UserStatsWrongMutability", + "msg": "UserWrongMutability" + }, + { + "code": 6233, + "name": "InvalidUserStatsAccount", + "msg": "InvalidUserAccount" + }, + { + "code": 6234, + "name": "UserNotFound", + "msg": "UserNotFound" + }, + { + "code": 6235, + "name": "UnableToLoadUserAccount", + "msg": "UnableToLoadUserAccount" + }, + { + "code": 6236, + "name": "UserStatsNotFound", + "msg": "UserStatsNotFound" + }, + { + "code": 6237, + "name": "UnableToLoadUserStatsAccount", + "msg": "UnableToLoadUserStatsAccount" + }, + { + "code": 6238, + "name": "UserNotInactive", + "msg": "User Not Inactive" + }, + { + "code": 6239, + "name": "RevertFill", + "msg": "RevertFill" + }, + { + "code": 6240, + "name": "InvalidMarketAccountforDeletion", + "msg": "Invalid MarketAccount for Deletion" + }, + { + "code": 6241, + "name": "InvalidSpotFulfillmentParams", + "msg": "Invalid Spot Fulfillment Params" + }, + { + "code": 6242, + "name": "FailedToGetMint", + "msg": "Failed to Get Mint" + }, + { + "code": 6243, + "name": "FailedPhoenixCPI", + "msg": "FailedPhoenixCPI" + }, + { + "code": 6244, + "name": "FailedToDeserializePhoenixMarket", + "msg": "FailedToDeserializePhoenixMarket" + }, + { + "code": 6245, + "name": "InvalidPricePrecision", + "msg": "InvalidPricePrecision" + }, + { + "code": 6246, + "name": "InvalidPhoenixProgram", + "msg": "InvalidPhoenixProgram" + }, + { + "code": 6247, + "name": "InvalidPhoenixMarket", + "msg": "InvalidPhoenixMarket" + }, + { + "code": 6248, + "name": "InvalidSwap", + "msg": "InvalidSwap" + }, + { + "code": 6249, + "name": "SwapLimitPriceBreached", + "msg": "SwapLimitPriceBreached" + }, + { + "code": 6250, + "name": "SpotMarketReduceOnly", + "msg": "SpotMarketReduceOnly" + }, + { + "code": 6251, + "name": "FundingWasNotUpdated", + "msg": "FundingWasNotUpdated" + }, + { + "code": 6252, + "name": "ImpossibleFill", + "msg": "ImpossibleFill" + }, + { + "code": 6253, + "name": "CantUpdatePerpBidAskTwap", + "msg": "CantUpdatePerpBidAskTwap" + }, + { + "code": 6254, + "name": "UserReduceOnly", + "msg": "UserReduceOnly" + }, + { + "code": 6255, + "name": "InvalidMarginCalculation", + "msg": "InvalidMarginCalculation" + }, + { + "code": 6256, + "name": "CantPayUserInitFee", + "msg": "CantPayUserInitFee" + }, + { + "code": 6257, + "name": "CantReclaimRent", + "msg": "CantReclaimRent" + }, + { + "code": 6258, + "name": "InsuranceFundOperationPaused", + "msg": "InsuranceFundOperationPaused" + }, + { + "code": 6259, + "name": "NoUnsettledPnl", + "msg": "NoUnsettledPnl" + }, + { + "code": 6260, + "name": "PnlPoolCantSettleUser", + "msg": "PnlPoolCantSettleUser" + }, + { + "code": 6261, + "name": "OracleNonPositive", + "msg": "OracleInvalid" + }, + { + "code": 6262, + "name": "OracleTooVolatile", + "msg": "OracleTooVolatile" + }, + { + "code": 6263, + "name": "OracleTooUncertain", + "msg": "OracleTooUncertain" + }, + { + "code": 6264, + "name": "OracleStaleForMargin", + "msg": "OracleStaleForMargin" + }, + { + "code": 6265, + "name": "OracleInsufficientDataPoints", + "msg": "OracleInsufficientDataPoints" + }, + { + "code": 6266, + "name": "OracleStaleForAMM", + "msg": "OracleStaleForAMM" + }, + { + "code": 6267, + "name": "UnableToParsePullOracleMessage", + "msg": "Unable to parse pull oracle message" + }, + { + "code": 6268, + "name": "MaxBorrows", + "msg": "Can not borow more than max borrows" + }, + { + "code": 6269, + "name": "OracleUpdatesNotMonotonic", + "msg": "Updates must be monotonically increasing" + }, + { + "code": 6270, + "name": "OraclePriceFeedMessageMismatch", + "msg": "Trying to update price feed with the wrong feed id" + }, + { + "code": 6271, + "name": "OracleUnsupportedMessageType", + "msg": "The message in the update must be a PriceFeedMessage" + }, + { + "code": 6272, + "name": "OracleDeserializeMessageFailed", + "msg": "Could not deserialize the message in the update" + }, + { + "code": 6273, + "name": "OracleWrongGuardianSetOwner", + "msg": "Wrong guardian set owner in update price atomic" + }, + { + "code": 6274, + "name": "OracleWrongWriteAuthority", + "msg": "Oracle post update atomic price feed account must be drift program" + }, + { + "code": 6275, + "name": "OracleWrongVaaOwner", + "msg": "Oracle vaa owner must be wormhole program" + }, + { + "code": 6276, + "name": "OracleTooManyPriceAccountUpdates", + "msg": "Multi updates must have 2 or fewer accounts passed in remaining accounts" + }, + { + "code": 6277, + "name": "OracleMismatchedVaaAndPriceUpdates", + "msg": "Don't have the same remaining accounts number and merkle price updates left" + }, + { + "code": 6278, + "name": "OracleBadRemainingAccountPublicKey", + "msg": "Remaining account passed is not a valid pda" + }, + { + "code": 6279, + "name": "FailedOpenbookV2CPI", + "msg": "FailedOpenbookV2CPI" + }, + { + "code": 6280, + "name": "InvalidOpenbookV2Program", + "msg": "InvalidOpenbookV2Program" + }, + { + "code": 6281, + "name": "InvalidOpenbookV2Market", + "msg": "InvalidOpenbookV2Market" + }, + { + "code": 6282, + "name": "NonZeroTransferFee", + "msg": "Non zero transfer fee" + }, + { + "code": 6283, + "name": "LiquidationOrderFailedToFill", + "msg": "Liquidation order failed to fill" + }, + { + "code": 6284, + "name": "InvalidPredictionMarketOrder", + "msg": "Invalid prediction market order" + } + ] +} + +export const IDL: Drift = { + "version": "2.92.0", + "name": "drift", + "instructions": [ + { + "name": "initializeUser", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "initializeUserStats", + "accounts": [ + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeReferrerName", + "accounts": [ + { + "name": "referrerName", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "deposit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "withdraw", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "transferDeposit", + "accounts": [ + { + "name": "fromUser", + "isMut": true, + "isSigner": false + }, + { + "name": "toUser", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "placePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + } + ] + }, + { + "name": "cancelOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "cancelOrderByUserId", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "userOrderId", + "type": "u8" + } + ] + }, + { + "name": "cancelOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketType", + "type": { + "option": { + "defined": "MarketType" + } + } + }, + { + "name": "marketIndex", + "type": { + "option": "u16" + } + }, + { + "name": "direction", + "type": { + "option": { + "defined": "PositionDirection" + } + } + } + ] + }, + { + "name": "cancelOrdersByIds", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderIds", + "type": { + "vec": "u32" + } + } + ] + }, + { + "name": "modifyOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "modifyOrderParams", + "type": { + "defined": "ModifyOrderParams" + } + } + ] + }, + { + "name": "modifyOrderByUserId", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "userOrderId", + "type": "u8" + }, + { + "name": "modifyOrderParams", + "type": { + "defined": "ModifyOrderParams" + } + } + ] + }, + { + "name": "placeAndTakePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "placeAndMakePerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "taker", + "isMut": true, + "isSigner": false + }, + { + "name": "takerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "takerOrderId", + "type": "u32" + } + ] + }, + { + "name": "placeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + } + ] + }, + { + "name": "placeAndTakeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "placeAndMakeSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "taker", + "isMut": true, + "isSigner": false + }, + { + "name": "takerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "OrderParams" + } + }, + { + "name": "takerOrderId", + "type": "u32" + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + } + ] + }, + { + "name": "placeOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "params", + "type": { + "vec": { + "defined": "OrderParams" + } + } + } + ] + }, + { + "name": "beginSwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "outSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "inSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "outTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "inTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "instructions", + "isMut": false, + "isSigner": false, + "docs": [ + "Instructions Sysvar for instruction introspection" + ] + } + ], + "args": [ + { + "name": "inMarketIndex", + "type": "u16" + }, + { + "name": "outMarketIndex", + "type": "u16" + }, + { + "name": "amountIn", + "type": "u64" + } + ] + }, + { + "name": "endSwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "outSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "inSpotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "outTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "inTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "instructions", + "isMut": false, + "isSigner": false, + "docs": [ + "Instructions Sysvar for instruction introspection" + ] + } + ], + "args": [ + { + "name": "inMarketIndex", + "type": "u16" + }, + { + "name": "outMarketIndex", + "type": "u16" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + }, + { + "name": "reduceOnly", + "type": { + "option": { + "defined": "SwapReduceOnly" + } + } + } + ] + }, + { + "name": "addPerpLpShares", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "nShares", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removePerpLpShares", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "sharesToBurn", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removePerpLpSharesInExpiringMarket", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "sharesToBurn", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateUserName", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updateUserCustomMarginRatio", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "marginRatio", + "type": "u32" + } + ] + }, + { + "name": "updateUserMarginTradingEnabled", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "marginTradingEnabled", + "type": "bool" + } + ] + }, + { + "name": "updateUserDelegate", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "delegate", + "type": "publicKey" + } + ] + }, + { + "name": "updateUserReduceOnly", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "reduceOnly", + "type": "bool" + } + ] + }, + { + "name": "updateUserAdvancedLp", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "subAccountId", + "type": "u16" + }, + { + "name": "advancedLp", + "type": "bool" + } + ] + }, + { + "name": "deleteUser", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "reclaimRent", + "accounts": [ + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "fillPerpOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "revertFill", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "fillSpotOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "fillerStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": { + "option": "u32" + } + }, + { + "name": "fulfillmentType", + "type": { + "option": { + "defined": "SpotFulfillmentType" + } + } + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "triggerOrder", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderId", + "type": "u32" + } + ] + }, + { + "name": "forceCancelOrders", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserIdle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserOpenOrdersCount", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "filler", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "adminDisableUpdatePerpBidAskTwap", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "disable", + "type": "bool" + } + ] + }, + { + "name": "settlePnl", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleMultiplePnls", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndexes", + "type": { + "vec": "u16" + } + }, + { + "name": "mode", + "type": { + "defined": "SettlePnlMode" + } + } + ] + }, + { + "name": "settleFundingPayment", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "settleLp", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleExpiredMarket", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "liquidatePerp", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxBaseAssetAmount", + "type": "u64" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidatePerpWithFill", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "liquidateSpot", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxLiabilityTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidateBorrowForPerpPnl", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxLiabilityTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "liquidatePerpPnlForDeposit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "liquidatorMaxPnlTransfer", + "type": "u128" + }, + { + "name": "limitPrice", + "type": { + "option": "u64" + } + } + ] + }, + { + "name": "setUserStatusToBeingLiquidated", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "resolvePerpPnlDeficit", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "perpMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "resolvePerpBankruptcy", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "quoteSpotMarketIndex", + "type": "u16" + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "resolveSpotBankruptcy", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "liquidator", + "isMut": true, + "isSigner": false + }, + { + "name": "liquidatorStats", + "isMut": true, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "settleRevenueToInsuranceFund", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateFundingRate", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updatePrelaunchOracle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updatePerpBidAskTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "keeperStats", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "updateSpotMarketCumulativeInterest", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateAmms", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "marketIndexes", + "type": { + "array": [ + "u16", + 5 + ] + } + } + ] + }, + { + "name": "updateSpotMarketExpiry", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "expiryTs", + "type": "i64" + } + ] + }, + { + "name": "updateUserQuoteAssetInsuranceStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateUserGovTokenInsuranceStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "addInsuranceFundStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "requestRemoveInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "cancelRequestRemoveInsuranceFundStake", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "removeInsuranceFundStake", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "transferProtocolIfShares", + "accounts": [ + { + "name": "signer", + "isMut": false, + "isSigner": true + }, + { + "name": "transferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundStake", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": false, + "isSigner": true + }, + { + "name": "insuranceFundVault", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "shares", + "type": "u128" + } + ] + }, + { + "name": "updatePythPullOracle", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "encodedVaa", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "postPythPullOracleUpdateAtomic", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "guardianSet", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "postMultiPythPullOracleUpdatesAtomic", + "accounts": [ + { + "name": "keeper", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "guardianSet", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": "bytes" + } + ] + }, + { + "name": "initialize", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "quoteAssetMint", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializeSpotMarket", + "accounts": [ + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketMint", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "optimalUtilization", + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "type": "u32" + }, + { + "name": "maxBorrowRate", + "type": "u32" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "initialAssetWeight", + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + }, + { + "name": "activeStatus", + "type": "bool" + }, + { + "name": "assetTier", + "type": { + "defined": "AssetTier" + } + }, + { + "name": "scaleInitialAssetWeightStart", + "type": "u64" + }, + { + "name": "withdrawGuardThreshold", + "type": "u64" + }, + { + "name": "orderTickSize", + "type": "u64" + }, + { + "name": "orderStepSize", + "type": "u64" + }, + { + "name": "ifTotalFactor", + "type": "u32" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "deleteInitializedSpotMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "insuranceFundVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "initializeSerumFulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "serumProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "serumMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "serumOpenOrders", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "serumFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "updateSerumFulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "serumFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "initializeOpenbookV2FulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "openbookV2Program", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2Market", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2FulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "openbookV2FulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "openbookV2FulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "initializePhoenixFulfillmentConfig", + "accounts": [ + { + "name": "baseSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "phoenixProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "phoenixFulfillmentConfigStatus", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "phoenixFulfillmentConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + } + ] + }, + { + "name": "updateSerumVault", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "srmVault", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "initializePerpMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "ammBaseAssetReserve", + "type": "u128" + }, + { + "name": "ammQuoteAssetReserve", + "type": "u128" + }, + { + "name": "ammPeriodicity", + "type": "i64" + }, + { + "name": "ammPegMultiplier", + "type": "u128" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "contractTier", + "type": { + "defined": "ContractTier" + } + }, + { + "name": "marginRatioInitial", + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "type": "u32" + }, + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "activeStatus", + "type": "bool" + }, + { + "name": "baseSpread", + "type": "u32" + }, + { + "name": "maxSpread", + "type": "u32" + }, + { + "name": "maxOpenInterest", + "type": "u128" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "type": "u64" + }, + { + "name": "orderStepSize", + "type": "u64" + }, + { + "name": "orderTickSize", + "type": "u64" + }, + { + "name": "minOrderSize", + "type": "u64" + }, + { + "name": "concentrationCoefScale", + "type": "u128" + }, + { + "name": "curveUpdateIntensity", + "type": "u8" + }, + { + "name": "ammJitIntensity", + "type": "u8" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "initializePredictionMarket", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "deleteInitializedPerpMarket", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marketIndex", + "type": "u16" + } + ] + }, + { + "name": "moveAmmPrice", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "baseAssetReserve", + "type": "u128" + }, + { + "name": "quoteAssetReserve", + "type": "u128" + }, + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "recenterPerpMarketAmm", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pegMultiplier", + "type": "u128" + }, + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketAmmSummaryStats", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "UpdatePerpMarketSummaryStatsParams" + } + } + ] + }, + { + "name": "updatePerpMarketExpiry", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "expiryTs", + "type": "i64" + } + ] + }, + { + "name": "settleExpiredMarketPoolsToRevenuePool", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "depositIntoPerpMarketFeePool", + "accounts": [ + { + "name": "state", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "sourceVault", + "isMut": true, + "isSigner": false + }, + { + "name": "driftSigner", + "isMut": false, + "isSigner": false + }, + { + "name": "quoteSpotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "depositIntoSpotMarketVault", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "sourceVault", + "isMut": true, + "isSigner": false + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "depositIntoSpotMarketRevenuePool", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "authority", + "isMut": true, + "isSigner": true + }, + { + "name": "spotMarketVault", + "isMut": true, + "isSigner": false + }, + { + "name": "userTokenAccount", + "isMut": true, + "isSigner": false + }, + { + "name": "tokenProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "repegAmmCurve", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "newPegCandidate", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketAmmOracleTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "resetPerpMarketAmmOracleTwap", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [] + }, + { + "name": "updateK", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "sqrtK", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketMarginRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "marginRatioInitial", + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketFundingPeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fundingPeriod", + "type": "i64" + } + ] + }, + { + "name": "updatePerpMarketMaxImbalances", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "unrealizedMaxImbalance", + "type": "u64" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketLiquidationFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + } + ] + }, + { + "name": "updateInsuranceFundUnstakingPeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "insuranceFundUnstakingPeriod", + "type": "i64" + } + ] + }, + { + "name": "updateSpotMarketLiquidationFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidatorFee", + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "type": "u32" + } + ] + }, + { + "name": "updateWithdrawGuardThreshold", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "withdrawGuardThreshold", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketIfFactor", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "spotMarketIndex", + "type": "u16" + }, + { + "name": "userIfFactor", + "type": "u32" + }, + { + "name": "totalIfFactor", + "type": "u32" + } + ] + }, + { + "name": "updateSpotMarketRevenueSettlePeriod", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "revenueSettlePeriod", + "type": "i64" + } + ] + }, + { + "name": "updateSpotMarketStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + } + ] + }, + { + "name": "updateSpotMarketPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updateSpotMarketAssetTier", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "assetTier", + "type": { + "defined": "AssetTier" + } + } + ] + }, + { + "name": "updateSpotMarketMarginWeights", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "initialAssetWeight", + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "type": "u32" + }, + { + "name": "imfFactor", + "type": "u32" + } + ] + }, + { + "name": "updateSpotMarketBorrowRate", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "optimalUtilization", + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "type": "u32" + }, + { + "name": "maxBorrowRate", + "type": "u32" + }, + { + "name": "minBorrowRate", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "updateSpotMarketMaxTokenDeposits", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxTokenDeposits", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketMaxTokenBorrows", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxTokenBorrowsFraction", + "type": "u16" + } + ] + }, + { + "name": "updateSpotMarketScaleInitialAssetWeightStart", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "scaleInitialAssetWeightStart", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketOracle", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "oracle", + "type": "publicKey" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + } + ] + }, + { + "name": "updateSpotMarketStepSizeAndTickSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "stepSize", + "type": "u64" + }, + { + "name": "tickSize", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketMinOrderSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderSize", + "type": "u64" + } + ] + }, + { + "name": "updateSpotMarketOrdersEnabled", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "ordersEnabled", + "type": "bool" + } + ] + }, + { + "name": "updateSpotMarketIfPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updateSpotMarketName", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updatePerpMarketStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + } + ] + }, + { + "name": "updatePerpMarketPausedOperations", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "pausedOperations", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketContractTier", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "contractTier", + "type": { + "defined": "ContractTier" + } + } + ] + }, + { + "name": "updatePerpMarketImfFactor", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "imfFactor", + "type": "u32" + }, + { + "name": "unrealizedPnlImfFactor", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketUnrealizedAssetWeight", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "unrealizedInitialAssetWeight", + "type": "u32" + }, + { + "name": "unrealizedMaintenanceAssetWeight", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketConcentrationCoef", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "concentrationScale", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketCurveUpdateIntensity", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "curveUpdateIntensity", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketTargetBaseAssetAmountPerLp", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "targetBaseAssetAmountPerLp", + "type": "i32" + } + ] + }, + { + "name": "updatePerpMarketPerLpBase", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "perLpBase", + "type": "i8" + } + ] + }, + { + "name": "updateLpCooldownTime", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "lpCooldownTime", + "type": "u64" + } + ] + }, + { + "name": "updatePerpFeeStructure", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } + } + ] + }, + { + "name": "updateSpotFeeStructure", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeStructure", + "type": { + "defined": "FeeStructure" + } + } + ] + }, + { + "name": "updateInitialPctToLiquidate", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "initialPctToLiquidate", + "type": "u16" + } + ] + }, + { + "name": "updateLiquidationDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidationDuration", + "type": "u8" + } + ] + }, + { + "name": "updateLiquidationMarginBufferRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "liquidationMarginBufferRatio", + "type": "u32" + } + ] + }, + { + "name": "updateOracleGuardRails", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "oracleGuardRails", + "type": { + "defined": "OracleGuardRails" + } + } + ] + }, + { + "name": "updateStateSettlementDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "settlementDuration", + "type": "u16" + } + ] + }, + { + "name": "updateStateMaxNumberOfSubAccounts", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxNumberOfSubAccounts", + "type": "u16" + } + ] + }, + { + "name": "updateStateMaxInitializeUserFee", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxInitializeUserFee", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketOracle", + "accounts": [ + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "oracle", + "isMut": false, + "isSigner": false + }, + { + "name": "admin", + "isMut": false, + "isSigner": true + } + ], + "args": [ + { + "name": "oracle", + "type": "publicKey" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + } + ] + }, + { + "name": "updatePerpMarketBaseSpread", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "baseSpread", + "type": "u32" + } + ] + }, + { + "name": "updateAmmJitIntensity", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "ammJitIntensity", + "type": "u8" + } + ] + }, + { + "name": "updatePerpMarketMaxSpread", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxSpread", + "type": "u32" + } + ] + }, + { + "name": "updatePerpMarketStepSizeAndTickSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "stepSize", + "type": "u64" + }, + { + "name": "tickSize", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketName", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "updatePerpMarketMinOrderSize", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "orderSize", + "type": "u64" + } + ] + }, + { + "name": "updatePerpMarketMaxSlippageRatio", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxSlippageRatio", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketMaxFillReserveFraction", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxFillReserveFraction", + "type": "u16" + } + ] + }, + { + "name": "updatePerpMarketMaxOpenInterest", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "maxOpenInterest", + "type": "u128" + } + ] + }, + { + "name": "updatePerpMarketNumberOfUsers", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "numberOfUsers", + "type": { + "option": "u32" + } + }, + { + "name": "numberOfUsersWithBase", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "updatePerpMarketFeeAdjustment", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeAdjustment", + "type": "i16" + } + ] + }, + { + "name": "updateSpotMarketFeeAdjustment", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "feeAdjustment", + "type": "i16" + } + ] + }, + { + "name": "updatePerpMarketFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostPosition", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "updateSpotMarketFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "spotMarket", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostDeposits", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostBorrows", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostTaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u8" + } + }, + { + "name": "fuelBoostInsurance", + "type": { + "option": "u8" + } + } + ] + }, + { + "name": "initUserFuel", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "user", + "isMut": true, + "isSigner": false + }, + { + "name": "userStats", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "fuelBoostDeposits", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostBorrows", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostTaker", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostMaker", + "type": { + "option": "u32" + } + }, + { + "name": "fuelBoostInsurance", + "type": { + "option": "u32" + } + } + ] + }, + { + "name": "updateAdmin", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "admin", + "type": "publicKey" + } + ] + }, + { + "name": "updateWhitelistMint", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "whitelistMint", + "type": "publicKey" + } + ] + }, + { + "name": "updateDiscountMint", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "discountMint", + "type": "publicKey" + } + ] + }, + { + "name": "updateExchangeStatus", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "exchangeStatus", + "type": "u8" + } + ] + }, + { + "name": "updatePerpAuctionDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "minPerpAuctionDuration", + "type": "u8" + } + ] + }, + { + "name": "updateSpotAuctionDuration", + "accounts": [ + { + "name": "admin", + "isMut": false, + "isSigner": true + }, + { + "name": "state", + "isMut": true, + "isSigner": false + } + ], + "args": [ + { + "name": "defaultSpotAuctionDuration", + "type": "u8" + } + ] + }, + { + "name": "initializeProtocolIfSharesTransferConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "protocolIfSharesTransferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [] + }, + { + "name": "updateProtocolIfSharesTransferConfig", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "protocolIfSharesTransferConfig", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "whitelistedSigners", + "type": { + "option": { + "array": [ + "publicKey", + 4 + ] + } + } + }, + { + "name": "maxTransferPerEpoch", + "type": { + "option": "u128" + } + } + ] + }, + { + "name": "initializePrelaunchOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + }, + { + "name": "rent", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } + } + ] + }, + { + "name": "updatePrelaunchOracleParams", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": true, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "params", + "type": { + "defined": "PrelaunchOracleParams" + } + } + ] + }, + { + "name": "deletePrelaunchOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "prelaunchOracle", + "isMut": true, + "isSigner": false + }, + { + "name": "perpMarket", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "perpMarketIndex", + "type": "u16" + } + ] + }, + { + "name": "initializePythPullOracle", + "accounts": [ + { + "name": "admin", + "isMut": true, + "isSigner": true + }, + { + "name": "pythSolanaReceiver", + "isMut": false, + "isSigner": false + }, + { + "name": "priceFeed", + "isMut": true, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "state", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "feedId", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + ], + "accounts": [ + { + "name": "OpenbookV2FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "openbookV2ProgramId", + "type": "publicKey" + }, + { + "name": "openbookV2Market", + "type": "publicKey" + }, + { + "name": "openbookV2MarketAuthority", + "type": "publicKey" + }, + { + "name": "openbookV2EventHeap", + "type": "publicKey" + }, + { + "name": "openbookV2Bids", + "type": "publicKey" + }, + { + "name": "openbookV2Asks", + "type": "publicKey" + }, + { + "name": "openbookV2BaseVault", + "type": "publicKey" + }, + { + "name": "openbookV2QuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "PhoenixV1FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "phoenixProgramId", + "type": "publicKey" + }, + { + "name": "phoenixLogAuthority", + "type": "publicKey" + }, + { + "name": "phoenixMarket", + "type": "publicKey" + }, + { + "name": "phoenixBaseVault", + "type": "publicKey" + }, + { + "name": "phoenixQuoteVault", + "type": "publicKey" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "SerumV3FulfillmentConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "type": "publicKey" + }, + { + "name": "serumProgramId", + "type": "publicKey" + }, + { + "name": "serumMarket", + "type": "publicKey" + }, + { + "name": "serumRequestQueue", + "type": "publicKey" + }, + { + "name": "serumEventQueue", + "type": "publicKey" + }, + { + "name": "serumBids", + "type": "publicKey" + }, + { + "name": "serumAsks", + "type": "publicKey" + }, + { + "name": "serumBaseVault", + "type": "publicKey" + }, + { + "name": "serumQuoteVault", + "type": "publicKey" + }, + { + "name": "serumOpenOrders", + "type": "publicKey" + }, + { + "name": "serumSignerNonce", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "fulfillmentType", + "type": { + "defined": "SpotFulfillmentType" + } + }, + { + "name": "status", + "type": { + "defined": "SpotFulfillmentConfigStatus" + } + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "insuranceFundStake", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "ifShares", + "type": "u128" + }, + { + "name": "lastWithdrawRequestShares", + "type": "u128" + }, + { + "name": "ifBase", + "type": "u128" + }, + { + "name": "lastValidTs", + "type": "i64" + }, + { + "name": "lastWithdrawRequestValue", + "type": "u64" + }, + { + "name": "lastWithdrawRequestTs", + "type": "i64" + }, + { + "name": "costBasis", + "type": "i64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 14 + ] + } + } + ] + } + }, + { + "name": "ProtocolIfSharesTransferConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "whitelistedSigners", + "type": { + "array": [ + "publicKey", + 4 + ] + } + }, + { + "name": "maxTransferPerEpoch", + "type": "u128" + }, + { + "name": "currentEpochTransfer", + "type": "u128" + }, + { + "name": "nextEpochTs", + "type": "i64" + }, + { + "name": "padding", + "type": { + "array": [ + "u128", + 8 + ] + } + } + ] + } + }, + { + "name": "PrelaunchOracle", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "maxPrice", + "type": "i64" + }, + { + "name": "confidence", + "type": "u64" + }, + { + "name": "lastUpdateSlot", + "type": "u64" + }, + { + "name": "ammLastUpdateSlot", + "type": "u64" + }, + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 70 + ] + } + } + ] + } + }, + { + "name": "PerpMarket", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "docs": [ + "The perp market's address. It is a pda of the market index" + ], + "type": "publicKey" + }, + { + "name": "amm", + "docs": [ + "The automated market maker" + ], + "type": { + "defined": "AMM" + } + }, + { + "name": "pnlPool", + "docs": [ + "The market's pnl pool. When users settle negative pnl, the balance increases.", + "When users settle positive pnl, the balance decreases. Can not go negative." + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "name", + "docs": [ + "Encoded display name for the perp market e.g. SOL-PERP" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "insuranceClaim", + "docs": [ + "The perp market's claim on the insurance fund" + ], + "type": { + "defined": "InsuranceClaim" + } + }, + { + "name": "unrealizedPnlMaxImbalance", + "docs": [ + "The max pnl imbalance before positive pnl asset weight is discounted", + "pnl imbalance is the difference between long and short pnl. When it's greater than 0,", + "the amm has negative pnl and the initial asset weight for positive pnl is discounted", + "precision = QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "expiryTs", + "docs": [ + "The ts when the market will be expired. Only set if market is in reduce only mode" + ], + "type": "i64" + }, + { + "name": "expiryPrice", + "docs": [ + "The price at which positions will be settled. Only set if market is expired", + "precision = PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "nextFillRecordId", + "docs": [ + "Every trade has a fill record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "nextFundingRateRecordId", + "docs": [ + "Every funding rate update has a record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "nextCurveRecordId", + "docs": [ + "Every amm k updated has a record id. This is the next id to be used" + ], + "type": "u64" + }, + { + "name": "imfFactor", + "docs": [ + "The initial margin fraction factor. Used to increase margin ratio for large positions", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlImfFactor", + "docs": [ + "The imf factor for unrealized pnl. Used to discount asset weight for large positive pnl", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "The fee the liquidator is paid for taking over perp position", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "docs": [ + "The fee the insurance fund receives from liquidation", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "marginRatioInitial", + "docs": [ + "The margin ratio which determines how much collateral is required to open a position", + "e.g. margin ratio of .1 means a user must have $100 of total collateral to open a $1000 position", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "marginRatioMaintenance", + "docs": [ + "The margin ratio which determines when a user will be liquidated", + "e.g. margin ratio of .05 means a user must have $50 of total collateral to maintain a $1000 position", + "else they will be liquidated", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlInitialAssetWeight", + "docs": [ + "The initial asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "unrealizedPnlMaintenanceAssetWeight", + "docs": [ + "The maintenance asset weight for positive pnl. Negative pnl always has an asset weight of 1", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "numberOfUsersWithBase", + "docs": [ + "number of users in a position (base)" + ], + "type": "u32" + }, + { + "name": "numberOfUsers", + "docs": [ + "number of users in a position (pnl) or pnl (quote)" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether a market is active, reduce only, expired, etc", + "Affects whether users can open/close positions" + ], + "type": { + "defined": "MarketStatus" + } + }, + { + "name": "contractType", + "docs": [ + "Currently only Perpetual markets are supported" + ], + "type": { + "defined": "ContractType" + } + }, + { + "name": "contractTier", + "docs": [ + "The contract tier determines how much insurance a market can receive, with more speculative markets receiving less insurance", + "It also influences the order perp markets can be liquidated, with less speculative markets being liquidated first" + ], + "type": { + "defined": "ContractTier" + } + }, + { + "name": "pausedOperations", + "type": "u8" + }, + { + "name": "quoteSpotMarketIndex", + "docs": [ + "The spot market that pnl is settled in" + ], + "type": "u16" + }, + { + "name": "feeAdjustment", + "docs": [ + "Between -100 and 100, represents what % to increase/decrease the fee by", + "E.g. if this is -50 and the fee is 5bps, the new fee will be 2.5bps", + "if this is 50 and the fee is 5bps, the new fee will be 7.5bps" + ], + "type": "i16" + }, + { + "name": "fuelBoostPosition", + "docs": [ + "fuel multiplier for perp funding", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for perp taker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for perp maker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 43 + ] + } + } + ] + } + }, + { + "name": "spotMarket", + "type": { + "kind": "struct", + "fields": [ + { + "name": "pubkey", + "docs": [ + "The address of the spot market. It is a pda of the market index" + ], + "type": "publicKey" + }, + { + "name": "oracle", + "docs": [ + "The oracle used to price the markets deposits/borrows" + ], + "type": "publicKey" + }, + { + "name": "mint", + "docs": [ + "The token mint of the market" + ], + "type": "publicKey" + }, + { + "name": "vault", + "docs": [ + "The vault used to store the market's deposits", + "The amount in the vault should be equal to or greater than deposits - borrows" + ], + "type": "publicKey" + }, + { + "name": "name", + "docs": [ + "The encoded display name for the market e.g. SOL" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "historicalOracleData", + "type": { + "defined": "HistoricalOracleData" + } + }, + { + "name": "historicalIndexData", + "type": { + "defined": "HistoricalIndexData" + } + }, + { + "name": "revenuePool", + "docs": [ + "Revenue the protocol has collected in this markets token", + "e.g. for SOL-PERP, funds can be settled in usdc and will flow into the USDC revenue pool" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "spotFeePool", + "docs": [ + "The fees collected from swaps between this market and the quote market", + "Is settled to the quote markets revenue pool" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "insuranceFund", + "docs": [ + "Details on the insurance fund covering bankruptcies in this markets token", + "Covers bankruptcies for borrows with this markets token and perps settling in this markets token" + ], + "type": { + "defined": "InsuranceFund" + } + }, + { + "name": "totalSpotFee", + "docs": [ + "The total spot fees collected for this market", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "depositBalance", + "docs": [ + "The sum of the scaled balances for deposits across users and pool balances", + "To convert to the deposit token amount, multiply by the cumulative deposit interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "borrowBalance", + "docs": [ + "The sum of the scaled balances for borrows across users and pool balances", + "To convert to the borrow token amount, multiply by the cumulative borrow interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeDepositInterest", + "docs": [ + "The cumulative interest earned by depositors", + "Used to calculate the deposit token amount from the deposit balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeBorrowInterest", + "docs": [ + "The cumulative interest earned by borrowers", + "Used to calculate the borrow token amount from the borrow balance", + "precision: SPOT_CUMULATIVE_INTEREST_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the mint's token", + "precision: token mint precision" + ], + "type": "u128" + }, + { + "name": "totalQuoteSocialLoss", + "docs": [ + "The total socialized loss from borrows, in the quote market's token", + "preicision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "withdrawGuardThreshold", + "docs": [ + "no withdraw limits/guards when deposits below this threshold", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "maxTokenDeposits", + "docs": [ + "The max amount of token deposits in this market", + "0 if there is no limit", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "depositTokenTwap", + "docs": [ + "24hr average of deposit token amount", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "borrowTokenTwap", + "docs": [ + "24hr average of borrow token amount", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "utilizationTwap", + "docs": [ + "24hr average of utilization", + "which is borrow amount over token amount", + "precision: SPOT_UTILIZATION_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastInterestTs", + "docs": [ + "Last time the cumulative deposit and borrow interest was updated" + ], + "type": "u64" + }, + { + "name": "lastTwapTs", + "docs": [ + "Last time the deposit/borrow/utilization averages were updated" + ], + "type": "u64" + }, + { + "name": "expiryTs", + "docs": [ + "The time the market is set to expire. Only set if market is in reduce only mode" + ], + "type": "i64" + }, + { + "name": "orderStepSize", + "docs": [ + "Spot orders must be a multiple of the step size", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "orderTickSize", + "docs": [ + "Spot orders must be a multiple of the tick size", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minOrderSize", + "docs": [ + "The minimum order size", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "maxPositionSize", + "docs": [ + "The maximum spot position size", + "if the limit is 0, there is no limit", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "nextFillRecordId", + "docs": [ + "Every spot trade has a fill record id. This is the next id to use" + ], + "type": "u64" + }, + { + "name": "nextDepositRecordId", + "docs": [ + "Every deposit has a deposit record id. This is the next id to use" + ], + "type": "u64" + }, + { + "name": "initialAssetWeight", + "docs": [ + "The initial asset weight used to calculate a deposits contribution to a users initial total collateral", + "e.g. if the asset weight is .8, $100 of deposits contributes $80 to the users initial total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "maintenanceAssetWeight", + "docs": [ + "The maintenance asset weight used to calculate a deposits contribution to a users maintenance total collateral", + "e.g. if the asset weight is .9, $100 of deposits contributes $90 to the users maintenance total collateral", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "initialLiabilityWeight", + "docs": [ + "The initial liability weight used to calculate a borrows contribution to a users initial margin requirement", + "e.g. if the liability weight is .9, $100 of borrows contributes $90 to the users initial margin requirement", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "maintenanceLiabilityWeight", + "docs": [ + "The maintenance liability weight used to calculate a borrows contribution to a users maintenance margin requirement", + "e.g. if the liability weight is .8, $100 of borrows contributes $80 to the users maintenance margin requirement", + "precision: SPOT_WEIGHT_PRECISION" + ], + "type": "u32" + }, + { + "name": "imfFactor", + "docs": [ + "The initial margin fraction factor. Used to increase liability weight/decrease asset weight for large positions", + "precision: MARGIN_PRECISION" + ], + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "The fee the liquidator is paid for taking over borrow/deposit", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "ifLiquidationFee", + "docs": [ + "The fee the insurance fund receives from liquidation", + "precision: LIQUIDATOR_FEE_PRECISION" + ], + "type": "u32" + }, + { + "name": "optimalUtilization", + "docs": [ + "The optimal utilization rate for this market.", + "Used to determine the markets borrow rate", + "precision: SPOT_UTILIZATION_PRECISION" + ], + "type": "u32" + }, + { + "name": "optimalBorrowRate", + "docs": [ + "The borrow rate for this market when the market has optimal utilization", + "precision: SPOT_RATE_PRECISION" + ], + "type": "u32" + }, + { + "name": "maxBorrowRate", + "docs": [ + "The borrow rate for this market when the market has 1000 utilization", + "precision: SPOT_RATE_PRECISION" + ], + "type": "u32" + }, + { + "name": "decimals", + "docs": [ + "The market's token mint's decimals. To from decimals to a precision, 10^decimals" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "ordersEnabled", + "docs": [ + "Whether or not spot trading is enabled" + ], + "type": "bool" + }, + { + "name": "oracleSource", + "type": { + "defined": "OracleSource" + } + }, + { + "name": "status", + "type": { + "defined": "MarketStatus" + } + }, + { + "name": "assetTier", + "docs": [ + "The asset tier affects how a deposit can be used as collateral and the priority for a borrow being liquidated" + ], + "type": { + "defined": "AssetTier" + } + }, + { + "name": "pausedOperations", + "type": "u8" + }, + { + "name": "ifPausedOperations", + "type": "u8" + }, + { + "name": "feeAdjustment", + "type": "i16" + }, + { + "name": "maxTokenBorrowsFraction", + "docs": [ + "What fraction of max_token_deposits", + "disabled when 0, 1 => 1/10000 => .01% of max_token_deposits", + "precision: X/10000" + ], + "type": "u16" + }, + { + "name": "flashLoanAmount", + "docs": [ + "For swaps, the amount of token loaned out in the begin_swap ix", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "flashLoanInitialTokenAmount", + "docs": [ + "For swaps, the amount in the users token account in the begin_swap ix", + "Used to calculate how much of the token left the system in end_swap ix", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "totalSwapFee", + "docs": [ + "The total fees received from swaps", + "precision: token mint precision" + ], + "type": "u64" + }, + { + "name": "scaleInitialAssetWeightStart", + "docs": [ + "When to begin scaling down the initial asset weight", + "disabled when 0", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minBorrowRate", + "docs": [ + "The min borrow rate for this market when the market regardless of utilization", + "1 => 1/200 => .5%", + "precision: X/200" + ], + "type": "u8" + }, + { + "name": "fuelBoostDeposits", + "docs": [ + "fuel multiplier for spot deposits", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostBorrows", + "docs": [ + "fuel multiplier for spot borrows", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostTaker", + "docs": [ + "fuel multiplier for spot taker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostMaker", + "docs": [ + "fuel multiplier for spot maker", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "fuelBoostInsurance", + "docs": [ + "fuel multiplier for spot insurance stake", + "precision: 10" + ], + "type": "u8" + }, + { + "name": "tokenProgram", + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 41 + ] + } + } + ] + } + }, + { + "name": "State", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "publicKey" + }, + { + "name": "whitelistMint", + "type": "publicKey" + }, + { + "name": "discountMint", + "type": "publicKey" + }, + { + "name": "signer", + "type": "publicKey" + }, + { + "name": "srmVault", + "type": "publicKey" + }, + { + "name": "perpFeeStructure", + "type": { + "defined": "FeeStructure" + } + }, + { + "name": "spotFeeStructure", + "type": { + "defined": "FeeStructure" + } + }, + { + "name": "oracleGuardRails", + "type": { + "defined": "OracleGuardRails" + } + }, + { + "name": "numberOfAuthorities", + "type": "u64" + }, + { + "name": "numberOfSubAccounts", + "type": "u64" + }, + { + "name": "lpCooldownTime", + "type": "u64" + }, + { + "name": "liquidationMarginBufferRatio", + "type": "u32" + }, + { + "name": "settlementDuration", + "type": "u16" + }, + { + "name": "numberOfMarkets", + "type": "u16" + }, + { + "name": "numberOfSpotMarkets", + "type": "u16" + }, + { + "name": "signerNonce", + "type": "u8" + }, + { + "name": "minPerpAuctionDuration", + "type": "u8" + }, + { + "name": "defaultMarketOrderTimeInForce", + "type": "u8" + }, + { + "name": "defaultSpotAuctionDuration", + "type": "u8" + }, + { + "name": "exchangeStatus", + "type": "u8" + }, + { + "name": "liquidationDuration", + "type": "u8" + }, + { + "name": "initialPctToLiquidate", + "type": "u16" + }, + { + "name": "maxNumberOfSubAccounts", + "type": "u16" + }, + { + "name": "maxInitializeUserFee", + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 10 + ] + } + } + ] + } + }, + { + "name": "User", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "docs": [ + "The owner/authority of the account" + ], + "type": "publicKey" + }, + { + "name": "delegate", + "docs": [ + "An addresses that can control the account on the authority's behalf. Has limited power, cant withdraw" + ], + "type": "publicKey" + }, + { + "name": "name", + "docs": [ + "Encoded display name e.g. \"toly\"" + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "spotPositions", + "docs": [ + "The user's spot positions" + ], + "type": { + "array": [ + { + "defined": "SpotPosition" + }, + 8 + ] + } + }, + { + "name": "perpPositions", + "docs": [ + "The user's perp positions" + ], + "type": { + "array": [ + { + "defined": "PerpPosition" + }, + 8 + ] + } + }, + { + "name": "orders", + "docs": [ + "The user's orders" + ], + "type": { + "array": [ + { + "defined": "Order" + }, + 32 + ] + } + }, + { + "name": "lastAddPerpLpSharesTs", + "docs": [ + "The last time the user added perp lp positions" + ], + "type": "i64" + }, + { + "name": "totalDeposits", + "docs": [ + "The total values of deposits the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalWithdraws", + "docs": [ + "The total values of withdrawals the user has made", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalSocialLoss", + "docs": [ + "The total socialized loss the users has incurred upon the protocol", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "settledPerpPnl", + "docs": [ + "Fees (taker fees, maker rebate, referrer reward, filler reward) and pnl for perps", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "cumulativeSpotFees", + "docs": [ + "Fees (taker fees, maker rebate, filler reward) for spot", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "cumulativePerpFunding", + "docs": [ + "Cumulative funding paid/received for perps", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "liquidationMarginFreed", + "docs": [ + "The amount of margin freed during liquidation. Used to force the liquidation to occur over a period of time", + "Defaults to zero when not being liquidated", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastActiveSlot", + "docs": [ + "The last slot a user was active. Used to determine if a user is idle" + ], + "type": "u64" + }, + { + "name": "nextOrderId", + "docs": [ + "Every user order has an order id. This is the next order id to be used" + ], + "type": "u32" + }, + { + "name": "maxMarginRatio", + "docs": [ + "Custom max initial margin ratio for the user" + ], + "type": "u32" + }, + { + "name": "nextLiquidationId", + "docs": [ + "The next liquidation id to be used for user" + ], + "type": "u16" + }, + { + "name": "subAccountId", + "docs": [ + "The sub account id for this user" + ], + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether the user is active, being liquidated or bankrupt" + ], + "type": "u8" + }, + { + "name": "isMarginTradingEnabled", + "docs": [ + "Whether the user has enabled margin trading" + ], + "type": "bool" + }, + { + "name": "idle", + "docs": [ + "User is idle if they haven't interacted with the protocol in 1 week and they have no orders, perp positions or borrows", + "Off-chain keeper bots can ignore users that are idle" + ], + "type": "bool" + }, + { + "name": "openOrders", + "docs": [ + "number of open orders" + ], + "type": "u8" + }, + { + "name": "hasOpenOrder", + "docs": [ + "Whether or not user has open order" + ], + "type": "bool" + }, + { + "name": "openAuctions", + "docs": [ + "number of open orders with auction" + ], + "type": "u8" + }, + { + "name": "hasOpenAuction", + "docs": [ + "Whether or not user has open order with auction" + ], + "type": "bool" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 5 + ] + } + }, + { + "name": "lastFuelBonusUpdateTs", + "type": "u32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "UserStats", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "docs": [ + "The authority for all of a users sub accounts" + ], + "type": "publicKey" + }, + { + "name": "referrer", + "docs": [ + "The address that referred this user" + ], + "type": "publicKey" + }, + { + "name": "fees", + "docs": [ + "Stats on the fees paid by the user" + ], + "type": { + "defined": "UserFees" + } + }, + { + "name": "nextEpochTs", + "docs": [ + "The timestamp of the next epoch", + "Epoch is used to limit referrer rewards earned in single epoch" + ], + "type": "i64" + }, + { + "name": "makerVolume30d", + "docs": [ + "Rolling 30day maker volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "takerVolume30d", + "docs": [ + "Rolling 30day taker volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "fillerVolume30d", + "docs": [ + "Rolling 30day filler volume for user", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMakerVolume30dTs", + "docs": [ + "last time the maker volume was updated" + ], + "type": "i64" + }, + { + "name": "lastTakerVolume30dTs", + "docs": [ + "last time the taker volume was updated" + ], + "type": "i64" + }, + { + "name": "lastFillerVolume30dTs", + "docs": [ + "last time the filler volume was updated" + ], + "type": "i64" + }, + { + "name": "ifStakedQuoteAssetAmount", + "docs": [ + "The amount of tokens staked in the quote spot markets if" + ], + "type": "u64" + }, + { + "name": "numberOfSubAccounts", + "docs": [ + "The current number of sub accounts" + ], + "type": "u16" + }, + { + "name": "numberOfSubAccountsCreated", + "docs": [ + "The number of sub accounts created. Can be greater than the number of sub accounts if user", + "has deleted sub accounts" + ], + "type": "u16" + }, + { + "name": "isReferrer", + "docs": [ + "Whether the user is a referrer. Sub account 0 can not be deleted if user is a referrer" + ], + "type": "bool" + }, + { + "name": "disableUpdatePerpBidAskTwap", + "type": "bool" + }, + { + "name": "padding1", + "type": { + "array": [ + "u8", + 2 + ] + } + }, + { + "name": "fuelInsurance", + "docs": [ + "accumulated fuel for token amounts of insurance" + ], + "type": "u32" + }, + { + "name": "fuelDeposits", + "docs": [ + "accumulated fuel for notional of deposits" + ], + "type": "u32" + }, + { + "name": "fuelBorrows", + "docs": [ + "accumulate fuel bonus for notional of borrows" + ], + "type": "u32" + }, + { + "name": "fuelPositions", + "docs": [ + "accumulated fuel for perp open interest" + ], + "type": "u32" + }, + { + "name": "fuelTaker", + "docs": [ + "accumulate fuel bonus for taker volume" + ], + "type": "u32" + }, + { + "name": "fuelMaker", + "docs": [ + "accumulate fuel bonus for maker volume" + ], + "type": "u32" + }, + { + "name": "ifStakedGovTokenAmount", + "docs": [ + "The amount of tokens staked in the governance spot markets if" + ], + "type": "u64" + }, + { + "name": "lastFuelIfBonusUpdateTs", + "docs": [ + "last unix ts user stats data was used to update if fuel (u32 to save space)" + ], + "type": "u32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "ReferrerName", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "publicKey" + }, + { + "name": "user", + "type": "publicKey" + }, + { + "name": "userStats", + "type": "publicKey" + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + } + ], + "types": [ + { + "name": "UpdatePerpMarketSummaryStatsParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "quoteAssetAmountWithUnsettledLp", + "type": { + "option": "i64" + } + }, + { + "name": "netUnsettledFundingPnl", + "type": { + "option": "i64" + } + }, + { + "name": "updateAmmSummaryStats", + "type": { + "option": "bool" + } + } + ] + } + }, + { + "name": "LiquidatePerpRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "oraclePrice", + "type": "i64" + }, + { + "name": "baseAssetAmount", + "type": "i64" + }, + { + "name": "quoteAssetAmount", + "type": "i64" + }, + { + "name": "lpShares", + "docs": [ + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u64" + }, + { + "name": "fillRecordId", + "type": "u64" + }, + { + "name": "userOrderId", + "type": "u32" + }, + { + "name": "liquidatorOrderId", + "type": "u32" + }, + { + "name": "liquidatorFee", + "docs": [ + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "ifFee", + "docs": [ + "precision: QUOTE_PRECISION" + ], + "type": "u64" + } + ] + } + }, + { + "name": "LiquidateSpotRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "assetPrice", + "type": "i64" + }, + { + "name": "assetTransfer", + "type": "u128" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liabilityPrice", + "type": "i64" + }, + { + "name": "liabilityTransfer", + "docs": [ + "precision: token mint precision" + ], + "type": "u128" + }, + { + "name": "ifFee", + "docs": [ + "precision: token mint precision" + ], + "type": "u64" + } + ] + } + }, + { + "name": "LiquidateBorrowForPerpPnlRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "marketOraclePrice", + "type": "i64" + }, + { + "name": "pnlTransfer", + "type": "u128" + }, + { + "name": "liabilityMarketIndex", + "type": "u16" + }, + { + "name": "liabilityPrice", + "type": "i64" + }, + { + "name": "liabilityTransfer", + "type": "u128" + } + ] + } + }, + { + "name": "LiquidatePerpPnlForDepositRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "marketOraclePrice", + "type": "i64" + }, + { + "name": "pnlTransfer", + "type": "u128" + }, + { + "name": "assetMarketIndex", + "type": "u16" + }, + { + "name": "assetPrice", + "type": "i64" + }, + { + "name": "assetTransfer", + "type": "u128" + } + ] + } + }, + { + "name": "PerpBankruptcyRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "pnl", + "type": "i128" + }, + { + "name": "ifPayment", + "type": "u128" + }, + { + "name": "clawbackUser", + "type": { + "option": "publicKey" + } + }, + { + "name": "clawbackUserPayment", + "type": { + "option": "u128" + } + }, + { + "name": "cumulativeFundingRateDelta", + "type": "i128" + } + ] + } + }, + { + "name": "SpotBankruptcyRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "borrowAmount", + "type": "u128" + }, + { + "name": "ifPayment", + "type": "u128" + }, + { + "name": "cumulativeDepositInterestDelta", + "type": "u128" + } + ] + } + }, + { + "name": "MarketIdentifier", + "type": { + "kind": "struct", + "fields": [ + { + "name": "marketType", + "type": { + "defined": "MarketType" + } + }, + { + "name": "marketIndex", + "type": "u16" + } + ] + } + }, + { + "name": "HistoricalOracleData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastOraclePrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOracleConf", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastOracleDelay", + "docs": [ + "number of slots since last update" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwap", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwap5min", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOraclePriceTwapTs", + "docs": [ + "unix_timestamp of last snapshot" + ], + "type": "i64" + } + ] + } + }, + { + "name": "HistoricalIndexData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastIndexBidPrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexAskPrice", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwap", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwap5min", + "docs": [ + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastIndexPriceTwapTs", + "docs": [ + "unix_timestamp of last snapshot" + ], + "type": "i64" + } + ] + } + }, + { + "name": "PrelaunchOracleParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "perpMarketIndex", + "type": "u16" + }, + { + "name": "price", + "type": { + "option": "i64" + } + }, + { + "name": "maxPrice", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "OrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "orderType", + "type": { + "defined": "OrderType" + } + }, + { + "name": "marketType", + "type": { + "defined": "MarketType" + } + }, + { + "name": "direction", + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "userOrderId", + "type": "u8" + }, + { + "name": "baseAssetAmount", + "type": "u64" + }, + { + "name": "price", + "type": "u64" + }, + { + "name": "marketIndex", + "type": "u16" + }, + { + "name": "reduceOnly", + "type": "bool" + }, + { + "name": "postOnly", + "type": { + "defined": "PostOnlyParam" + } + }, + { + "name": "immediateOrCancel", + "type": "bool" + }, + { + "name": "maxTs", + "type": { + "option": "i64" + } + }, + { + "name": "triggerPrice", + "type": { + "option": "u64" + } + }, + { + "name": "triggerCondition", + "type": { + "defined": "OrderTriggerCondition" + } + }, + { + "name": "oraclePriceOffset", + "type": { + "option": "i32" + } + }, + { + "name": "auctionDuration", + "type": { + "option": "u8" + } + }, + { + "name": "auctionStartPrice", + "type": { + "option": "i64" + } + }, + { + "name": "auctionEndPrice", + "type": { + "option": "i64" + } + } + ] + } + }, + { + "name": "ModifyOrderParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "direction", + "type": { + "option": { + "defined": "PositionDirection" + } + } + }, + { + "name": "baseAssetAmount", + "type": { + "option": "u64" + } + }, + { + "name": "price", + "type": { + "option": "u64" + } + }, + { + "name": "reduceOnly", + "type": { + "option": "bool" + } + }, + { + "name": "postOnly", + "type": { + "option": { + "defined": "PostOnlyParam" + } + } + }, + { + "name": "immediateOrCancel", + "type": { + "option": "bool" + } + }, + { + "name": "maxTs", + "type": { + "option": "i64" + } + }, + { + "name": "triggerPrice", + "type": { + "option": "u64" + } + }, + { + "name": "triggerCondition", + "type": { + "option": { + "defined": "OrderTriggerCondition" + } + } + }, + { + "name": "oraclePriceOffset", + "type": { + "option": "i32" + } + }, + { + "name": "auctionDuration", + "type": { + "option": "u8" + } + }, + { + "name": "auctionStartPrice", + "type": { + "option": "i64" + } + }, + { + "name": "auctionEndPrice", + "type": { + "option": "i64" + } + }, + { + "name": "policy", + "type": { + "option": { + "defined": "ModifyOrderPolicy" + } + } + } + ] + } + }, + { + "name": "InsuranceClaim", + "type": { + "kind": "struct", + "fields": [ + { + "name": "revenueWithdrawSinceLastSettle", + "docs": [ + "The amount of revenue last settled", + "Positive if funds left the perp market,", + "negative if funds were pulled into the perp market", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "maxRevenueWithdrawPerPeriod", + "docs": [ + "The max amount of revenue that can be withdrawn per period", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "quoteMaxInsurance", + "docs": [ + "The max amount of insurance that perp market can use to resolve bankruptcy and pnl deficits", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "quoteSettledInsurance", + "docs": [ + "The amount of insurance that has been used to resolve bankruptcy and pnl deficits", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastRevenueWithdrawTs", + "docs": [ + "The last time revenue was settled in/out of market" + ], + "type": "i64" + } + ] + } + }, + { + "name": "PoolBalance", + "type": { + "kind": "struct", + "fields": [ + { + "name": "scaledBalance", + "docs": [ + "To get the pool's token amount, you must multiply the scaled balance by the market's cumulative", + "deposit interest", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u128" + }, + { + "name": "marketIndex", + "docs": [ + "The spot market the pool is for" + ], + "type": "u16" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 6 + ] + } + } + ] + } + }, + { + "name": "AMM", + "type": { + "kind": "struct", + "fields": [ + { + "name": "oracle", + "docs": [ + "oracle price data public key" + ], + "type": "publicKey" + }, + { + "name": "historicalOracleData", + "docs": [ + "stores historically witnessed oracle data" + ], + "type": { + "defined": "HistoricalOracleData" + } + }, + { + "name": "baseAssetAmountPerLp", + "docs": [ + "accumulated base asset amount since inception per lp share", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteAssetAmountPerLp", + "docs": [ + "accumulated quote asset amount since inception per lp share", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "feePool", + "docs": [ + "partition of fees from perp market trading moved from pnl settlements" + ], + "type": { + "defined": "PoolBalance" + } + }, + { + "name": "baseAssetReserve", + "docs": [ + "`x` reserves for constant product mm formula (x * y = k)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "quoteAssetReserve", + "docs": [ + "`y` reserves for constant product mm formula (x * y = k)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "concentrationCoef", + "docs": [ + "determines how close the min/max base asset reserve sit vs base reserves", + "allow for decreasing slippage without increasing liquidity and v.v.", + "precision: PERCENTAGE_PRECISION" + ], + "type": "u128" + }, + { + "name": "minBaseAssetReserve", + "docs": [ + "minimum base_asset_reserve allowed before AMM is unavailable", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "maxBaseAssetReserve", + "docs": [ + "maximum base_asset_reserve allowed before AMM is unavailable", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "sqrtK", + "docs": [ + "`sqrt(k)` in constant product mm formula (x * y = k). stored to avoid drift caused by integer math issues", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "pegMultiplier", + "docs": [ + "normalizing numerical factor for y, its use offers lowest slippage in cp-curve when market is balanced", + "precision: PEG_PRECISION" + ], + "type": "u128" + }, + { + "name": "terminalQuoteAssetReserve", + "docs": [ + "y when market is balanced. stored to save computation", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "baseAssetAmountLong", + "docs": [ + "always non-negative. tracks number of total longs in market (regardless of counterparty)", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountShort", + "docs": [ + "always non-positive. tracks number of total shorts in market (regardless of counterparty)", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountWithAmm", + "docs": [ + "tracks net position (longs-shorts) in market with AMM as counterparty", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "baseAssetAmountWithUnsettledLp", + "docs": [ + "tracks net position (longs-shorts) in market with LPs as counterparty", + "precision: BASE_PRECISION" + ], + "type": "i128" + }, + { + "name": "maxOpenInterest", + "docs": [ + "max allowed open interest, blocks trades that breach this value", + "precision: BASE_PRECISION" + ], + "type": "u128" + }, + { + "name": "quoteAssetAmount", + "docs": [ + "sum of all user's perp quote_asset_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteEntryAmountLong", + "docs": [ + "sum of all long user's quote_entry_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteEntryAmountShort", + "docs": [ + "sum of all short user's quote_entry_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteBreakEvenAmountLong", + "docs": [ + "sum of all long user's quote_break_even_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "quoteBreakEvenAmountShort", + "docs": [ + "sum of all short user's quote_break_even_amount in market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "userLpShares", + "docs": [ + "total user lp shares of sqrt_k (protocol owned liquidity = sqrt_k - last_funding_rate)", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "lastFundingRate", + "docs": [ + "last funding rate in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateLong", + "docs": [ + "last funding rate for longs in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateShort", + "docs": [ + "last funding rate for shorts in this perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "last24hAvgFundingRate", + "docs": [ + "estimate of last 24h of funding rate perp market (unit is quote per base)", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "totalFee", + "docs": [ + "total fees collected by this perp market", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalMmFee", + "docs": [ + "total fees collected by the vAMM's bid/ask spread", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalExchangeFee", + "docs": [ + "total fees collected by exchange fee schedule", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalFeeMinusDistributions", + "docs": [ + "total fees minus any recognized upnl and pool withdraws", + "precision: QUOTE_PRECISION" + ], + "type": "i128" + }, + { + "name": "totalFeeWithdrawn", + "docs": [ + "sum of all fees from fee pool withdrawn to revenue pool", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "totalLiquidationFee", + "docs": [ + "all fees collected by market for liquidations", + "precision: QUOTE_PRECISION" + ], + "type": "u128" + }, + { + "name": "cumulativeFundingRateLong", + "docs": [ + "accumulated funding rate for longs since inception in market" + ], + "type": "i128" + }, + { + "name": "cumulativeFundingRateShort", + "docs": [ + "accumulated funding rate for shorts since inception in market" + ], + "type": "i128" + }, + { + "name": "totalSocialLoss", + "docs": [ + "accumulated social loss paid by users since inception in market" + ], + "type": "u128" + }, + { + "name": "askBaseAssetReserve", + "docs": [ + "transformed base_asset_reserve for users going long", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "askQuoteAssetReserve", + "docs": [ + "transformed quote_asset_reserve for users going long", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "bidBaseAssetReserve", + "docs": [ + "transformed base_asset_reserve for users going short", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "bidQuoteAssetReserve", + "docs": [ + "transformed quote_asset_reserve for users going short", + "precision: AMM_RESERVE_PRECISION" + ], + "type": "u128" + }, + { + "name": "lastOracleNormalisedPrice", + "docs": [ + "the last seen oracle price partially shrunk toward the amm reserve price", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastOracleReservePriceSpreadPct", + "docs": [ + "the gap between the oracle price and the reserve price = y * peg_multiplier / x" + ], + "type": "i64" + }, + { + "name": "lastBidPriceTwap", + "docs": [ + "average estimate of bid price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastAskPriceTwap", + "docs": [ + "average estimate of ask price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwap", + "docs": [ + "average estimate of (bid+ask)/2 price over funding_period", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwap5min", + "docs": [ + "average estimate of (bid+ask)/2 price over FIVE_MINUTES" + ], + "type": "u64" + }, + { + "name": "lastUpdateSlot", + "docs": [ + "the last blockchain slot the amm was updated" + ], + "type": "u64" + }, + { + "name": "lastOracleConfPct", + "docs": [ + "the pct size of the oracle confidence interval", + "precision: PERCENTAGE_PRECISION" + ], + "type": "u64" + }, + { + "name": "netRevenueSinceLastFunding", + "docs": [ + "the total_fee_minus_distribution change since the last funding update", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastFundingRateTs", + "docs": [ + "the last funding rate update unix_timestamp" + ], + "type": "i64" + }, + { + "name": "fundingPeriod", + "docs": [ + "the peridocity of the funding rate updates" + ], + "type": "i64" + }, + { + "name": "orderStepSize", + "docs": [ + "the base step size (increment) of orders", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "orderTickSize", + "docs": [ + "the price tick size of orders", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "minOrderSize", + "docs": [ + "the minimum base size of an order", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "maxPositionSize", + "docs": [ + "the max base size a single user can have", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "volume24h", + "docs": [ + "estimated total of volume in market", + "QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "longIntensityVolume", + "docs": [ + "the volume intensity of long fills against AMM" + ], + "type": "u64" + }, + { + "name": "shortIntensityVolume", + "docs": [ + "the volume intensity of short fills against AMM" + ], + "type": "u64" + }, + { + "name": "lastTradeTs", + "docs": [ + "the blockchain unix timestamp at the time of the last trade" + ], + "type": "i64" + }, + { + "name": "markStd", + "docs": [ + "estimate of standard deviation of the fill (mark) prices", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "oracleStd", + "docs": [ + "estimate of standard deviation of the oracle price at each update", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastMarkPriceTwapTs", + "docs": [ + "the last unix_timestamp the mark twap was updated" + ], + "type": "i64" + }, + { + "name": "baseSpread", + "docs": [ + "the minimum spread the AMM can quote. also used as step size for some spread logic increases." + ], + "type": "u32" + }, + { + "name": "maxSpread", + "docs": [ + "the maximum spread the AMM can quote" + ], + "type": "u32" + }, + { + "name": "longSpread", + "docs": [ + "the spread for asks vs the reserve price" + ], + "type": "u32" + }, + { + "name": "shortSpread", + "docs": [ + "the spread for bids vs the reserve price" + ], + "type": "u32" + }, + { + "name": "longIntensityCount", + "docs": [ + "the count intensity of long fills against AMM" + ], + "type": "u32" + }, + { + "name": "shortIntensityCount", + "docs": [ + "the count intensity of short fills against AMM" + ], + "type": "u32" + }, + { + "name": "maxFillReserveFraction", + "docs": [ + "the fraction of total available liquidity a single fill on the AMM can consume" + ], + "type": "u16" + }, + { + "name": "maxSlippageRatio", + "docs": [ + "the maximum slippage a single fill on the AMM can push" + ], + "type": "u16" + }, + { + "name": "curveUpdateIntensity", + "docs": [ + "the update intensity of AMM formulaic updates (adjusting k). 0-100" + ], + "type": "u8" + }, + { + "name": "ammJitIntensity", + "docs": [ + "the jit intensity of AMM. larger intensity means larger participation in jit. 0 means no jit participation.", + "(0, 100] is intensity for protocol-owned AMM. (100, 200] is intensity for user LP-owned AMM." + ], + "type": "u8" + }, + { + "name": "oracleSource", + "docs": [ + "the oracle provider information. used to decode/scale the oracle public key" + ], + "type": { + "defined": "OracleSource" + } + }, + { + "name": "lastOracleValid", + "docs": [ + "tracks whether the oracle was considered valid at the last AMM update" + ], + "type": "bool" + }, + { + "name": "targetBaseAssetAmountPerLp", + "docs": [ + "the target value for `base_asset_amount_per_lp`, used during AMM JIT with LP split", + "precision: BASE_PRECISION" + ], + "type": "i32" + }, + { + "name": "perLpBase", + "docs": [ + "expo for unit of per_lp, base 10 (if per_lp_base=X, then per_lp unit is 10^X)" + ], + "type": "i8" + }, + { + "name": "padding1", + "type": "u8" + }, + { + "name": "padding2", + "type": "u16" + }, + { + "name": "totalFeeEarnedPerLp", + "type": "u64" + }, + { + "name": "netUnsettledFundingPnl", + "type": "i64" + }, + { + "name": "quoteAssetAmountWithUnsettledLp", + "type": "i64" + }, + { + "name": "referencePriceOffset", + "type": "i32" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 12 + ] + } + } + ] + } + }, + { + "name": "InsuranceFund", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "totalShares", + "type": "u128" + }, + { + "name": "userShares", + "type": "u128" + }, + { + "name": "sharesBase", + "type": "u128" + }, + { + "name": "unstakingPeriod", + "type": "i64" + }, + { + "name": "lastRevenueSettleTs", + "type": "i64" + }, + { + "name": "revenueSettlePeriod", + "type": "i64" + }, + { + "name": "totalFactor", + "type": "u32" + }, + { + "name": "userFactor", + "type": "u32" + } + ] + } + }, + { + "name": "OracleGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "priceDivergence", + "type": { + "defined": "PriceDivergenceGuardRails" + } + }, + { + "name": "validity", + "type": { + "defined": "ValidityGuardRails" + } + } + ] + } + }, + { + "name": "PriceDivergenceGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "markOraclePercentDivergence", + "type": "u64" + }, + { + "name": "oracleTwap5minPercentDivergence", + "type": "u64" + } + ] + } + }, + { + "name": "ValidityGuardRails", + "type": { + "kind": "struct", + "fields": [ + { + "name": "slotsBeforeStaleForAmm", + "type": "i64" + }, + { + "name": "slotsBeforeStaleForMargin", + "type": "i64" + }, + { + "name": "confidenceIntervalMaxSize", + "type": "u64" + }, + { + "name": "tooVolatileRatio", + "type": "i64" + } + ] + } + }, + { + "name": "FeeStructure", + "type": { + "kind": "struct", + "fields": [ + { + "name": "feeTiers", + "type": { + "array": [ + { + "defined": "FeeTier" + }, + 10 + ] + } + }, + { + "name": "fillerRewardStructure", + "type": { + "defined": "OrderFillerRewardStructure" + } + }, + { + "name": "referrerRewardEpochUpperBound", + "type": "u64" + }, + { + "name": "flatFillerFee", + "type": "u64" + } + ] + } + }, + { + "name": "FeeTier", + "type": { + "kind": "struct", + "fields": [ + { + "name": "feeNumerator", + "type": "u32" + }, + { + "name": "feeDenominator", + "type": "u32" + }, + { + "name": "makerRebateNumerator", + "type": "u32" + }, + { + "name": "makerRebateDenominator", + "type": "u32" + }, + { + "name": "referrerRewardNumerator", + "type": "u32" + }, + { + "name": "referrerRewardDenominator", + "type": "u32" + }, + { + "name": "refereeFeeNumerator", + "type": "u32" + }, + { + "name": "refereeFeeDenominator", + "type": "u32" + } + ] + } + }, + { + "name": "OrderFillerRewardStructure", + "type": { + "kind": "struct", + "fields": [ + { + "name": "rewardNumerator", + "type": "u32" + }, + { + "name": "rewardDenominator", + "type": "u32" + }, + { + "name": "timeBasedRewardLowerBound", + "type": "u128" + } + ] + } + }, + { + "name": "UserFees", + "type": { + "kind": "struct", + "fields": [ + { + "name": "totalFeePaid", + "docs": [ + "Total taker fee paid", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalFeeRebate", + "docs": [ + "Total maker fee rebate", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalTokenDiscount", + "docs": [ + "Total discount from holding token", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalRefereeDiscount", + "docs": [ + "Total discount from being referred", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "totalReferrerReward", + "docs": [ + "Total reward to referrer", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "currentEpochReferrerReward", + "docs": [ + "Total reward to referrer this epoch", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + } + ] + } + }, + { + "name": "SpotPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "scaledBalance", + "docs": [ + "The scaled balance of the position. To get the token amount, multiply by the cumulative deposit/borrow", + "interest of corresponding market.", + "precision: SPOT_BALANCE_PRECISION" + ], + "type": "u64" + }, + { + "name": "openBids", + "docs": [ + "How many spot bids the user has open", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "openAsks", + "docs": [ + "How many spot asks the user has open", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "cumulativeDeposits", + "docs": [ + "The cumulative deposits/borrows a user has made into a market", + "precision: token mint precision" + ], + "type": "i64" + }, + { + "name": "marketIndex", + "docs": [ + "The market index of the corresponding spot market" + ], + "type": "u16" + }, + { + "name": "balanceType", + "docs": [ + "Whether the position is deposit or borrow" + ], + "type": { + "defined": "SpotBalanceType" + } + }, + { + "name": "openOrders", + "docs": [ + "Number of open orders" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 4 + ] + } + } + ] + } + }, + { + "name": "PerpPosition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "lastCumulativeFundingRate", + "docs": [ + "The perp market's last cumulative funding rate. Used to calculate the funding payment owed to user", + "precision: FUNDING_RATE_PRECISION" + ], + "type": "i64" + }, + { + "name": "baseAssetAmount", + "docs": [ + "the size of the users perp position", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteAssetAmount", + "docs": [ + "Used to calculate the users pnl. Upon entry, is equal to base_asset_amount * avg entry price - fees", + "Updated when the user open/closes position or settles pnl. Includes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteBreakEvenAmount", + "docs": [ + "The amount of quote the user would need to exit their position at to break even", + "Updated when the user open/closes position or settles pnl. Includes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "quoteEntryAmount", + "docs": [ + "The amount quote the user entered the position with. Equal to base asset amount * avg entry price", + "Updated when the user open/closes position. Excludes fees/funding", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "openBids", + "docs": [ + "The amount of open bids the user has in this perp market", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "openAsks", + "docs": [ + "The amount of open asks the user has in this perp market", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "settledPnl", + "docs": [ + "The amount of pnl settled in this market since opening the position", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lpShares", + "docs": [ + "The number of lp (liquidity provider) shares the user has in this perp market", + "LP shares allow users to provide liquidity via the AMM", + "precision: BASE_PRECISION" + ], + "type": "u64" + }, + { + "name": "lastBaseAssetAmountPerLp", + "docs": [ + "The last base asset amount per lp the amm had", + "Used to settle the users lp position", + "precision: BASE_PRECISION" + ], + "type": "i64" + }, + { + "name": "lastQuoteAssetAmountPerLp", + "docs": [ + "The last quote asset amount per lp the amm had", + "Used to settle the users lp position", + "precision: QUOTE_PRECISION" + ], + "type": "i64" + }, + { + "name": "remainderBaseAssetAmount", + "docs": [ + "Settling LP position can lead to a small amount of base asset being left over smaller than step size", + "This records that remainder so it can be settled later on", + "precision: BASE_PRECISION" + ], + "type": "i32" + }, + { + "name": "marketIndex", + "docs": [ + "The market index for the perp market" + ], + "type": "u16" + }, + { + "name": "openOrders", + "docs": [ + "The number of open orders" + ], + "type": "u8" + }, + { + "name": "perLpBase", + "type": "i8" + } + ] + } + }, + { + "name": "Order", + "type": { + "kind": "struct", + "fields": [ + { + "name": "slot", + "docs": [ + "The slot the order was placed" + ], + "type": "u64" + }, + { + "name": "price", + "docs": [ + "The limit price for the order (can be 0 for market orders)", + "For orders with an auction, this price isn't used until the auction is complete", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "baseAssetAmount", + "docs": [ + "The size of the order", + "precision for perps: BASE_PRECISION", + "precision for spot: token mint precision" + ], + "type": "u64" + }, + { + "name": "baseAssetAmountFilled", + "docs": [ + "The amount of the order filled", + "precision for perps: BASE_PRECISION", + "precision for spot: token mint precision" + ], + "type": "u64" + }, + { + "name": "quoteAssetAmountFilled", + "docs": [ + "The amount of quote filled for the order", + "precision: QUOTE_PRECISION" + ], + "type": "u64" + }, + { + "name": "triggerPrice", + "docs": [ + "At what price the order will be triggered. Only relevant for trigger orders", + "precision: PRICE_PRECISION" + ], + "type": "u64" + }, + { + "name": "auctionStartPrice", + "docs": [ + "The start price for the auction. Only relevant for market/oracle orders", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "auctionEndPrice", + "docs": [ + "The end price for the auction. Only relevant for market/oracle orders", + "precision: PRICE_PRECISION" + ], + "type": "i64" + }, + { + "name": "maxTs", + "docs": [ + "The time when the order will expire" + ], + "type": "i64" + }, + { + "name": "oraclePriceOffset", + "docs": [ + "If set, the order limit price is the oracle price + this offset", + "precision: PRICE_PRECISION" + ], + "type": "i32" + }, + { + "name": "orderId", + "docs": [ + "The id for the order. Each users has their own order id space" + ], + "type": "u32" + }, + { + "name": "marketIndex", + "docs": [ + "The perp/spot market index" + ], + "type": "u16" + }, + { + "name": "status", + "docs": [ + "Whether the order is open or unused" + ], + "type": { + "defined": "OrderStatus" + } + }, + { + "name": "orderType", + "docs": [ + "The type of order" + ], + "type": { + "defined": "OrderType" + } + }, + { + "name": "marketType", + "docs": [ + "Whether market is spot or perp" + ], + "type": { + "defined": "MarketType" + } + }, + { + "name": "userOrderId", + "docs": [ + "User generated order id. Can make it easier to place/cancel orders" + ], + "type": "u8" + }, + { + "name": "existingPositionDirection", + "docs": [ + "What the users position was when the order was placed" + ], + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "direction", + "docs": [ + "Whether the user is going long or short. LONG = bid, SHORT = ask" + ], + "type": { + "defined": "PositionDirection" + } + }, + { + "name": "reduceOnly", + "docs": [ + "Whether the order is allowed to only reduce position size" + ], + "type": "bool" + }, + { + "name": "postOnly", + "docs": [ + "Whether the order must be a maker" + ], + "type": "bool" + }, + { + "name": "immediateOrCancel", + "docs": [ + "Whether the order must be canceled the same slot it is placed" + ], + "type": "bool" + }, + { + "name": "triggerCondition", + "docs": [ + "Whether the order is triggered above or below the trigger price. Only relevant for trigger orders" + ], + "type": { + "defined": "OrderTriggerCondition" + } + }, + { + "name": "auctionDuration", + "docs": [ + "How many slots the auction lasts" + ], + "type": "u8" + }, + { + "name": "padding", + "type": { + "array": [ + "u8", + 3 + ] + } + } + ] + } + }, + { + "name": "SwapDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Add" + }, + { + "name": "Remove" + } + ] + } + }, + { + "name": "ModifyOrderId", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UserOrderId", + "fields": [ + "u8" + ] + }, + { + "name": "OrderId", + "fields": [ + "u32" + ] + } + ] + } + }, + { + "name": "PositionDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Long" + }, + { + "name": "Short" + } + ] + } + }, + { + "name": "SpotFulfillmentType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "SerumV3" + }, + { + "name": "Match" + }, + { + "name": "PhoenixV1" + }, + { + "name": "OpenbookV2" + } + ] + } + }, + { + "name": "SwapReduceOnly", + "type": { + "kind": "enum", + "variants": [ + { + "name": "In" + }, + { + "name": "Out" + } + ] + } + }, + { + "name": "TwapPeriod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "FundingPeriod" + }, + { + "name": "FiveMin" + } + ] + } + }, + { + "name": "LiquidationMultiplierType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Discount" + }, + { + "name": "Premium" + } + ] + } + }, + { + "name": "MarginRequirementType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Initial" + }, + { + "name": "Fill" + }, + { + "name": "Maintenance" + } + ] + } + }, + { + "name": "OracleValidity", + "type": { + "kind": "enum", + "variants": [ + { + "name": "NonPositive" + }, + { + "name": "TooVolatile" + }, + { + "name": "TooUncertain" + }, + { + "name": "StaleForMargin" + }, + { + "name": "InsufficientDataPoints" + }, + { + "name": "StaleForAMM" + }, + { + "name": "Valid" + } + ] + } + }, + { + "name": "DriftAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateFunding" + }, + { + "name": "SettlePnl" + }, + { + "name": "TriggerOrder" + }, + { + "name": "FillOrderMatch" + }, + { + "name": "FillOrderAmm" + }, + { + "name": "Liquidate" + }, + { + "name": "MarginCalc" + }, + { + "name": "UpdateTwap" + }, + { + "name": "UpdateAMMCurve" + }, + { + "name": "OracleOrderPrice" + } + ] + } + }, + { + "name": "PositionUpdateType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Open" + }, + { + "name": "Increase" + }, + { + "name": "Reduce" + }, + { + "name": "Close" + }, + { + "name": "Flip" + } + ] + } + }, + { + "name": "DepositExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "Transfer" + }, + { + "name": "Borrow" + }, + { + "name": "RepayBorrow" + } + ] + } + }, + { + "name": "DepositDirection", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Deposit" + }, + { + "name": "Withdraw" + } + ] + } + }, + { + "name": "OrderAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Place" + }, + { + "name": "Cancel" + }, + { + "name": "Fill" + }, + { + "name": "Trigger" + }, + { + "name": "Expire" + } + ] + } + }, + { + "name": "OrderActionExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "InsufficientFreeCollateral" + }, + { + "name": "OraclePriceBreachedLimitPrice" + }, + { + "name": "MarketOrderFilledToLimitPrice" + }, + { + "name": "OrderExpired" + }, + { + "name": "Liquidation" + }, + { + "name": "OrderFilledWithAMM" + }, + { + "name": "OrderFilledWithAMMJit" + }, + { + "name": "OrderFilledWithMatch" + }, + { + "name": "OrderFilledWithMatchJit" + }, + { + "name": "MarketExpired" + }, + { + "name": "RiskingIncreasingOrder" + }, + { + "name": "ReduceOnlyOrderIncreasedPosition" + }, + { + "name": "OrderFillWithSerum" + }, + { + "name": "NoBorrowLiquidity" + }, + { + "name": "OrderFillWithPhoenix" + }, + { + "name": "OrderFilledWithAMMJitLPSplit" + }, + { + "name": "OrderFilledWithLPJit" + }, + { + "name": "DeriskLp" + }, + { + "name": "OrderFilledWithOpenbookV2" + } + ] + } + }, + { + "name": "LPAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AddLiquidity" + }, + { + "name": "RemoveLiquidity" + }, + { + "name": "SettleLiquidity" + }, + { + "name": "RemoveLiquidityDerisk" + } + ] + } + }, + { + "name": "LiquidationType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "LiquidatePerp" + }, + { + "name": "LiquidateSpot" + }, + { + "name": "LiquidateBorrowForPerpPnl" + }, + { + "name": "LiquidatePerpPnlForDeposit" + }, + { + "name": "PerpBankruptcy" + }, + { + "name": "SpotBankruptcy" + } + ] + } + }, + { + "name": "SettlePnlExplanation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "ExpiredPosition" + } + ] + } + }, + { + "name": "StakeAction", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Stake" + }, + { + "name": "UnstakeRequest" + }, + { + "name": "UnstakeCancelRequest" + }, + { + "name": "Unstake" + }, + { + "name": "UnstakeTransfer" + }, + { + "name": "StakeTransfer" + } + ] + } + }, + { + "name": "FillMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Fill" + }, + { + "name": "PlaceAndMake" + }, + { + "name": "PlaceAndTake" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "PerpFulfillmentMethod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "AMM", + "fields": [ + { + "option": "u64" + } + ] + }, + { + "name": "Match", + "fields": [ + "publicKey", + "u16" + ] + } + ] + } + }, + { + "name": "SpotFulfillmentMethod", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ExternalMarket" + }, + { + "name": "Match", + "fields": [ + "publicKey", + "u16" + ] + } + ] + } + }, + { + "name": "MarginCalculationMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Standard", + "fields": [ + { + "name": "trackOpenOrdersFraction", + "type": "bool" + } + ] + }, + { + "name": "Liquidation", + "fields": [ + { + "name": "marketToTrackMarginRequirement", + "type": { + "option": { + "defined": "MarketIdentifier" + } + } + } + ] + } + ] + } + }, + { + "name": "OracleSource", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Pyth" + }, + { + "name": "Switchboard" + }, + { + "name": "QuoteAsset" + }, + { + "name": "Pyth1K" + }, + { + "name": "Pyth1M" + }, + { + "name": "PythStableCoin" + }, + { + "name": "Prelaunch" + }, + { + "name": "PythPull" + }, + { + "name": "Pyth1KPull" + }, + { + "name": "Pyth1MPull" + }, + { + "name": "PythStableCoinPull" + }, + { + "name": "SwitchboardOnDemand" + } + ] + } + }, + { + "name": "PostOnlyParam", + "type": { + "kind": "enum", + "variants": [ + { + "name": "None" + }, + { + "name": "MustPostOnly" + }, + { + "name": "TryPostOnly" + }, + { + "name": "Slide" + } + ] + } + }, + { + "name": "ModifyOrderPolicy", + "type": { + "kind": "enum", + "variants": [ + { + "name": "TryModify" + }, + { + "name": "MustModify" + } + ] + } + }, + { + "name": "PerpOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateFunding" + }, + { + "name": "AmmFill" + }, + { + "name": "Fill" + }, + { + "name": "SettlePnl" + }, + { + "name": "SettlePnlWithPosition" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "SpotOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "UpdateCumulativeInterest" + }, + { + "name": "Fill" + }, + { + "name": "Deposit" + }, + { + "name": "Withdraw" + }, + { + "name": "Liquidation" + } + ] + } + }, + { + "name": "InsuranceFundOperation", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Init" + }, + { + "name": "Add" + }, + { + "name": "RequestRemove" + }, + { + "name": "Remove" + } + ] + } + }, + { + "name": "MarketStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Initialized" + }, + { + "name": "Active" + }, + { + "name": "FundingPaused" + }, + { + "name": "AmmPaused" + }, + { + "name": "FillPaused" + }, + { + "name": "WithdrawPaused" + }, + { + "name": "ReduceOnly" + }, + { + "name": "Settlement" + }, + { + "name": "Delisted" + } + ] + } + }, + { + "name": "ContractType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Perpetual" + }, + { + "name": "Future" + }, + { + "name": "Prediction" + } + ] + } + }, + { + "name": "ContractTier", + "type": { + "kind": "enum", + "variants": [ + { + "name": "A" + }, + { + "name": "B" + }, + { + "name": "C" + }, + { + "name": "Speculative" + }, + { + "name": "HighlySpeculative" + }, + { + "name": "Isolated" + } + ] + } + }, + { + "name": "AMMLiquiditySplit", + "type": { + "kind": "enum", + "variants": [ + { + "name": "ProtocolOwned" + }, + { + "name": "LPOwned" + }, + { + "name": "Shared" + } + ] + } + }, + { + "name": "SettlePnlMode", + "type": { + "kind": "enum", + "variants": [ + { + "name": "MustSettle" + }, + { + "name": "TrySettle" + } + ] + } + }, + { + "name": "SpotBalanceType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Deposit" + }, + { + "name": "Borrow" + } + ] + } + }, + { + "name": "SpotFulfillmentConfigStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Enabled" + }, + { + "name": "Disabled" + } + ] + } + }, + { + "name": "AssetTier", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Collateral" + }, + { + "name": "Protected" + }, + { + "name": "Cross" + }, + { + "name": "Isolated" + }, + { + "name": "Unlisted" + } + ] + } + }, + { + "name": "ExchangeStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "DepositPaused" + }, + { + "name": "WithdrawPaused" + }, + { + "name": "AmmPaused" + }, + { + "name": "FillPaused" + }, + { + "name": "LiqPaused" + }, + { + "name": "FundingPaused" + }, + { + "name": "SettlePnlPaused" + } + ] + } + }, + { + "name": "UserStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "BeingLiquidated" + }, + { + "name": "Bankrupt" + }, + { + "name": "ReduceOnly" + }, + { + "name": "AdvancedLp" + } + ] + } + }, + { + "name": "AssetType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Base" + }, + { + "name": "Quote" + } + ] + } + }, + { + "name": "OrderStatus", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Init" + }, + { + "name": "Open" + }, + { + "name": "Filled" + }, + { + "name": "Canceled" + } + ] + } + }, + { + "name": "OrderType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Market" + }, + { + "name": "Limit" + }, + { + "name": "TriggerMarket" + }, + { + "name": "TriggerLimit" + }, + { + "name": "Oracle" + } + ] + } + }, + { + "name": "OrderTriggerCondition", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Above" + }, + { + "name": "Below" + }, + { + "name": "TriggeredAbove" + }, + { + "name": "TriggeredBelow" + } + ] + } + }, + { + "name": "MarketType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Spot" + }, + { + "name": "Perp" + } + ] + } + } + ], + "events": [ + { + "name": "NewUserRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "subAccountId", + "type": "u16", + "index": false + }, + { + "name": "name", + "type": { + "array": [ + "u8", + 32 + ] + }, + "index": false + }, + { + "name": "referrer", + "type": "publicKey", + "index": false + } + ] + }, + { + "name": "DepositRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "direction", + "type": { + "defined": "DepositDirection" + }, + "index": false + }, + { + "name": "depositRecordId", + "type": "u64", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + }, + { + "name": "marketDepositBalance", + "type": "u128", + "index": false + }, + { + "name": "marketWithdrawBalance", + "type": "u128", + "index": false + }, + { + "name": "marketCumulativeDepositInterest", + "type": "u128", + "index": false + }, + { + "name": "marketCumulativeBorrowInterest", + "type": "u128", + "index": false + }, + { + "name": "totalDepositsAfter", + "type": "u64", + "index": false + }, + { + "name": "totalWithdrawsAfter", + "type": "u64", + "index": false + }, + { + "name": "explanation", + "type": { + "defined": "DepositExplanation" + }, + "index": false + }, + { + "name": "transferUser", + "type": { + "option": "publicKey" + }, + "index": false + } + ] + }, + { + "name": "SpotInterestRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "depositBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterest", + "type": "u128", + "index": false + }, + { + "name": "borrowBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeBorrowInterest", + "type": "u128", + "index": false + }, + { + "name": "optimalUtilization", + "type": "u32", + "index": false + }, + { + "name": "optimalBorrowRate", + "type": "u32", + "index": false + }, + { + "name": "maxBorrowRate", + "type": "u32", + "index": false + } + ] + }, + { + "name": "FundingPaymentRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "fundingPayment", + "type": "i64", + "index": false + }, + { + "name": "baseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "userLastCumulativeFunding", + "type": "i64", + "index": false + }, + { + "name": "ammCumulativeFundingLong", + "type": "i128", + "index": false + }, + { + "name": "ammCumulativeFundingShort", + "type": "i128", + "index": false + } + ] + }, + { + "name": "FundingRateRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "recordId", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "fundingRate", + "type": "i64", + "index": false + }, + { + "name": "fundingRateLong", + "type": "i128", + "index": false + }, + { + "name": "fundingRateShort", + "type": "i128", + "index": false + }, + { + "name": "cumulativeFundingRateLong", + "type": "i128", + "index": false + }, + { + "name": "cumulativeFundingRateShort", + "type": "i128", + "index": false + }, + { + "name": "oraclePriceTwap", + "type": "i64", + "index": false + }, + { + "name": "markPriceTwap", + "type": "u64", + "index": false + }, + { + "name": "periodRevenue", + "type": "i64", + "index": false + }, + { + "name": "baseAssetAmountWithAmm", + "type": "i128", + "index": false + }, + { + "name": "baseAssetAmountWithUnsettledLp", + "type": "i128", + "index": false + } + ] + }, + { + "name": "CurveRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "recordId", + "type": "u64", + "index": false + }, + { + "name": "pegMultiplierBefore", + "type": "u128", + "index": false + }, + { + "name": "baseAssetReserveBefore", + "type": "u128", + "index": false + }, + { + "name": "quoteAssetReserveBefore", + "type": "u128", + "index": false + }, + { + "name": "sqrtKBefore", + "type": "u128", + "index": false + }, + { + "name": "pegMultiplierAfter", + "type": "u128", + "index": false + }, + { + "name": "baseAssetReserveAfter", + "type": "u128", + "index": false + }, + { + "name": "quoteAssetReserveAfter", + "type": "u128", + "index": false + }, + { + "name": "sqrtKAfter", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountLong", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountShort", + "type": "u128", + "index": false + }, + { + "name": "baseAssetAmountWithAmm", + "type": "i128", + "index": false + }, + { + "name": "totalFee", + "type": "i128", + "index": false + }, + { + "name": "totalFeeMinusDistributions", + "type": "i128", + "index": false + }, + { + "name": "adjustmentCost", + "type": "i128", + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + }, + { + "name": "fillRecord", + "type": "u128", + "index": false + }, + { + "name": "numberOfUsers", + "type": "u32", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + } + ] + }, + { + "name": "OrderRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "order", + "type": { + "defined": "Order" + }, + "index": false + } + ] + }, + { + "name": "OrderActionRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "action", + "type": { + "defined": "OrderAction" + }, + "index": false + }, + { + "name": "actionExplanation", + "type": { + "defined": "OrderActionExplanation" + }, + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "marketType", + "type": { + "defined": "MarketType" + }, + "index": false + }, + { + "name": "filler", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "fillerReward", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "fillRecordId", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "baseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "quoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerFee", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerFee", + "type": { + "option": "i64" + }, + "index": false + }, + { + "name": "referrerReward", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "quoteAssetAmountSurplus", + "type": { + "option": "i64" + }, + "index": false + }, + { + "name": "spotFulfillmentMethodFee", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "taker", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "takerOrderId", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "takerOrderDirection", + "type": { + "option": { + "defined": "PositionDirection" + } + }, + "index": false + }, + { + "name": "takerOrderBaseAssetAmount", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerOrderCumulativeBaseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "takerOrderCumulativeQuoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "maker", + "type": { + "option": "publicKey" + }, + "index": false + }, + { + "name": "makerOrderId", + "type": { + "option": "u32" + }, + "index": false + }, + { + "name": "makerOrderDirection", + "type": { + "option": { + "defined": "PositionDirection" + } + }, + "index": false + }, + { + "name": "makerOrderBaseAssetAmount", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerOrderCumulativeBaseAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "makerOrderCumulativeQuoteAssetAmountFilled", + "type": { + "option": "u64" + }, + "index": false + }, + { + "name": "oraclePrice", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LPRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "action", + "type": { + "defined": "LPAction" + }, + "index": false + }, + { + "name": "nShares", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "deltaBaseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "deltaQuoteAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "pnl", + "type": "i64", + "index": false + } + ] + }, + { + "name": "LiquidationRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "liquidationType", + "type": { + "defined": "LiquidationType" + }, + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "liquidator", + "type": "publicKey", + "index": false + }, + { + "name": "marginRequirement", + "type": "u128", + "index": false + }, + { + "name": "totalCollateral", + "type": "i128", + "index": false + }, + { + "name": "marginFreed", + "type": "u64", + "index": false + }, + { + "name": "liquidationId", + "type": "u16", + "index": false + }, + { + "name": "bankrupt", + "type": "bool", + "index": false + }, + { + "name": "canceledOrderIds", + "type": { + "vec": "u32" + }, + "index": false + }, + { + "name": "liquidatePerp", + "type": { + "defined": "LiquidatePerpRecord" + }, + "index": false + }, + { + "name": "liquidateSpot", + "type": { + "defined": "LiquidateSpotRecord" + }, + "index": false + }, + { + "name": "liquidateBorrowForPerpPnl", + "type": { + "defined": "LiquidateBorrowForPerpPnlRecord" + }, + "index": false + }, + { + "name": "liquidatePerpPnlForDeposit", + "type": { + "defined": "LiquidatePerpPnlForDepositRecord" + }, + "index": false + }, + { + "name": "perpBankruptcy", + "type": { + "defined": "PerpBankruptcyRecord" + }, + "index": false + }, + { + "name": "spotBankruptcy", + "type": { + "defined": "SpotBankruptcyRecord" + }, + "index": false + } + ] + }, + { + "name": "SettlePnlRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "pnl", + "type": "i128", + "index": false + }, + { + "name": "baseAssetAmount", + "type": "i64", + "index": false + }, + { + "name": "quoteAssetAmountAfter", + "type": "i64", + "index": false + }, + { + "name": "quoteEntryAmount", + "type": "i64", + "index": false + }, + { + "name": "settlePrice", + "type": "i64", + "index": false + }, + { + "name": "explanation", + "type": { + "defined": "SettlePnlExplanation" + }, + "index": false + } + ] + }, + { + "name": "InsuranceFundRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "spotMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "perpMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "userIfFactor", + "type": "u32", + "index": false + }, + { + "name": "totalIfFactor", + "type": "u32", + "index": false + }, + { + "name": "vaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "insuranceVaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "totalIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "amount", + "type": "i64", + "index": false + } + ] + }, + { + "name": "InsuranceFundStakeRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "userAuthority", + "type": "publicKey", + "index": false + }, + { + "name": "action", + "type": { + "defined": "StakeAction" + }, + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "insuranceVaultAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "ifSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "userIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesBefore", + "type": "u128", + "index": false + }, + { + "name": "ifSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "userIfSharesAfter", + "type": "u128", + "index": false + }, + { + "name": "totalIfSharesAfter", + "type": "u128", + "index": false + } + ] + }, + { + "name": "SwapRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "user", + "type": "publicKey", + "index": false + }, + { + "name": "amountOut", + "type": "u64", + "index": false + }, + { + "name": "amountIn", + "type": "u64", + "index": false + }, + { + "name": "outMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "inMarketIndex", + "type": "u16", + "index": false + }, + { + "name": "outOraclePrice", + "type": "i64", + "index": false + }, + { + "name": "inOraclePrice", + "type": "i64", + "index": false + }, + { + "name": "fee", + "type": "u64", + "index": false + } + ] + }, + { + "name": "SpotMarketVaultDepositRecord", + "fields": [ + { + "name": "ts", + "type": "i64", + "index": false + }, + { + "name": "marketIndex", + "type": "u16", + "index": false + }, + { + "name": "depositBalance", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterestBefore", + "type": "u128", + "index": false + }, + { + "name": "cumulativeDepositInterestAfter", + "type": "u128", + "index": false + }, + { + "name": "depositTokenAmountBefore", + "type": "u64", + "index": false + }, + { + "name": "amount", + "type": "u64", + "index": false + } + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "InvalidSpotMarketAuthority", + "msg": "Invalid Spot Market Authority" + }, + { + "code": 6001, + "name": "InvalidInsuranceFundAuthority", + "msg": "Clearing house not insurance fund authority" + }, + { + "code": 6002, + "name": "InsufficientDeposit", + "msg": "Insufficient deposit" + }, + { + "code": 6003, + "name": "InsufficientCollateral", + "msg": "Insufficient collateral" + }, + { + "code": 6004, + "name": "SufficientCollateral", + "msg": "Sufficient collateral" + }, + { + "code": 6005, + "name": "MaxNumberOfPositions", + "msg": "Max number of positions taken" + }, + { + "code": 6006, + "name": "AdminControlsPricesDisabled", + "msg": "Admin Controls Prices Disabled" + }, + { + "code": 6007, + "name": "MarketDelisted", + "msg": "Market Delisted" + }, + { + "code": 6008, + "name": "MarketIndexAlreadyInitialized", + "msg": "Market Index Already Initialized" + }, + { + "code": 6009, + "name": "UserAccountAndUserPositionsAccountMismatch", + "msg": "User Account And User Positions Account Mismatch" + }, + { + "code": 6010, + "name": "UserHasNoPositionInMarket", + "msg": "User Has No Position In Market" + }, + { + "code": 6011, + "name": "InvalidInitialPeg", + "msg": "Invalid Initial Peg" + }, + { + "code": 6012, + "name": "InvalidRepegRedundant", + "msg": "AMM repeg already configured with amt given" + }, + { + "code": 6013, + "name": "InvalidRepegDirection", + "msg": "AMM repeg incorrect repeg direction" + }, + { + "code": 6014, + "name": "InvalidRepegProfitability", + "msg": "AMM repeg out of bounds pnl" + }, + { + "code": 6015, + "name": "SlippageOutsideLimit", + "msg": "Slippage Outside Limit Price" + }, + { + "code": 6016, + "name": "OrderSizeTooSmall", + "msg": "Order Size Too Small" + }, + { + "code": 6017, + "name": "InvalidUpdateK", + "msg": "Price change too large when updating K" + }, + { + "code": 6018, + "name": "AdminWithdrawTooLarge", + "msg": "Admin tried to withdraw amount larger than fees collected" + }, + { + "code": 6019, + "name": "MathError", + "msg": "Math Error" + }, + { + "code": 6020, + "name": "BnConversionError", + "msg": "Conversion to u128/u64 failed with an overflow or underflow" + }, + { + "code": 6021, + "name": "ClockUnavailable", + "msg": "Clock unavailable" + }, + { + "code": 6022, + "name": "UnableToLoadOracle", + "msg": "Unable To Load Oracles" + }, + { + "code": 6023, + "name": "PriceBandsBreached", + "msg": "Price Bands Breached" + }, + { + "code": 6024, + "name": "ExchangePaused", + "msg": "Exchange is paused" + }, + { + "code": 6025, + "name": "InvalidWhitelistToken", + "msg": "Invalid whitelist token" + }, + { + "code": 6026, + "name": "WhitelistTokenNotFound", + "msg": "Whitelist token not found" + }, + { + "code": 6027, + "name": "InvalidDiscountToken", + "msg": "Invalid discount token" + }, + { + "code": 6028, + "name": "DiscountTokenNotFound", + "msg": "Discount token not found" + }, + { + "code": 6029, + "name": "ReferrerNotFound", + "msg": "Referrer not found" + }, + { + "code": 6030, + "name": "ReferrerStatsNotFound", + "msg": "ReferrerNotFound" + }, + { + "code": 6031, + "name": "ReferrerMustBeWritable", + "msg": "ReferrerMustBeWritable" + }, + { + "code": 6032, + "name": "ReferrerStatsMustBeWritable", + "msg": "ReferrerMustBeWritable" + }, + { + "code": 6033, + "name": "ReferrerAndReferrerStatsAuthorityUnequal", + "msg": "ReferrerAndReferrerStatsAuthorityUnequal" + }, + { + "code": 6034, + "name": "InvalidReferrer", + "msg": "InvalidReferrer" + }, + { + "code": 6035, + "name": "InvalidOracle", + "msg": "InvalidOracle" + }, + { + "code": 6036, + "name": "OracleNotFound", + "msg": "OracleNotFound" + }, + { + "code": 6037, + "name": "LiquidationsBlockedByOracle", + "msg": "Liquidations Blocked By Oracle" + }, + { + "code": 6038, + "name": "MaxDeposit", + "msg": "Can not deposit more than max deposit" + }, + { + "code": 6039, + "name": "CantDeleteUserWithCollateral", + "msg": "Can not delete user that still has collateral" + }, + { + "code": 6040, + "name": "InvalidFundingProfitability", + "msg": "AMM funding out of bounds pnl" + }, + { + "code": 6041, + "name": "CastingFailure", + "msg": "Casting Failure" + }, + { + "code": 6042, + "name": "InvalidOrder", + "msg": "InvalidOrder" + }, + { + "code": 6043, + "name": "InvalidOrderMaxTs", + "msg": "InvalidOrderMaxTs" + }, + { + "code": 6044, + "name": "InvalidOrderMarketType", + "msg": "InvalidOrderMarketType" + }, + { + "code": 6045, + "name": "InvalidOrderForInitialMarginReq", + "msg": "InvalidOrderForInitialMarginReq" + }, + { + "code": 6046, + "name": "InvalidOrderNotRiskReducing", + "msg": "InvalidOrderNotRiskReducing" + }, + { + "code": 6047, + "name": "InvalidOrderSizeTooSmall", + "msg": "InvalidOrderSizeTooSmall" + }, + { + "code": 6048, + "name": "InvalidOrderNotStepSizeMultiple", + "msg": "InvalidOrderNotStepSizeMultiple" + }, + { + "code": 6049, + "name": "InvalidOrderBaseQuoteAsset", + "msg": "InvalidOrderBaseQuoteAsset" + }, + { + "code": 6050, + "name": "InvalidOrderIOC", + "msg": "InvalidOrderIOC" + }, + { + "code": 6051, + "name": "InvalidOrderPostOnly", + "msg": "InvalidOrderPostOnly" + }, + { + "code": 6052, + "name": "InvalidOrderIOCPostOnly", + "msg": "InvalidOrderIOCPostOnly" + }, + { + "code": 6053, + "name": "InvalidOrderTrigger", + "msg": "InvalidOrderTrigger" + }, + { + "code": 6054, + "name": "InvalidOrderAuction", + "msg": "InvalidOrderAuction" + }, + { + "code": 6055, + "name": "InvalidOrderOracleOffset", + "msg": "InvalidOrderOracleOffset" + }, + { + "code": 6056, + "name": "InvalidOrderMinOrderSize", + "msg": "InvalidOrderMinOrderSize" + }, + { + "code": 6057, + "name": "PlacePostOnlyLimitFailure", + "msg": "Failed to Place Post-Only Limit Order" + }, + { + "code": 6058, + "name": "UserHasNoOrder", + "msg": "User has no order" + }, + { + "code": 6059, + "name": "OrderAmountTooSmall", + "msg": "Order Amount Too Small" + }, + { + "code": 6060, + "name": "MaxNumberOfOrders", + "msg": "Max number of orders taken" + }, + { + "code": 6061, + "name": "OrderDoesNotExist", + "msg": "Order does not exist" + }, + { + "code": 6062, + "name": "OrderNotOpen", + "msg": "Order not open" + }, + { + "code": 6063, + "name": "FillOrderDidNotUpdateState", + "msg": "FillOrderDidNotUpdateState" + }, + { + "code": 6064, + "name": "ReduceOnlyOrderIncreasedRisk", + "msg": "Reduce only order increased risk" + }, + { + "code": 6065, + "name": "UnableToLoadAccountLoader", + "msg": "Unable to load AccountLoader" + }, + { + "code": 6066, + "name": "TradeSizeTooLarge", + "msg": "Trade Size Too Large" + }, + { + "code": 6067, + "name": "UserCantReferThemselves", + "msg": "User cant refer themselves" + }, + { + "code": 6068, + "name": "DidNotReceiveExpectedReferrer", + "msg": "Did not receive expected referrer" + }, + { + "code": 6069, + "name": "CouldNotDeserializeReferrer", + "msg": "Could not deserialize referrer" + }, + { + "code": 6070, + "name": "CouldNotDeserializeReferrerStats", + "msg": "Could not deserialize referrer stats" + }, + { + "code": 6071, + "name": "UserOrderIdAlreadyInUse", + "msg": "User Order Id Already In Use" + }, + { + "code": 6072, + "name": "NoPositionsLiquidatable", + "msg": "No positions liquidatable" + }, + { + "code": 6073, + "name": "InvalidMarginRatio", + "msg": "Invalid Margin Ratio" + }, + { + "code": 6074, + "name": "CantCancelPostOnlyOrder", + "msg": "Cant Cancel Post Only Order" + }, + { + "code": 6075, + "name": "InvalidOracleOffset", + "msg": "InvalidOracleOffset" + }, + { + "code": 6076, + "name": "CantExpireOrders", + "msg": "CantExpireOrders" + }, + { + "code": 6077, + "name": "CouldNotLoadMarketData", + "msg": "CouldNotLoadMarketData" + }, + { + "code": 6078, + "name": "PerpMarketNotFound", + "msg": "PerpMarketNotFound" + }, + { + "code": 6079, + "name": "InvalidMarketAccount", + "msg": "InvalidMarketAccount" + }, + { + "code": 6080, + "name": "UnableToLoadPerpMarketAccount", + "msg": "UnableToLoadMarketAccount" + }, + { + "code": 6081, + "name": "MarketWrongMutability", + "msg": "MarketWrongMutability" + }, + { + "code": 6082, + "name": "UnableToCastUnixTime", + "msg": "UnableToCastUnixTime" + }, + { + "code": 6083, + "name": "CouldNotFindSpotPosition", + "msg": "CouldNotFindSpotPosition" + }, + { + "code": 6084, + "name": "NoSpotPositionAvailable", + "msg": "NoSpotPositionAvailable" + }, + { + "code": 6085, + "name": "InvalidSpotMarketInitialization", + "msg": "InvalidSpotMarketInitialization" + }, + { + "code": 6086, + "name": "CouldNotLoadSpotMarketData", + "msg": "CouldNotLoadSpotMarketData" + }, + { + "code": 6087, + "name": "SpotMarketNotFound", + "msg": "SpotMarketNotFound" + }, + { + "code": 6088, + "name": "InvalidSpotMarketAccount", + "msg": "InvalidSpotMarketAccount" + }, + { + "code": 6089, + "name": "UnableToLoadSpotMarketAccount", + "msg": "UnableToLoadSpotMarketAccount" + }, + { + "code": 6090, + "name": "SpotMarketWrongMutability", + "msg": "SpotMarketWrongMutability" + }, + { + "code": 6091, + "name": "SpotMarketInterestNotUpToDate", + "msg": "SpotInterestNotUpToDate" + }, + { + "code": 6092, + "name": "SpotMarketInsufficientDeposits", + "msg": "SpotMarketInsufficientDeposits" + }, + { + "code": 6093, + "name": "UserMustSettleTheirOwnPositiveUnsettledPNL", + "msg": "UserMustSettleTheirOwnPositiveUnsettledPNL" + }, + { + "code": 6094, + "name": "CantUpdatePoolBalanceType", + "msg": "CantUpdatePoolBalanceType" + }, + { + "code": 6095, + "name": "InsufficientCollateralForSettlingPNL", + "msg": "InsufficientCollateralForSettlingPNL" + }, + { + "code": 6096, + "name": "AMMNotUpdatedInSameSlot", + "msg": "AMMNotUpdatedInSameSlot" + }, + { + "code": 6097, + "name": "AuctionNotComplete", + "msg": "AuctionNotComplete" + }, + { + "code": 6098, + "name": "MakerNotFound", + "msg": "MakerNotFound" + }, + { + "code": 6099, + "name": "MakerStatsNotFound", + "msg": "MakerNotFound" + }, + { + "code": 6100, + "name": "MakerMustBeWritable", + "msg": "MakerMustBeWritable" + }, + { + "code": 6101, + "name": "MakerStatsMustBeWritable", + "msg": "MakerMustBeWritable" + }, + { + "code": 6102, + "name": "MakerOrderNotFound", + "msg": "MakerOrderNotFound" + }, + { + "code": 6103, + "name": "CouldNotDeserializeMaker", + "msg": "CouldNotDeserializeMaker" + }, + { + "code": 6104, + "name": "CouldNotDeserializeMakerStats", + "msg": "CouldNotDeserializeMaker" + }, + { + "code": 6105, + "name": "AuctionPriceDoesNotSatisfyMaker", + "msg": "AuctionPriceDoesNotSatisfyMaker" + }, + { + "code": 6106, + "name": "MakerCantFulfillOwnOrder", + "msg": "MakerCantFulfillOwnOrder" + }, + { + "code": 6107, + "name": "MakerOrderMustBePostOnly", + "msg": "MakerOrderMustBePostOnly" + }, + { + "code": 6108, + "name": "CantMatchTwoPostOnlys", + "msg": "CantMatchTwoPostOnlys" + }, + { + "code": 6109, + "name": "OrderBreachesOraclePriceLimits", + "msg": "OrderBreachesOraclePriceLimits" + }, + { + "code": 6110, + "name": "OrderMustBeTriggeredFirst", + "msg": "OrderMustBeTriggeredFirst" + }, + { + "code": 6111, + "name": "OrderNotTriggerable", + "msg": "OrderNotTriggerable" + }, + { + "code": 6112, + "name": "OrderDidNotSatisfyTriggerCondition", + "msg": "OrderDidNotSatisfyTriggerCondition" + }, + { + "code": 6113, + "name": "PositionAlreadyBeingLiquidated", + "msg": "PositionAlreadyBeingLiquidated" + }, + { + "code": 6114, + "name": "PositionDoesntHaveOpenPositionOrOrders", + "msg": "PositionDoesntHaveOpenPositionOrOrders" + }, + { + "code": 6115, + "name": "AllOrdersAreAlreadyLiquidations", + "msg": "AllOrdersAreAlreadyLiquidations" + }, + { + "code": 6116, + "name": "CantCancelLiquidationOrder", + "msg": "CantCancelLiquidationOrder" + }, + { + "code": 6117, + "name": "UserIsBeingLiquidated", + "msg": "UserIsBeingLiquidated" + }, + { + "code": 6118, + "name": "LiquidationsOngoing", + "msg": "LiquidationsOngoing" + }, + { + "code": 6119, + "name": "WrongSpotBalanceType", + "msg": "WrongSpotBalanceType" + }, + { + "code": 6120, + "name": "UserCantLiquidateThemself", + "msg": "UserCantLiquidateThemself" + }, + { + "code": 6121, + "name": "InvalidPerpPositionToLiquidate", + "msg": "InvalidPerpPositionToLiquidate" + }, + { + "code": 6122, + "name": "InvalidBaseAssetAmountForLiquidatePerp", + "msg": "InvalidBaseAssetAmountForLiquidatePerp" + }, + { + "code": 6123, + "name": "InvalidPositionLastFundingRate", + "msg": "InvalidPositionLastFundingRate" + }, + { + "code": 6124, + "name": "InvalidPositionDelta", + "msg": "InvalidPositionDelta" + }, + { + "code": 6125, + "name": "UserBankrupt", + "msg": "UserBankrupt" + }, + { + "code": 6126, + "name": "UserNotBankrupt", + "msg": "UserNotBankrupt" + }, + { + "code": 6127, + "name": "UserHasInvalidBorrow", + "msg": "UserHasInvalidBorrow" + }, + { + "code": 6128, + "name": "DailyWithdrawLimit", + "msg": "DailyWithdrawLimit" + }, + { + "code": 6129, + "name": "DefaultError", + "msg": "DefaultError" + }, + { + "code": 6130, + "name": "InsufficientLPTokens", + "msg": "Insufficient LP tokens" + }, + { + "code": 6131, + "name": "CantLPWithPerpPosition", + "msg": "Cant LP with a market position" + }, + { + "code": 6132, + "name": "UnableToBurnLPTokens", + "msg": "Unable to burn LP tokens" + }, + { + "code": 6133, + "name": "TryingToRemoveLiquidityTooFast", + "msg": "Trying to remove liqudity too fast after adding it" + }, + { + "code": 6134, + "name": "InvalidSpotMarketVault", + "msg": "Invalid Spot Market Vault" + }, + { + "code": 6135, + "name": "InvalidSpotMarketState", + "msg": "Invalid Spot Market State" + }, + { + "code": 6136, + "name": "InvalidSerumProgram", + "msg": "InvalidSerumProgram" + }, + { + "code": 6137, + "name": "InvalidSerumMarket", + "msg": "InvalidSerumMarket" + }, + { + "code": 6138, + "name": "InvalidSerumBids", + "msg": "InvalidSerumBids" + }, + { + "code": 6139, + "name": "InvalidSerumAsks", + "msg": "InvalidSerumAsks" + }, + { + "code": 6140, + "name": "InvalidSerumOpenOrders", + "msg": "InvalidSerumOpenOrders" + }, + { + "code": 6141, + "name": "FailedSerumCPI", + "msg": "FailedSerumCPI" + }, + { + "code": 6142, + "name": "FailedToFillOnExternalMarket", + "msg": "FailedToFillOnExternalMarket" + }, + { + "code": 6143, + "name": "InvalidFulfillmentConfig", + "msg": "InvalidFulfillmentConfig" + }, + { + "code": 6144, + "name": "InvalidFeeStructure", + "msg": "InvalidFeeStructure" + }, + { + "code": 6145, + "name": "InsufficientIFShares", + "msg": "Insufficient IF shares" + }, + { + "code": 6146, + "name": "MarketActionPaused", + "msg": "the Market has paused this action" + }, + { + "code": 6147, + "name": "MarketPlaceOrderPaused", + "msg": "the Market status doesnt allow placing orders" + }, + { + "code": 6148, + "name": "MarketFillOrderPaused", + "msg": "the Market status doesnt allow filling orders" + }, + { + "code": 6149, + "name": "MarketWithdrawPaused", + "msg": "the Market status doesnt allow withdraws" + }, + { + "code": 6150, + "name": "ProtectedAssetTierViolation", + "msg": "Action violates the Protected Asset Tier rules" + }, + { + "code": 6151, + "name": "IsolatedAssetTierViolation", + "msg": "Action violates the Isolated Asset Tier rules" + }, + { + "code": 6152, + "name": "UserCantBeDeleted", + "msg": "User Cant Be Deleted" + }, + { + "code": 6153, + "name": "ReduceOnlyWithdrawIncreasedRisk", + "msg": "Reduce Only Withdraw Increased Risk" + }, + { + "code": 6154, + "name": "MaxOpenInterest", + "msg": "Max Open Interest" + }, + { + "code": 6155, + "name": "CantResolvePerpBankruptcy", + "msg": "Cant Resolve Perp Bankruptcy" + }, + { + "code": 6156, + "name": "LiquidationDoesntSatisfyLimitPrice", + "msg": "Liquidation Doesnt Satisfy Limit Price" + }, + { + "code": 6157, + "name": "MarginTradingDisabled", + "msg": "Margin Trading Disabled" + }, + { + "code": 6158, + "name": "InvalidMarketStatusToSettlePnl", + "msg": "Invalid Market Status to Settle Perp Pnl" + }, + { + "code": 6159, + "name": "PerpMarketNotInSettlement", + "msg": "PerpMarketNotInSettlement" + }, + { + "code": 6160, + "name": "PerpMarketNotInReduceOnly", + "msg": "PerpMarketNotInReduceOnly" + }, + { + "code": 6161, + "name": "PerpMarketSettlementBufferNotReached", + "msg": "PerpMarketSettlementBufferNotReached" + }, + { + "code": 6162, + "name": "PerpMarketSettlementUserHasOpenOrders", + "msg": "PerpMarketSettlementUserHasOpenOrders" + }, + { + "code": 6163, + "name": "PerpMarketSettlementUserHasActiveLP", + "msg": "PerpMarketSettlementUserHasActiveLP" + }, + { + "code": 6164, + "name": "UnableToSettleExpiredUserPosition", + "msg": "UnableToSettleExpiredUserPosition" + }, + { + "code": 6165, + "name": "UnequalMarketIndexForSpotTransfer", + "msg": "UnequalMarketIndexForSpotTransfer" + }, + { + "code": 6166, + "name": "InvalidPerpPositionDetected", + "msg": "InvalidPerpPositionDetected" + }, + { + "code": 6167, + "name": "InvalidSpotPositionDetected", + "msg": "InvalidSpotPositionDetected" + }, + { + "code": 6168, + "name": "InvalidAmmDetected", + "msg": "InvalidAmmDetected" + }, + { + "code": 6169, + "name": "InvalidAmmForFillDetected", + "msg": "InvalidAmmForFillDetected" + }, + { + "code": 6170, + "name": "InvalidAmmLimitPriceOverride", + "msg": "InvalidAmmLimitPriceOverride" + }, + { + "code": 6171, + "name": "InvalidOrderFillPrice", + "msg": "InvalidOrderFillPrice" + }, + { + "code": 6172, + "name": "SpotMarketBalanceInvariantViolated", + "msg": "SpotMarketBalanceInvariantViolated" + }, + { + "code": 6173, + "name": "SpotMarketVaultInvariantViolated", + "msg": "SpotMarketVaultInvariantViolated" + }, + { + "code": 6174, + "name": "InvalidPDA", + "msg": "InvalidPDA" + }, + { + "code": 6175, + "name": "InvalidPDASigner", + "msg": "InvalidPDASigner" + }, + { + "code": 6176, + "name": "RevenueSettingsCannotSettleToIF", + "msg": "RevenueSettingsCannotSettleToIF" + }, + { + "code": 6177, + "name": "NoRevenueToSettleToIF", + "msg": "NoRevenueToSettleToIF" + }, + { + "code": 6178, + "name": "NoAmmPerpPnlDeficit", + "msg": "NoAmmPerpPnlDeficit" + }, + { + "code": 6179, + "name": "SufficientPerpPnlPool", + "msg": "SufficientPerpPnlPool" + }, + { + "code": 6180, + "name": "InsufficientPerpPnlPool", + "msg": "InsufficientPerpPnlPool" + }, + { + "code": 6181, + "name": "PerpPnlDeficitBelowThreshold", + "msg": "PerpPnlDeficitBelowThreshold" + }, + { + "code": 6182, + "name": "MaxRevenueWithdrawPerPeriodReached", + "msg": "MaxRevenueWithdrawPerPeriodReached" + }, + { + "code": 6183, + "name": "MaxIFWithdrawReached", + "msg": "InvalidSpotPositionDetected" + }, + { + "code": 6184, + "name": "NoIFWithdrawAvailable", + "msg": "NoIFWithdrawAvailable" + }, + { + "code": 6185, + "name": "InvalidIFUnstake", + "msg": "InvalidIFUnstake" + }, + { + "code": 6186, + "name": "InvalidIFUnstakeSize", + "msg": "InvalidIFUnstakeSize" + }, + { + "code": 6187, + "name": "InvalidIFUnstakeCancel", + "msg": "InvalidIFUnstakeCancel" + }, + { + "code": 6188, + "name": "InvalidIFForNewStakes", + "msg": "InvalidIFForNewStakes" + }, + { + "code": 6189, + "name": "InvalidIFRebase", + "msg": "InvalidIFRebase" + }, + { + "code": 6190, + "name": "InvalidInsuranceUnstakeSize", + "msg": "InvalidInsuranceUnstakeSize" + }, + { + "code": 6191, + "name": "InvalidOrderLimitPrice", + "msg": "InvalidOrderLimitPrice" + }, + { + "code": 6192, + "name": "InvalidIFDetected", + "msg": "InvalidIFDetected" + }, + { + "code": 6193, + "name": "InvalidAmmMaxSpreadDetected", + "msg": "InvalidAmmMaxSpreadDetected" + }, + { + "code": 6194, + "name": "InvalidConcentrationCoef", + "msg": "InvalidConcentrationCoef" + }, + { + "code": 6195, + "name": "InvalidSrmVault", + "msg": "InvalidSrmVault" + }, + { + "code": 6196, + "name": "InvalidVaultOwner", + "msg": "InvalidVaultOwner" + }, + { + "code": 6197, + "name": "InvalidMarketStatusForFills", + "msg": "InvalidMarketStatusForFills" + }, + { + "code": 6198, + "name": "IFWithdrawRequestInProgress", + "msg": "IFWithdrawRequestInProgress" + }, + { + "code": 6199, + "name": "NoIFWithdrawRequestInProgress", + "msg": "NoIFWithdrawRequestInProgress" + }, + { + "code": 6200, + "name": "IFWithdrawRequestTooSmall", + "msg": "IFWithdrawRequestTooSmall" + }, + { + "code": 6201, + "name": "IncorrectSpotMarketAccountPassed", + "msg": "IncorrectSpotMarketAccountPassed" + }, + { + "code": 6202, + "name": "BlockchainClockInconsistency", + "msg": "BlockchainClockInconsistency" + }, + { + "code": 6203, + "name": "InvalidIFSharesDetected", + "msg": "InvalidIFSharesDetected" + }, + { + "code": 6204, + "name": "NewLPSizeTooSmall", + "msg": "NewLPSizeTooSmall" + }, + { + "code": 6205, + "name": "MarketStatusInvalidForNewLP", + "msg": "MarketStatusInvalidForNewLP" + }, + { + "code": 6206, + "name": "InvalidMarkTwapUpdateDetected", + "msg": "InvalidMarkTwapUpdateDetected" + }, + { + "code": 6207, + "name": "MarketSettlementAttemptOnActiveMarket", + "msg": "MarketSettlementAttemptOnActiveMarket" + }, + { + "code": 6208, + "name": "MarketSettlementRequiresSettledLP", + "msg": "MarketSettlementRequiresSettledLP" + }, + { + "code": 6209, + "name": "MarketSettlementAttemptTooEarly", + "msg": "MarketSettlementAttemptTooEarly" + }, + { + "code": 6210, + "name": "MarketSettlementTargetPriceInvalid", + "msg": "MarketSettlementTargetPriceInvalid" + }, + { + "code": 6211, + "name": "UnsupportedSpotMarket", + "msg": "UnsupportedSpotMarket" + }, + { + "code": 6212, + "name": "SpotOrdersDisabled", + "msg": "SpotOrdersDisabled" + }, + { + "code": 6213, + "name": "MarketBeingInitialized", + "msg": "Market Being Initialized" + }, + { + "code": 6214, + "name": "InvalidUserSubAccountId", + "msg": "Invalid Sub Account Id" + }, + { + "code": 6215, + "name": "InvalidTriggerOrderCondition", + "msg": "Invalid Trigger Order Condition" + }, + { + "code": 6216, + "name": "InvalidSpotPosition", + "msg": "Invalid Spot Position" + }, + { + "code": 6217, + "name": "CantTransferBetweenSameUserAccount", + "msg": "Cant transfer between same user account" + }, + { + "code": 6218, + "name": "InvalidPerpPosition", + "msg": "Invalid Perp Position" + }, + { + "code": 6219, + "name": "UnableToGetLimitPrice", + "msg": "Unable To Get Limit Price" + }, + { + "code": 6220, + "name": "InvalidLiquidation", + "msg": "Invalid Liquidation" + }, + { + "code": 6221, + "name": "SpotFulfillmentConfigDisabled", + "msg": "Spot Fulfillment Config Disabled" + }, + { + "code": 6222, + "name": "InvalidMaker", + "msg": "Invalid Maker" + }, + { + "code": 6223, + "name": "FailedUnwrap", + "msg": "Failed Unwrap" + }, + { + "code": 6224, + "name": "MaxNumberOfUsers", + "msg": "Max Number Of Users" + }, + { + "code": 6225, + "name": "InvalidOracleForSettlePnl", + "msg": "InvalidOracleForSettlePnl" + }, + { + "code": 6226, + "name": "MarginOrdersOpen", + "msg": "MarginOrdersOpen" + }, + { + "code": 6227, + "name": "TierViolationLiquidatingPerpPnl", + "msg": "TierViolationLiquidatingPerpPnl" + }, + { + "code": 6228, + "name": "CouldNotLoadUserData", + "msg": "CouldNotLoadUserData" + }, + { + "code": 6229, + "name": "UserWrongMutability", + "msg": "UserWrongMutability" + }, + { + "code": 6230, + "name": "InvalidUserAccount", + "msg": "InvalidUserAccount" + }, + { + "code": 6231, + "name": "CouldNotLoadUserStatsData", + "msg": "CouldNotLoadUserData" + }, + { + "code": 6232, + "name": "UserStatsWrongMutability", + "msg": "UserWrongMutability" + }, + { + "code": 6233, + "name": "InvalidUserStatsAccount", + "msg": "InvalidUserAccount" + }, + { + "code": 6234, + "name": "UserNotFound", + "msg": "UserNotFound" + }, + { + "code": 6235, + "name": "UnableToLoadUserAccount", + "msg": "UnableToLoadUserAccount" + }, + { + "code": 6236, + "name": "UserStatsNotFound", + "msg": "UserStatsNotFound" + }, + { + "code": 6237, + "name": "UnableToLoadUserStatsAccount", + "msg": "UnableToLoadUserStatsAccount" + }, + { + "code": 6238, + "name": "UserNotInactive", + "msg": "User Not Inactive" + }, + { + "code": 6239, + "name": "RevertFill", + "msg": "RevertFill" + }, + { + "code": 6240, + "name": "InvalidMarketAccountforDeletion", + "msg": "Invalid MarketAccount for Deletion" + }, + { + "code": 6241, + "name": "InvalidSpotFulfillmentParams", + "msg": "Invalid Spot Fulfillment Params" + }, + { + "code": 6242, + "name": "FailedToGetMint", + "msg": "Failed to Get Mint" + }, + { + "code": 6243, + "name": "FailedPhoenixCPI", + "msg": "FailedPhoenixCPI" + }, + { + "code": 6244, + "name": "FailedToDeserializePhoenixMarket", + "msg": "FailedToDeserializePhoenixMarket" + }, + { + "code": 6245, + "name": "InvalidPricePrecision", + "msg": "InvalidPricePrecision" + }, + { + "code": 6246, + "name": "InvalidPhoenixProgram", + "msg": "InvalidPhoenixProgram" + }, + { + "code": 6247, + "name": "InvalidPhoenixMarket", + "msg": "InvalidPhoenixMarket" + }, + { + "code": 6248, + "name": "InvalidSwap", + "msg": "InvalidSwap" + }, + { + "code": 6249, + "name": "SwapLimitPriceBreached", + "msg": "SwapLimitPriceBreached" + }, + { + "code": 6250, + "name": "SpotMarketReduceOnly", + "msg": "SpotMarketReduceOnly" + }, + { + "code": 6251, + "name": "FundingWasNotUpdated", + "msg": "FundingWasNotUpdated" + }, + { + "code": 6252, + "name": "ImpossibleFill", + "msg": "ImpossibleFill" + }, + { + "code": 6253, + "name": "CantUpdatePerpBidAskTwap", + "msg": "CantUpdatePerpBidAskTwap" + }, + { + "code": 6254, + "name": "UserReduceOnly", + "msg": "UserReduceOnly" + }, + { + "code": 6255, + "name": "InvalidMarginCalculation", + "msg": "InvalidMarginCalculation" + }, + { + "code": 6256, + "name": "CantPayUserInitFee", + "msg": "CantPayUserInitFee" + }, + { + "code": 6257, + "name": "CantReclaimRent", + "msg": "CantReclaimRent" + }, + { + "code": 6258, + "name": "InsuranceFundOperationPaused", + "msg": "InsuranceFundOperationPaused" + }, + { + "code": 6259, + "name": "NoUnsettledPnl", + "msg": "NoUnsettledPnl" + }, + { + "code": 6260, + "name": "PnlPoolCantSettleUser", + "msg": "PnlPoolCantSettleUser" + }, + { + "code": 6261, + "name": "OracleNonPositive", + "msg": "OracleInvalid" + }, + { + "code": 6262, + "name": "OracleTooVolatile", + "msg": "OracleTooVolatile" + }, + { + "code": 6263, + "name": "OracleTooUncertain", + "msg": "OracleTooUncertain" + }, + { + "code": 6264, + "name": "OracleStaleForMargin", + "msg": "OracleStaleForMargin" + }, + { + "code": 6265, + "name": "OracleInsufficientDataPoints", + "msg": "OracleInsufficientDataPoints" + }, + { + "code": 6266, + "name": "OracleStaleForAMM", + "msg": "OracleStaleForAMM" + }, + { + "code": 6267, + "name": "UnableToParsePullOracleMessage", + "msg": "Unable to parse pull oracle message" + }, + { + "code": 6268, + "name": "MaxBorrows", + "msg": "Can not borow more than max borrows" + }, + { + "code": 6269, + "name": "OracleUpdatesNotMonotonic", + "msg": "Updates must be monotonically increasing" + }, + { + "code": 6270, + "name": "OraclePriceFeedMessageMismatch", + "msg": "Trying to update price feed with the wrong feed id" + }, + { + "code": 6271, + "name": "OracleUnsupportedMessageType", + "msg": "The message in the update must be a PriceFeedMessage" + }, + { + "code": 6272, + "name": "OracleDeserializeMessageFailed", + "msg": "Could not deserialize the message in the update" + }, + { + "code": 6273, + "name": "OracleWrongGuardianSetOwner", + "msg": "Wrong guardian set owner in update price atomic" + }, + { + "code": 6274, + "name": "OracleWrongWriteAuthority", + "msg": "Oracle post update atomic price feed account must be drift program" + }, + { + "code": 6275, + "name": "OracleWrongVaaOwner", + "msg": "Oracle vaa owner must be wormhole program" + }, + { + "code": 6276, + "name": "OracleTooManyPriceAccountUpdates", + "msg": "Multi updates must have 2 or fewer accounts passed in remaining accounts" + }, + { + "code": 6277, + "name": "OracleMismatchedVaaAndPriceUpdates", + "msg": "Don't have the same remaining accounts number and merkle price updates left" + }, + { + "code": 6278, + "name": "OracleBadRemainingAccountPublicKey", + "msg": "Remaining account passed is not a valid pda" + }, + { + "code": 6279, + "name": "FailedOpenbookV2CPI", + "msg": "FailedOpenbookV2CPI" + }, + { + "code": 6280, + "name": "InvalidOpenbookV2Program", + "msg": "InvalidOpenbookV2Program" + }, + { + "code": 6281, + "name": "InvalidOpenbookV2Market", + "msg": "InvalidOpenbookV2Market" + }, + { + "code": 6282, + "name": "NonZeroTransferFee", + "msg": "Non zero transfer fee" + }, + { + "code": 6283, + "name": "LiquidationOrderFailedToFill", + "msg": "Liquidation order failed to fill" + }, + { + "code": 6284, + "name": "InvalidPredictionMarketOrder", + "msg": "Invalid prediction market order" + } + ] +} \ No newline at end of file diff --git a/DriftStakeVoterPlugin/idl/driftStakeVoter.ts b/DriftStakeVoterPlugin/idl/driftStakeVoter.ts new file mode 100644 index 0000000000..61496132c7 --- /dev/null +++ b/DriftStakeVoterPlugin/idl/driftStakeVoter.ts @@ -0,0 +1,745 @@ +export type DriftStakeVoter = { + version: '0.0.1' + name: 'drift_stake_voter' + instructions: [ + { + name: 'createRegistrar' + accounts: [ + { + name: 'registrar' + isMut: true + isSigner: false + docs: [ + 'There can only be a single registrar per Realm and governing mint of the Realm' + ] + }, + { + name: 'governanceProgramId' + isMut: false + isSigner: false + docs: [ + 'The program id of the spl-governance program the realm belongs to' + ] + }, + { + name: 'driftProgramId' + isMut: false + isSigner: false + }, + { + name: 'realm' + isMut: false + isSigner: false + docs: [ + 'An spl-governance Realm', + '', + 'Realm is validated in the instruction:', + '- Realm is owned by the governance_program_id', + '- governing_token_mint must be the community or council mint', + '- realm_authority is realm.authority' + ] + }, + { + name: 'governingTokenMint' + isMut: false + isSigner: false + docs: [ + 'Either the realm community mint or the council mint.', + 'It must match Realm.community_mint or Realm.config.council_mint', + '', + 'Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity', + 'for the voting population and the tokens of that are no longer used' + ] + }, + { + name: 'realmAuthority' + isMut: false + isSigner: true + docs: ['realm_authority must sign and match Realm.authority'] + }, + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'spotMarketIndex' + type: 'u16' + } + ] + }, + { + name: 'createVoterWeightRecord' + accounts: [ + { + name: 'registrar' + isMut: false + isSigner: false + }, + { + name: 'voterWeightRecord' + isMut: true + isSigner: false + }, + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'governingTokenOwner' + type: 'publicKey' + } + ] + }, + { + name: 'updateVoterWeightRecord' + accounts: [ + { + name: 'registrar' + isMut: false + isSigner: false + }, + { + name: 'voterWeightRecord' + isMut: true + isSigner: false + }, + { + name: 'tokenOwnerRecord' + isMut: false + isSigner: false + docs: [ + 'TokenOwnerRecord for any of the configured spl-governance instances' + ] + }, + { + name: 'spotMarket' + isMut: false + isSigner: false + isOptional: true + }, + { + name: 'insuranceFundVault' + isMut: false + isSigner: false + isOptional: true + }, + { + name: 'insuranceFundStake' + isMut: false + isSigner: false + isOptional: true + }, + { + name: 'driftProgram' + isMut: false + isSigner: false + } + ] + args: [] + } + ] + accounts: [ + { + name: 'registrar' + docs: [ + 'Registrar which stores spl-governance configurations for the given Realm' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'governanceProgramId' + docs: ['spl-governance program the Realm belongs to'] + type: 'publicKey' + }, + { + name: 'realm' + docs: ['Realm of the Registrar'] + type: 'publicKey' + }, + { + name: 'governingTokenMint' + docs: [ + 'Governing token mint the Registrar is for', + 'It can either be the Community or the Council mint of the Realm', + 'When the plugin is enabled the mint is only used as the identity of the governing power (voting population)', + 'and the actual token of the mint is not used' + ] + type: 'publicKey' + }, + { + name: 'driftProgramId' + type: 'publicKey' + }, + { + name: 'spotMarketIndex' + type: 'u16' + } + ] + } + }, + { + name: 'voterWeightRecord' + docs: [ + 'VoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide voting power to the governance program from external addin contracts' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'realm' + docs: ['The Realm the VoterWeightRecord belongs to'] + type: 'publicKey' + }, + { + name: 'governingTokenMint' + docs: [ + 'Governing Token Mint the VoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only' + ] + type: 'publicKey' + }, + { + name: 'governingTokenOwner' + docs: [ + 'The owner of the governing token and voter', + 'This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner' + ] + type: 'publicKey' + }, + { + name: 'voterWeight' + docs: [ + "Voter's weight", + 'The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)' + ] + type: 'u64' + }, + { + name: 'voterWeightExpiry' + docs: [ + 'The slot when the voting weight expires', + 'It should be set to None if the weight never expires', + 'If the voter weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight' + ] + type: { + option: 'u64' + } + }, + { + name: 'weightAction' + docs: [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + 'When the action is provided then the governance program asserts the executing action is the same as specified by the addin' + ] + type: { + option: { + defined: 'VoterWeightAction' + } + } + }, + { + name: 'weightActionTarget' + docs: [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + 'For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target', + 'When the target is provided then the governance program asserts the target is the same as specified by the addin' + ] + type: { + option: 'publicKey' + } + }, + { + name: 'reserved' + docs: ['Reserved space for future versions'] + type: { + array: ['u8', 8] + } + } + ] + } + } + ] + types: [ + { + name: 'CollectionItemChangeType' + docs: ['Enum defining collection item change type'] + type: { + kind: 'enum' + variants: [ + { + name: 'Upsert' + }, + { + name: 'Remove' + } + ] + } + }, + { + name: 'VoterWeightAction' + docs: [ + 'VoterWeightAction enum as defined in spl-governance-addin-api', + "It's redefined here for Anchor to export it to IDL" + ] + type: { + kind: 'enum' + variants: [ + { + name: 'CastVote' + }, + { + name: 'CommentProposal' + }, + { + name: 'CreateGovernance' + }, + { + name: 'CreateProposal' + }, + { + name: 'SignOffProposal' + } + ] + } + } + ] + errors: [ + { + code: 6000 + name: 'InvalidRealmAuthority' + msg: 'Invalid Realm Authority' + }, + { + code: 6001 + name: 'InvalidRealmForRegistrar' + msg: 'Invalid Realm for Registrar' + }, + { + code: 6002 + name: 'InvalidVoterWeightRecordRealm' + msg: 'Invalid VoterWeightRecord Realm' + }, + { + code: 6003 + name: 'InvalidVoterWeightRecordMint' + msg: 'Invalid VoterWeightRecord Mint' + }, + { + code: 6004 + name: 'TokenOwnerRecordFromOwnRealmNotAllowed' + msg: 'TokenOwnerRecord from own realm is not allowed' + }, + { + code: 6005 + name: 'GovernanceProgramNotConfigured' + msg: 'Governance program not configured' + }, + { + code: 6006 + name: 'GoverningTokenOwnerMustMatch' + msg: 'Governing TokenOwner must match' + }, + { + code: 6007 + name: 'DriftError' + msg: 'DriftError' + } + ] +} + +export const IDL: DriftStakeVoter = { + version: '0.0.1', + name: 'drift_stake_voter', + instructions: [ + { + name: 'createRegistrar', + accounts: [ + { + name: 'registrar', + isMut: true, + isSigner: false, + docs: [ + 'There can only be a single registrar per Realm and governing mint of the Realm', + ], + }, + { + name: 'governanceProgramId', + isMut: false, + isSigner: false, + docs: [ + 'The program id of the spl-governance program the realm belongs to', + ], + }, + { + name: 'driftProgramId', + isMut: false, + isSigner: false, + }, + { + name: 'realm', + isMut: false, + isSigner: false, + docs: [ + 'An spl-governance Realm', + '', + 'Realm is validated in the instruction:', + '- Realm is owned by the governance_program_id', + '- governing_token_mint must be the community or council mint', + '- realm_authority is realm.authority', + ], + }, + { + name: 'governingTokenMint', + isMut: false, + isSigner: false, + docs: [ + 'Either the realm community mint or the council mint.', + 'It must match Realm.community_mint or Realm.config.council_mint', + '', + 'Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity', + 'for the voting population and the tokens of that are no longer used', + ], + }, + { + name: 'realmAuthority', + isMut: false, + isSigner: true, + docs: ['realm_authority must sign and match Realm.authority'], + }, + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'spotMarketIndex', + type: 'u16', + }, + ], + }, + { + name: 'createVoterWeightRecord', + accounts: [ + { + name: 'registrar', + isMut: false, + isSigner: false, + }, + { + name: 'voterWeightRecord', + isMut: true, + isSigner: false, + }, + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'governingTokenOwner', + type: 'publicKey', + }, + ], + }, + { + name: 'updateVoterWeightRecord', + accounts: [ + { + name: 'registrar', + isMut: false, + isSigner: false, + }, + { + name: 'voterWeightRecord', + isMut: true, + isSigner: false, + }, + { + name: 'tokenOwnerRecord', + isMut: false, + isSigner: false, + docs: [ + 'TokenOwnerRecord for any of the configured spl-governance instances', + ], + }, + { + name: 'spotMarket', + isMut: false, + isSigner: false, + isOptional: true, + }, + { + name: 'insuranceFundVault', + isMut: false, + isSigner: false, + isOptional: true, + }, + { + name: 'insuranceFundStake', + isMut: false, + isSigner: false, + isOptional: true, + }, + { + name: 'driftProgram', + isMut: false, + isSigner: false, + }, + ], + args: [], + }, + ], + accounts: [ + { + name: 'registrar', + docs: [ + 'Registrar which stores spl-governance configurations for the given Realm', + ], + type: { + kind: 'struct', + fields: [ + { + name: 'governanceProgramId', + docs: ['spl-governance program the Realm belongs to'], + type: 'publicKey', + }, + { + name: 'realm', + docs: ['Realm of the Registrar'], + type: 'publicKey', + }, + { + name: 'governingTokenMint', + docs: [ + 'Governing token mint the Registrar is for', + 'It can either be the Community or the Council mint of the Realm', + 'When the plugin is enabled the mint is only used as the identity of the governing power (voting population)', + 'and the actual token of the mint is not used', + ], + type: 'publicKey', + }, + { + name: 'driftProgramId', + type: 'publicKey', + }, + { + name: 'spotMarketIndex', + type: 'u16', + }, + ], + }, + }, + { + name: 'voterWeightRecord', + docs: [ + 'VoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide voting power to the governance program from external addin contracts', + ], + type: { + kind: 'struct', + fields: [ + { + name: 'realm', + docs: ['The Realm the VoterWeightRecord belongs to'], + type: 'publicKey', + }, + { + name: 'governingTokenMint', + docs: [ + 'Governing Token Mint the VoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only', + ], + type: 'publicKey', + }, + { + name: 'governingTokenOwner', + docs: [ + 'The owner of the governing token and voter', + 'This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner', + ], + type: 'publicKey', + }, + { + name: 'voterWeight', + docs: [ + "Voter's weight", + 'The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)', + ], + type: 'u64', + }, + { + name: 'voterWeightExpiry', + docs: [ + 'The slot when the voting weight expires', + 'It should be set to None if the weight never expires', + 'If the voter weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight', + ], + type: { + option: 'u64', + }, + }, + { + name: 'weightAction', + docs: [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + 'When the action is provided then the governance program asserts the executing action is the same as specified by the addin', + ], + type: { + option: { + defined: 'VoterWeightAction', + }, + }, + }, + { + name: 'weightActionTarget', + docs: [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + 'For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target', + 'When the target is provided then the governance program asserts the target is the same as specified by the addin', + ], + type: { + option: 'publicKey', + }, + }, + { + name: 'reserved', + docs: ['Reserved space for future versions'], + type: { + array: ['u8', 8], + }, + }, + ], + }, + }, + ], + types: [ + { + name: 'CollectionItemChangeType', + docs: ['Enum defining collection item change type'], + type: { + kind: 'enum', + variants: [ + { + name: 'Upsert', + }, + { + name: 'Remove', + }, + ], + }, + }, + { + name: 'VoterWeightAction', + docs: [ + 'VoterWeightAction enum as defined in spl-governance-addin-api', + "It's redefined here for Anchor to export it to IDL", + ], + type: { + kind: 'enum', + variants: [ + { + name: 'CastVote', + }, + { + name: 'CommentProposal', + }, + { + name: 'CreateGovernance', + }, + { + name: 'CreateProposal', + }, + { + name: 'SignOffProposal', + }, + ], + }, + }, + ], + errors: [ + { + code: 6000, + name: 'InvalidRealmAuthority', + msg: 'Invalid Realm Authority', + }, + { + code: 6001, + name: 'InvalidRealmForRegistrar', + msg: 'Invalid Realm for Registrar', + }, + { + code: 6002, + name: 'InvalidVoterWeightRecordRealm', + msg: 'Invalid VoterWeightRecord Realm', + }, + { + code: 6003, + name: 'InvalidVoterWeightRecordMint', + msg: 'Invalid VoterWeightRecord Mint', + }, + { + code: 6004, + name: 'TokenOwnerRecordFromOwnRealmNotAllowed', + msg: 'TokenOwnerRecord from own realm is not allowed', + }, + { + code: 6005, + name: 'GovernanceProgramNotConfigured', + msg: 'Governance program not configured', + }, + { + code: 6006, + name: 'GoverningTokenOwnerMustMatch', + msg: 'Governing TokenOwner must match', + }, + { + code: 6007, + name: 'DriftError', + msg: 'DriftError', + }, + ], +} diff --git a/GatewayPlugin/config.ts b/GatewayPlugin/config.ts index 734f8b660c..9c2b1df115 100644 --- a/GatewayPlugin/config.ts +++ b/GatewayPlugin/config.ts @@ -1,23 +1,48 @@ // 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 +export const availablePasses: { + name: string + value: string + description: string + isSybilResistance: boolean +}[] = [ + // Default + { + name: 'Uniqueness', + value: 'uniqobk8oGh4XBLMqM68K8M2zNu3CdYX7q5go7whQiv', + description: + 'A biometric proof of personhood, preventing Sybil attacks while retaining privacy', + isSybilResistance: true, + }, + { + name: 'ID Verification', + value: 'bni1ewus6aMxTxBi5SAfzEmmXLf8KcVFRmTfproJuKw', + description: + 'A KYC process for your DAO, allowing users to prove their identity by presenting a government-issued ID', + isSybilResistance: false, + }, + { + name: 'Bot Resistance', + value: 'ignREusXmGrscGNUesoU9mxfds9AiYTezUKex2PsZV6', + description: 'A simple CAPTCHA to prevent bots from spamming your DAO', + isSybilResistance: false, + }, + { + name: 'Other', + value: '', + description: + 'Set up your own custom verification (contact Civic.com for options)', + isSybilResistance: false, + }, +] + +// 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 +export type CivicPass = ArrayElement + +// Use this when populating a dropdown +export const defaultPass: CivicPass = availablePasses[0] +// Use this in cases where you are implicitly adding sybil resistance to a DAO (e.g. QV DAO creation), rather than +// offering a choice - this allows defaultPass to be something *other than* sybil resistance without breaking things. +export const defaultSybilResistancePass = availablePasses[0] diff --git a/GatewayPlugin/sdk/accounts.tsx b/GatewayPlugin/sdk/accounts.tsx deleted file mode 100644 index 7a8bf84f1c..0000000000 --- a/GatewayPlugin/sdk/accounts.tsx +++ /dev/null @@ -1,124 +0,0 @@ -import { PublicKey } from '@solana/web3.js' -import { - getTokenOwnerRecordAddress, - ProgramAccount, - Realm, -} from '@solana/spl-governance' -import { GatewayClient } from '@solana/governance-program-library/dist' -import { getRegistrarPDA, getVoterWeightRecord } from '@utils/plugin/accounts' -import { notify } from '@utils/notifications' - -export const getGatekeeperNetwork = async ( - client: GatewayClient, - realm: ProgramAccount -): Promise => { - // Get the registrar for the realm - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - client.program.programId - ) - const registrarObject = await client.program.account.registrar.fetch( - registrar - ) - - // Find the gatekeeper network from the registrar - return registrarObject.gatekeeperNetwork -} - -const getPredecessorProgramId = async ( - client: GatewayClient, - realm: ProgramAccount -): Promise => { - // Get the registrar for the realm - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - client.program.programId - ) - const registrarObject = await client.program.account.registrar.fetch( - registrar - ) - - // Find the gatekeeper network from the registrar - return registrarObject.previousVoterWeightPluginProgramId -} - -export const getPreviousVotingWeightRecord = async ( - client: GatewayClient, - realm: ProgramAccount, - walletPk: PublicKey -): Promise => { - // TODO cache this to avoid lookup every time someone votes - const predecessorProgramId = await getPredecessorProgramId(client, realm) - - if (predecessorProgramId) { - // this gateway plugin registrar has a predecessor plugin - get its voting weight record - const { voterWeightPk } = await getVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - walletPk, - predecessorProgramId - ) - return voterWeightPk - } - - // this gateway plugin registrar has no predecessor plugin. - // The previous voting weight record is the token owner record - return getTokenOwnerRecordAddress( - realm.owner, - realm.pubkey, - realm.account.communityMint, - walletPk - ) -} - -export const getVoteInstruction = async ( - client: GatewayClient, - gatewayToken: PublicKey, - realm: ProgramAccount, - walletPk: PublicKey -) => { - // Throw if the user has no gateway token (TODO handle this later) - if (!gatewayToken) { - const error = new Error( - `Unable to execute transaction: No Civic Pass found` - ) - notify({ type: 'error', message: `${error}` }) - throw error - } - - // get the user's voter weight account address - const { voterWeightPk } = await getVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - walletPk, - client.program.programId - ) - - // Get the registrar for the realm - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - client.program.programId - ) - - // the previous voting weight record in the chain of plugins, - // or the token owner record if this is the first plugin in the chain - const inputVoterWeight = await getPreviousVotingWeightRecord( - client, - realm, - walletPk - ) - - // call updateVotingWeightRecord on the plugin - return client.program.methods - .updateVoterWeightRecord() - .accounts({ - registrar, - voterWeightRecord: voterWeightPk, - inputVoterWeight, - gatewayToken, - }) - .instruction() -} diff --git a/GatewayPlugin/sdk/api.ts b/GatewayPlugin/sdk/api.ts index ecce0caab5..d95e6d92e6 100644 --- a/GatewayPlugin/sdk/api.ts +++ b/GatewayPlugin/sdk/api.ts @@ -1,16 +1,65 @@ -import { PublicKey } from '@solana/web3.js' -import { GatewayClient } from '@solana/governance-program-library' +import {PublicKey} from '@solana/web3.js' +import {GatewayClient} from '@solana/governance-program-library' +import {ProgramAccount, Realm, SYSTEM_PROGRAM_ID} from "@solana/spl-governance"; +import {getRegistrarPDA} from "@utils/plugin/accounts"; -export const tryGetGatewayRegistrar = async ( - registrarPk: PublicKey, - client: GatewayClient + +// 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 ) => { - try { - const existingRegistrar = await client.program.account.registrar.fetch( - registrarPk - ) - return existingRegistrar - } catch (e) { - return null - } + const {registrar} = getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + gatewayClient.program.programId + ) + + const remainingAccounts = predecessor + ? [{pubkey: predecessor, isSigner: false, isWritable: false}] + : [] + + return gatewayClient!.program.methods + .createRegistrar(!!predecessor) + .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} = 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/GatewayPlugin/store/gatewayPluginStore.ts b/GatewayPlugin/store/gatewayPluginStore.ts deleted file mode 100644 index 33020c28aa..0000000000 --- a/GatewayPlugin/store/gatewayPluginStore.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { BN } from '@coral-xyz/anchor' -import { MaxVoterWeightRecord, ProgramAccount } from '@solana/spl-governance' -import { VotingClient } from '@utils/uiTypes/VotePlugin' -import create, { State } from 'zustand' -import { PublicKey } from '@solana/web3.js' - -interface gatewayPluginStore extends State { - state: { - gatewayToken: PublicKey | null - gatekeeperNetwork: PublicKey | null - votingPower: BN - maxVoteRecord: ProgramAccount | null - isLoadingGatewayToken: boolean - } - setGatewayToken: (gatewayToken: PublicKey, votingClient: VotingClient) => void - setGatekeeperNetwork: (gatekeeperNetwork: PublicKey) => void - setVotingPower: (gatewayToken: PublicKey) => void - setMaxVoterWeight: ( - maxVoterRecord: ProgramAccount | null - ) => void - setIsLoadingGatewayToken: (val: boolean) => void -} - -const defaultState = { - gatewayToken: null, - gatekeeperNetwork: null, - votingPower: new BN(0), - maxVoteRecord: null, - isLoadingGatewayToken: false, -} - -const useGatewayPluginStore = create((set, _get) => ({ - state: { - ...defaultState, - }, - setIsLoadingGatewayToken: (val) => { - set((s) => { - s.state.isLoadingGatewayToken = val - }) - }, - setGatewayToken: (gatewayToken, votingClient) => { - votingClient._setCurrentVoterGatewayToken(gatewayToken) - set((s) => { - s.state.gatewayToken = gatewayToken - }) - _get().setVotingPower(gatewayToken) - }, - setGatekeeperNetwork: (gatekeeperNetwork) => { - set((s) => { - s.state.gatekeeperNetwork = gatekeeperNetwork - }) - }, - - setVotingPower: () => { - set((s) => { - s.state.votingPower = new BN(1) - }) - }, - setMaxVoterWeight: (maxVoterRecord) => { - set((s) => { - s.state.maxVoteRecord = maxVoterRecord - }) - }, -})) - -export default useGatewayPluginStore diff --git a/HeliumVotePlugin/components/ClaimUnreleasedPositions.tsx b/HeliumVotePlugin/components/ClaimUnreleasedPositions.tsx index 15fad243a2..db761c946d 100644 --- a/HeliumVotePlugin/components/ClaimUnreleasedPositions.tsx +++ b/HeliumVotePlugin/components/ClaimUnreleasedPositions.tsx @@ -1,8 +1,6 @@ import { useEffect, useState } from 'react' import { TransactionInstruction } from '@solana/web3.js' import { SecondaryButton } from '@components/Button' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { chunks } from '@utils/helpers' import { registrarKey, @@ -20,6 +18,7 @@ import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/to import { useConnection } from '@solana/wallet-adapter-react' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmProposalsQuery } from '@hooks/queries/proposal' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; const NFT_SOL_BALANCE = 0.0014616 @@ -34,30 +33,29 @@ const ClaimUnreleasedPositions = ({ const [ownVoteRecords, setOwnVoteRecords] = useState([]) const [solToBeClaimed, setSolToBeClaimed] = useState(0) const realm = useRealmQuery().data?.result - const votingPlugin = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const { heliumClient } = useHeliumClient(); const { data: proposalsArray } = useRealmProposalsQuery() const { data: tokenOwnerRecord } = useAddressQuery_CommunityTokenOwner() - const isHeliumVsr = votingPlugin.client instanceof HeliumVsrClient + const isHeliumVsr = !!heliumClient; const releasePositions = async () => { if (!wallet?.publicKey) throw new Error('no wallet') if (!realm) throw new Error() if (!tokenOwnerRecord) throw new Error() + if (!heliumClient) throw new Error("No Helium client") setIsLoading(true) const instructions: TransactionInstruction[] = [] const [registrar] = registrarKey( realm.pubkey, realm.account.communityMint, - votingPlugin.client!.program.programId + heliumClient!.program.programId ) const [voterWeightPk] = voterWeightRecordKey( registrar, wallet.publicKey, - votingPlugin.client!.program.programId + heliumClient!.program.programId ) const voteRecords = ownVoteRecords @@ -67,7 +65,7 @@ const ClaimUnreleasedPositions = ({ ) const [posKey] = positionKey( i.account.nftMint, - votingPlugin.client!.program.programId + heliumClient.program.programId ) if ( proposal === undefined || @@ -77,7 +75,7 @@ const ClaimUnreleasedPositions = ({ continue } - const relinquishVoteIx = await (votingPlugin.client as HeliumVsrClient).program.methods + const relinquishVoteIx = await heliumClient.program.methods .relinquishVoteV0() .accounts({ registrar, @@ -120,7 +118,8 @@ const ClaimUnreleasedPositions = ({ } } const getVoteRecords = async () => { - const currentClient = votingPlugin.client as HeliumVsrClient + const currentClient = heliumClient; + if (!currentClient) return const voteRecords = (await currentClient.program.account['nftVoteRecord']?.all([ { @@ -148,11 +147,11 @@ const ClaimUnreleasedPositions = ({ } useEffect(() => { - if (wallet?.publicKey && isHeliumVsr && votingPlugin.client) { + if (wallet?.publicKey && isHeliumVsr && heliumClient) { getVoteRecords() } // 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 - }, [votingPlugin.clientType, isHeliumVsr, wallet?.publicKey?.toBase58()]) + }, [heliumClient, isHeliumVsr, wallet?.publicKey?.toBase58()]) if (isHeliumVsr) { return ( diff --git a/HeliumVotePlugin/components/LockTokensAccount.tsx b/HeliumVotePlugin/components/LockTokensAccount.tsx index c3bb1450f6..ad667c8752 100644 --- a/HeliumVotePlugin/components/LockTokensAccount.tsx +++ b/HeliumVotePlugin/components/LockTokensAccount.tsx @@ -22,7 +22,6 @@ import { getMintMetadata } from '@components/instructions/programs/splToken' import { abbreviateAddress } from '@utils/formatting' import Button from '@components/Button' import { daysToSecs } from '@utils/dateTools' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { LockCommunityTokensBtn } from './LockCommunityTokensBtn' import { LockTokensModal, LockTokensModalFormValues } from './LockTokensModal' import { useCreatePosition } from '../hooks/useCreatePosition' @@ -45,6 +44,9 @@ import { } from '@hooks/queries/mintInfo' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { fetchJupiterPrice } from '@hooks/queries/jupiterPrice' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; +import {Registrar} from "../sdk/types"; +import {useVotingClients} from "@hooks/useVotingClients"; export const LockTokensAccount: React.FC<{ // tokenOwnerRecordPk: string | string[] | undefined // @asktree: this was unused @@ -74,15 +76,18 @@ export const LockTokensAccount: React.FC<{ : // I wanted to eliminate `null` as a possible type wallet?.publicKey ?? undefined - const [ - currentClient, - vsrClient, - vsrRegistrar, - ] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.heliumVsrClient, - s.state.heliumVsrRegistrar, - ]) + const { heliumClient: vsrClient } = useHeliumClient(); + const votingClients = useVotingClients(); + + const vsrRegistrar = useAsync( + async () => { + if (realm && vsrClient) { + return vsrClient.getRegistrarAccount(realm?.pubkey, realm?.account.communityMint) as Promise + } + }, + [realm, vsrClient] + ) + const { loading: loadingSubDaos, error: subDaosError, @@ -136,7 +141,7 @@ export const LockTokensAccount: React.FC<{ vsrClient ) { await getPositions({ - votingClient: currentClient, + votingClient: votingClients('community'), // community mint is hardcoded for getPositions realmPk: realm.pubkey, communityMintPk: realm.account.communityMint, walletPk: tokenOwnerRecordWalletPk @@ -208,10 +213,10 @@ export const LockTokensAccount: React.FC<{ (lockupPeriodInDays: number) => calcLockupMultiplier({ lockupSecs: daysToSecs(lockupPeriodInDays), - registrar: vsrRegistrar, + registrar: vsrRegistrar.result ?? null, realm, }), - [realm, vsrRegistrar] + [realm, vsrRegistrar.result] ) const handleLockTokens = async (values: LockTokensModalFormValues) => { @@ -229,7 +234,7 @@ export const LockTokensAccount: React.FC<{ if (!error) { await getPositions({ - votingClient: currentClient, + votingClient: votingClients('community'), // community mint is hardcoded for getPositions realmPk: realm!.pubkey, communityMintPk: realm!.account.communityMint, walletPk: wallet!.publicKey!, @@ -401,7 +406,6 @@ export const LockTokensAccount: React.FC<{
diff --git a/HeliumVotePlugin/components/PositionCard.tsx b/HeliumVotePlugin/components/PositionCard.tsx index 1ee16ac0bf..7a3c0adf21 100644 --- a/HeliumVotePlugin/components/PositionCard.tsx +++ b/HeliumVotePlugin/components/PositionCard.tsx @@ -1,5 +1,4 @@ import React, { useCallback, useState, useMemo } from 'react' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { fmtMintAmount, getMintDecimalAmount } from '@tools/sdk/units' import tokenPriceService from '@utils/services/tokenPrice' import { abbreviateAddress } from '@utils/formatting' @@ -14,7 +13,7 @@ import { getMinDurationFmt, getTimeLeftFromNowFmt, } from '@utils/dateTools' -import { PositionWithMeta, SubDaoWithMeta } from '../sdk/types' +import {PositionWithMeta, Registrar, SubDaoWithMeta} from '../sdk/types' import useHeliumVsrStore from '../hooks/useHeliumVsrStore' import { LockTokensModal, @@ -39,6 +38,9 @@ import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' import queryClient from '@hooks/queries/queryClient' import { tokenAccountQueryKeys } from '@hooks/queries/tokenAccount' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; +import {useVotingClients} from "@hooks/useVotingClients"; +import {useAsync} from "react-async-hook"; interface PositionCardProps { subDaos?: SubDaoWithMeta[] @@ -65,15 +67,17 @@ export const PositionCard: React.FC = ({ s.state.positions, s.getPositions, ]) - const [ - currentClient, - vsrClient, - vsrRegistrar, - ] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.heliumVsrClient, - s.state.heliumVsrRegistrar, - ]) + const { heliumClient: vsrClient } = useHeliumClient(); + const votingClients = useVotingClients(); + + const vsrRegistrar = useAsync( + async () => { + if (realm && vsrClient) { + return vsrClient.getRegistrarAccount(realm?.pubkey, realm?.account.communityMint) as Promise + } + }, + [realm, vsrClient] + ) const transferablePositions: PositionWithMeta[] = useMemo(() => { if (!unixNow || !positions.length) { @@ -189,10 +193,10 @@ export const PositionCard: React.FC = ({ (lockupPeriodInDays: number) => calcLockupMultiplier({ lockupSecs: daysToSecs(lockupPeriodInDays), - registrar: vsrRegistrar, + registrar: vsrRegistrar.result ?? null, realm, }), - [realm, vsrRegistrar] + [realm, vsrRegistrar.result] ) const refetchState = async () => { @@ -200,7 +204,7 @@ export const PositionCard: React.FC = ({ queryKey: tokenAccountQueryKeys.all(connection.endpoint), }) await getPositions({ - votingClient: currentClient, + votingClient: votingClients('community'), // community mint is hardcoded for getPositions realmPk: realm!.pubkey, communityMintPk: realm!.account.communityMint, walletPk: wallet!.publicKey!, 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/HeliumVotePlugin/hooks/useClosePosition.ts b/HeliumVotePlugin/hooks/useClosePosition.ts index 7088a69eed..cacbb2ed2b 100644 --- a/HeliumVotePlugin/hooks/useClosePosition.ts +++ b/HeliumVotePlugin/hooks/useClosePosition.ts @@ -4,8 +4,6 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js' import { useAsyncCallback } from 'react-async-hook' import { PositionWithMeta } from '../sdk/types' import useRealm from '@hooks/useRealm' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { useSolanaUnixNow } from '@hooks/useSolanaUnixNow' import { SequenceType } from '@blockworks-foundation/mangolana/lib/globalTypes' import { notify } from '@utils/notifications' @@ -15,15 +13,14 @@ import { } from '@utils/sendTransactions' import { withCreateTokenOwnerRecord } from '@solana/spl-governance' import { useRealmQuery } from '@hooks/queries/realm' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useClosePosition = () => { const { unixNow } = useSolanaUnixNow() const { connection, wallet } = useWalletDeprecated() const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const [{ client }] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - ]) + const { heliumClient } = useHeliumClient(); const { error, loading, execute } = useAsyncCallback( async ({ position, @@ -39,8 +36,7 @@ export const useClosePosition = () => { !connection.current || !realm || !realmInfo || - !client || - !(client instanceof HeliumVsrClient) || + !heliumClient || !wallet || position.numActiveVotes > 0 || // lockupExpired @@ -69,7 +65,7 @@ export const useClosePosition = () => { } instructions.push( - await client.program.methods + await heliumClient.program.methods .withdrawV0({ amount: position.amountDepositedNative, }) @@ -81,7 +77,7 @@ export const useClosePosition = () => { ) instructions.push( - await client.program.methods + await heliumClient.program.methods .closePositionV0() .accounts({ position: position.pubkey, diff --git a/HeliumVotePlugin/hooks/useCreatePosition.ts b/HeliumVotePlugin/hooks/useCreatePosition.ts index 7f7898a775..1783a64081 100644 --- a/HeliumVotePlugin/hooks/useCreatePosition.ts +++ b/HeliumVotePlugin/hooks/useCreatePosition.ts @@ -12,8 +12,6 @@ import { useAsyncCallback } from 'react-async-hook' import { positionKey } from '@helium/voter-stake-registry-sdk' import useRealm from '@hooks/useRealm' import { LockupKind } from 'HeliumVotePlugin/components/LockTokensModal' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { notify } from '@utils/notifications' import { sendTransactionsV3, @@ -21,15 +19,16 @@ import { txBatchesToInstructionSetWithSigners, } from '@utils/sendTransactions' import { useRealmQuery } from '@hooks/queries/realm' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useCreatePosition = () => { const { connection, wallet } = useWalletDeprecated() const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const [{ client }, registrarPk] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.voteStakeRegistryRegistrarPk, - ]) + const {heliumClient} = useHeliumClient(); + const registrarPk = realm && heliumClient ? + heliumClient.getRegistrarPDA(realm.pubkey, realm.account.communityMint).registrar : undefined; + const { error, loading, execute } = useAsyncCallback( async ({ amount, @@ -47,8 +46,7 @@ export const useCreatePosition = () => { !connection.current || !registrarPk || !realm || - !client || - !(client instanceof HeliumVsrClient) || + !heliumClient || !wallet || !realmInfo || !realmInfo.programVersion @@ -98,7 +96,7 @@ export const useCreatePosition = () => { } instructions.push( - await client.program.methods + await heliumClient.program.methods .initializePositionV0({ kind: { [lockupKind]: {} }, periods: lockupPeriodsInDays, @@ -113,7 +111,7 @@ export const useCreatePosition = () => { ) instructions.push( - await client.program.methods + await heliumClient.program.methods .depositV0({ amount, }) diff --git a/HeliumVotePlugin/hooks/useExtendPosition.ts b/HeliumVotePlugin/hooks/useExtendPosition.ts index f95a0df691..22d1fe7e8a 100644 --- a/HeliumVotePlugin/hooks/useExtendPosition.ts +++ b/HeliumVotePlugin/hooks/useExtendPosition.ts @@ -11,18 +11,15 @@ import { sendTransactionsV3, txBatchesToInstructionSetWithSigners, } from '@utils/sendTransactions' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { withCreateTokenOwnerRecord } from '@solana/spl-governance' import { useRealmQuery } from '@hooks/queries/realm' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useExtendPosition = () => { const { connection, wallet, anchorProvider: provider } = useWalletDeprecated() const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const [{ client }] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - ]) + const {heliumClient} = useHeliumClient(); const { error, loading, execute } = useAsyncCallback( async ({ position, @@ -41,9 +38,8 @@ export const useExtendPosition = () => { !provider || !realm || !wallet || - !client || - !realmInfo || - !(client instanceof HeliumVsrClient) + !heliumClient || + !realmInfo; const idl = await Program.fetchIdl(programId, provider) const hsdProgram = await init(provider as any, programId, idl) @@ -84,7 +80,7 @@ export const useExtendPosition = () => { ) } else { instructions.push( - await client.program.methods + await heliumClient.program.methods .resetLockupV0({ kind: position.lockup.kind, periods: lockupPeriodsInDays, diff --git a/HeliumVotePlugin/hooks/useFlipPositionLockupKind.ts b/HeliumVotePlugin/hooks/useFlipPositionLockupKind.ts index 12648cbc2c..7b597887cf 100644 --- a/HeliumVotePlugin/hooks/useFlipPositionLockupKind.ts +++ b/HeliumVotePlugin/hooks/useFlipPositionLockupKind.ts @@ -12,20 +12,17 @@ import { sendTransactionsV3, txBatchesToInstructionSetWithSigners, } from '@utils/sendTransactions' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { useSolanaUnixNow } from '@hooks/useSolanaUnixNow' import { withCreateTokenOwnerRecord } from '@solana/spl-governance' import { useRealmQuery } from '@hooks/queries/realm' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useFlipPositionLockupKind = () => { const { unixNow } = useSolanaUnixNow() const { connection, wallet, anchorProvider: provider } = useWalletDeprecated() const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const [{ client }] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - ]) + const {heliumClient} = useHeliumClient(); const { error, loading, execute } = useAsyncCallback( async ({ position, @@ -41,10 +38,9 @@ export const useFlipPositionLockupKind = () => { !connection.current || !realm || !wallet || - !client || + !heliumClient || !unixNow || !realmInfo || - !(client instanceof HeliumVsrClient) || position.numActiveVotes > 0 const lockupKind = Object.keys(position.lockup.kind)[0] as string @@ -100,7 +96,7 @@ export const useFlipPositionLockupKind = () => { ) } else { instructions.push( - await client.program.methods + await heliumClient.program.methods .resetLockupV0({ kind, periods: positionLockupPeriodInDays, diff --git a/HeliumVotePlugin/hooks/useSplitPosition.ts b/HeliumVotePlugin/hooks/useSplitPosition.ts index ab6307fae0..b478eabf3f 100644 --- a/HeliumVotePlugin/hooks/useSplitPosition.ts +++ b/HeliumVotePlugin/hooks/useSplitPosition.ts @@ -13,8 +13,6 @@ import { PositionWithMeta } from '../sdk/types' import { PROGRAM_ID, init, daoKey } from '@helium/helium-sub-daos-sdk' import useRealm from '@hooks/useRealm' import { LockupKind } from 'HeliumVotePlugin/components/LockTokensModal' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { getMintNaturalAmountFromDecimalAsBN } from '@tools/sdk/units' import { positionKey } from '@helium/voter-stake-registry-sdk' import { notify } from '@utils/notifications' @@ -26,16 +24,16 @@ import { import { chunks } from '@utils/helpers' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useSplitPosition = () => { const { connection, wallet, anchorProvider: provider } = useWalletDeprecated() const realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result const { realmInfo } = useRealm() - const [{ client }, registrarPk] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.voteStakeRegistryRegistrarPk, - ]) + const {heliumClient} = useHeliumClient(); + const registrarPk = realm && heliumClient ? + heliumClient.getRegistrarPDA(realm.pubkey, realm.account.communityMint).registrar : undefined; const { error, loading, execute } = useAsyncCallback( async ({ sourcePosition, @@ -59,8 +57,7 @@ export const useSplitPosition = () => { !realm || !registrarPk || !realm || - !client || - !(client instanceof HeliumVsrClient) || + !heliumClient || !wallet || !realmInfo || !realmInfo.programVersion || @@ -121,7 +118,7 @@ export const useSplitPosition = () => { } instructions.push( - await client.program.methods + await heliumClient.program.methods .initializePositionV0({ kind: { [lockupKind]: {} }, periods: lockupPeriodsInDays, @@ -151,7 +148,7 @@ export const useSplitPosition = () => { ) } else { instructions.push( - await client.program.methods + await heliumClient.program.methods .transferV0({ amount: amountToTransfer, }) @@ -166,7 +163,7 @@ export const useSplitPosition = () => { if (amountToTransfer.eq(sourcePosition.amountDepositedNative)) { instructions.push( - await client.program.methods + await heliumClient.program.methods .closePositionV0() .accounts({ position: sourcePosition.pubkey, @@ -186,7 +183,7 @@ export const useSplitPosition = () => { sequenceType: SequenceType.Sequential, })) - notify({ message: 'Spliting Position' }) + notify({ message: 'Splitting Position' }) await sendTransactionsV3({ transactionInstructions: txsChunks, wallet, diff --git a/HeliumVotePlugin/hooks/useTransferPosition.ts b/HeliumVotePlugin/hooks/useTransferPosition.ts index d7e68e5105..d45f9d8b8e 100644 --- a/HeliumVotePlugin/hooks/useTransferPosition.ts +++ b/HeliumVotePlugin/hooks/useTransferPosition.ts @@ -4,8 +4,6 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js' import { useAsyncCallback } from 'react-async-hook' import { PositionWithMeta } from '../sdk/types' import { PROGRAM_ID, init, daoKey } from '@helium/helium-sub-daos-sdk' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' import { getMintNaturalAmountFromDecimalAsBN } from '@tools/sdk/units' import { notify } from '@utils/notifications' import { @@ -15,15 +13,13 @@ import { } from '@utils/sendTransactions' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' +import {useHeliumClient} from "../../VoterWeightPlugins/useHeliumClient"; export const useTransferPosition = () => { const { connection, wallet, anchorProvider: provider } = useWalletDeprecated() const realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result - const [{ client }] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.voteStakeRegistryRegistrarPk, - ]) + const {heliumClient} = useHeliumClient(); const { error, loading, execute } = useAsyncCallback( async ({ sourcePosition, @@ -43,8 +39,7 @@ export const useTransferPosition = () => { !realm || !mint || !wallet || - !client || - !(client instanceof HeliumVsrClient) || + !heliumClient || sourcePosition.numActiveVotes > 0 || targetPosition.numActiveVotes > 0 @@ -80,7 +75,7 @@ export const useTransferPosition = () => { ) } else { instructions.push( - await client.program.methods + await heliumClient.program.methods .transferV0({ amount: amountToTransfer, }) @@ -95,7 +90,7 @@ export const useTransferPosition = () => { if (amountToTransfer.eq(sourcePosition.amountDepositedNative)) { instructions.push( - await client.program.methods + await heliumClient.program.methods .closePositionV0() .accounts({ position: sourcePosition.pubkey, @@ -104,7 +99,7 @@ export const useTransferPosition = () => { ) } - notify({ message: 'Transfering' }) + notify({ message: 'Transferring' }) await sendTransactionsV3({ transactionInstructions: [ { diff --git a/HeliumVotePlugin/sdk/client.ts b/HeliumVotePlugin/sdk/client.ts index 3b35645781..b6341f95fc 100644 --- a/HeliumVotePlugin/sdk/client.ts +++ b/HeliumVotePlugin/sdk/client.ts @@ -1,21 +1,111 @@ -import { Program, Provider, web3 } from '@coral-xyz/anchor' -import { VoterStakeRegistry } from '@helium/idls/lib/types/voter_stake_registry' -import { PROGRAM_ID, init } from '@helium/voter-stake-registry-sdk' +import {Program, Provider, web3 } from '@coral-xyz/anchor' +import { VoterStakeRegistry, IDL } from '@helium/idls/lib/types/voter_stake_registry' +import {PROGRAM_ID, init, registrarKey, voterWeightRecordKey} from '@helium/voter-stake-registry-sdk' +import {Client, DEFAULT_GOVERNANCE_PROGRAM_ID} from "@solana/governance-program-library"; +import {PublicKey, TransactionInstruction} from "@solana/web3.js"; +import {getTokenOwnerRecordAddress, VoterWeightAction} from "@solana/spl-governance"; +import {AccountData} from "@utils/uiTypes/VotePlugin"; +import {getAssociatedTokenAddress} from "@blockworks-foundation/mango-v4"; +import BN from "bn.js"; +import {getPositions, GetPositionsReturn} from "../utils/getPositions"; -export class HeliumVsrClient { +export class HeliumVsrClient extends Client { constructor( public program: Program, - public devent?: boolean - ) {} + public devnet: boolean, + readonly governanceProgramId: PublicKey + ) { + super(program, devnet) + } + + readonly requiresInputVoterWeight = false; + + // NO-OP TODO: Double-check + async createVoterWeightRecord(): Promise { + return null; + } + + // NO-OP + async createMaxVoterWeightRecord(): Promise { + return null; + } + + async updateVoterWeightRecord(voter: PublicKey, realm: PublicKey, mint: PublicKey, action: VoterWeightAction) { + const { positions } = await this.getPositions(voter, realm, mint); + const tokenOwnerRecord = await getTokenOwnerRecordAddress(this.governanceProgramId, realm, mint, voter); + + const remainingAccounts: AccountData[] = [] + const [registrar] = registrarKey( + realm, + mint, + this.program.programId + ) + + for (const pos of positions) { + const tokenAccount = await getAssociatedTokenAddress( + pos.mint, + voter, + true + ) + + remainingAccounts.push( + new AccountData(tokenAccount), + new AccountData(pos.pubkey) + ) + } + + const [voterWeightPk] = voterWeightRecordKey( + registrar, + voter, + this.program.programId + ) + + const ix = await this.program.methods + .updateVoterWeightRecordV0({ + owner: voter, + voterWeightAction: { + [action]: {}, + }, + } as any) + .accounts({ + registrar, + voterWeightRecord: voterWeightPk, + voterTokenOwnerRecord: tokenOwnerRecord, + }) + .remainingAccounts(remainingAccounts.slice(0, 10)) + .instruction(); + + return { pre: [ix] } + } + // NO-OP + async updateMaxVoterWeightRecord(): Promise { + return null; + } + async calculateVoterWeight(voter: PublicKey, realm: PublicKey, mint: PublicKey): Promise { + const positionDetails = await this.getPositions(voter, realm, mint); + return positionDetails.votingPower + } + + private async getPositions(voter: PublicKey, realm: PublicKey, mint: PublicKey): Promise { + return getPositions({ + realmPk: realm, + walletPk: voter, + communityMintPk: mint, + client: this, + connection: this.program.provider.connection + }) + } static async connect( provider: Provider, programId: web3.PublicKey = PROGRAM_ID, - devnet?: boolean + devnet = false, + governanceProgramId = DEFAULT_GOVERNANCE_PROGRAM_ID ): Promise { return new HeliumVsrClient( (await init(provider as any, programId)) as any, - devnet + devnet, + governanceProgramId, ) } } 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/NftVotePlugin/NftProposalVoteState.tsx b/NftVotePlugin/NftProposalVoteState.tsx index 65c849c7bc..c087e8c524 100644 --- a/NftVotePlugin/NftProposalVoteState.tsx +++ b/NftVotePlugin/NftProposalVoteState.tsx @@ -2,12 +2,12 @@ import { NFT_PLUGINS_PKS } from '@constants/plugins' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { ProgramAccount, Proposal, ProposalState } from '@solana/spl-governance' import { useEffect } from 'react' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useNftProposalStore from './NftProposalStore' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import { useProposalVoteRecordQuery } from '@hooks/queries/voteRecord' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' import { useVotingPop } from '@components/VotePanel/hooks' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import {useNftClient} from "../VoterWeightPlugins/useNftClient"; const NftProposalVoteState = ({ proposal, @@ -16,12 +16,14 @@ const NftProposalVoteState = ({ }) => { const config = useRealmConfigQuery().data?.result - const plugin = useVotePluginsClientStore((s) => s.state.nftClient) + const { nftClient } = useNftClient(); const getCountedNfts = useNftProposalStore((s) => s.getCountedNfts) const countedNfts = useNftProposalStore((s) => s.countedNftsForProposal) const wallet = useWalletOnePointOh() const votingPop = useVotingPop() - const { result: votingPower } = useGovernancePowerAsync(votingPop) + const { totalCalculatedVoterWeight, isReady } = useRealmVoterWeightPlugins( + votingPop + ) const isNftPlugin = config?.account.communityTokenConfig.voterWeightAddin && NFT_PLUGINS_PKS.includes( @@ -31,13 +33,14 @@ const NftProposalVoteState = ({ const ownVoteRecord = useProposalVoteRecordQuery('electoral').data?.result const showVoteRecords = - votingPower && + isReady && + totalCalculatedVoterWeight?.value && countedNfts.length > 0 && - countedNfts.length < votingPower.toNumber() && + countedNfts.length < totalCalculatedVoterWeight.value.toNumber() && !ownVoteRecord const useComponent = - plugin && + nftClient && proposal && wallet?.connected && isNftPlugin && @@ -46,7 +49,7 @@ const NftProposalVoteState = ({ useEffect(() => { if (useComponent) { - getCountedNfts(plugin, proposal, wallet.publicKey!) + getCountedNfts(nftClient, proposal, wallet.publicKey!) } // 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 }, [useComponent]) diff --git a/ParclVotePlugin/ParclVoterWeightPluginClient.ts b/ParclVotePlugin/ParclVoterWeightPluginClient.ts new file mode 100644 index 0000000000..b196eddd61 --- /dev/null +++ b/ParclVotePlugin/ParclVoterWeightPluginClient.ts @@ -0,0 +1,101 @@ +import {Client} from "@solana/governance-program-library"; +import {PublicKey, TransactionInstruction} from "@solana/web3.js"; +import BN from "bn.js"; +import {StakeAccount, StakeConnection} from "@parcl-oss/staking"; +import {Provider, Wallet} from "@coral-xyz/anchor"; +import {VoterWeightAction} from "@solana/spl-governance"; +import {convertVoterWeightActionToType} from "../VoterWeightPlugins/lib/utils"; +import queryClient from "@hooks/queries/queryClient"; + +// A wrapper for the StakeConnection from @parcl-oss/staking, that implements the generic plugin client interface +export class ParclVoterWeightPluginClient extends Client { + readonly requiresInputVoterWeight = false; + // The parcl plugin does not have a registrar account + async getRegistrarAccount(): Promise { + return null; + } + + async getMaxVoterWeightRecordPDA() { + const maxVoterWeightPk = (await this.client.program.methods.updateMaxVoterWeight().pubkeys()).maxVoterRecord + + if (!maxVoterWeightPk) return null; + + return { + maxVoterWeightPk, + maxVoterWeightRecordBump: 0 // This is wrong for Parcl - but it doesn't matter as it is not used + } + } + + async getVoterWeightRecordPDA(realm: PublicKey, mint: PublicKey, voter: PublicKey) { + const { voterWeightAccount } = await this.getUpdateVoterWeightPks([], voter, VoterWeightAction.CastVote, PublicKey.default); + + return { + voterWeightPk: voterWeightAccount, + voterWeightRecordBump: 0 // This is wrong for Parcl - but it doesn't matter as it is not used + }; + } + + // NO-OP Parcl records are created through the Parcl dApp. + async createVoterWeightRecord(): Promise { + return null; + } + + // NO-OP + async createMaxVoterWeightRecord(): Promise { + return null; + } + + private async getStakeAccount(voter: PublicKey): Promise { + return queryClient.fetchQuery({ + queryKey: ['parcl getStakeAccount', voter], + queryFn: async() => { + const account = await this.client.getMainAccount(voter) + return account !== undefined ? account : null + }, + }) + } + + private async getUpdateVoterWeightPks(instructions: TransactionInstruction[], voter: PublicKey, action: VoterWeightAction, target?: PublicKey) { + const stakeAccount = await this.getStakeAccount(voter) + + if (!stakeAccount) throw new Error("Stake account not found for voter " + voter.toString()); + return this.client.withUpdateVoterWeight( + instructions, + stakeAccount, + { [convertVoterWeightActionToType(action)]: {} } as any, + target + ); + } + + async updateVoterWeightRecord(voter: PublicKey, realm: PublicKey, mint: PublicKey, action: VoterWeightAction, inputRecordCallback?: () => Promise, target?: PublicKey) { + const instructions: TransactionInstruction[] = []; + await this.getUpdateVoterWeightPks(instructions, voter, action, target); + + return { pre: instructions }; + } + // NO-OP + async updateMaxVoterWeightRecord(): Promise { + return null; + } + async calculateVoterWeight(voter: PublicKey): Promise { + const stakeAccount = await this.getStakeAccount(voter) + + if (stakeAccount) { + return stakeAccount.getVoterWeight(await this.client.getTime()).toBN() + } else { + return new BN(0) + } + } + constructor(program: typeof StakeConnection.prototype.program, private client: StakeConnection, devnet:boolean) { + super(program, devnet); + } + + static async connect(provider: Provider, devnet = false, wallet: Wallet): Promise { + const parclClient = await StakeConnection.connect( + provider.connection, + wallet + ) + + return new ParclVoterWeightPluginClient(parclClient.program, parclClient, devnet); + } +} \ No newline at end of file diff --git a/ParclVotePlugin/components/ParclAccountDetails.tsx b/ParclVotePlugin/components/ParclAccountDetails.tsx new file mode 100644 index 0000000000..16fa342857 --- /dev/null +++ b/ParclVotePlugin/components/ParclAccountDetails.tsx @@ -0,0 +1,163 @@ +import { MintInfo } from '@solana/spl-token' +import BN from 'bn.js' +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 { useRealmCommunityMintInfoQuery, useRealmCouncilMintInfoQuery } from '@hooks/queries/mintInfo' +import ParclVotingPower from './ParclVotingPower' +import { useUserTokenAccountsQuery } from '@hooks/queries/tokenAccount' +import { useRealmQuery } from '@hooks/queries/realm' +import { PublicKey } from '@solana/web3.js' +import VanillaWithdrawTokensButton from '@components/TokenBalance/VanillaWithdrawTokensButton' +import { Deposit } from '@components/GovernancePower/Power/Vanilla/Deposit' + +export const PARCL_INSTRUCTIONS = + 'You can deposit PRCL tokens at https://app.parcl.co/staking' + +const TokenDeposit = ({ + mintInfo, + mintAddress, + inAccountDetails, + setHasGovPower, + role +}: { + mintInfo: MintInfo | undefined, + mintAddress: PublicKey, + inAccountDetails?: boolean, + role: 'council' | 'community', + setHasGovPower?: (hasGovPower: boolean) => void +}) => { + const wallet = useWalletOnePointOh() + const { data: tokenAccounts } = useUserTokenAccountsQuery() + const connected = !!wallet?.connected + + const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result + const config = useRealmConfigQuery().data?.result + + const relevantTokenConfig = role === "community" + ? config?.account.communityTokenConfig + : config?.account.councilTokenConfig; + + const isMembership = + relevantTokenConfig?.tokenType === GoverningTokenType.Membership + const isDormant = + relevantTokenConfig?.tokenType === GoverningTokenType.Dormant; + + const depositTokenRecord = ownTokenRecord + const depositTokenAccount = tokenAccounts?.find((a) => + a.account.mint.equals(mintAddress) + ); + + const hasTokensInWallet = + depositTokenAccount && depositTokenAccount.account.amount.gt(new BN(0)) + + const hasTokensDeposited = + depositTokenRecord && + depositTokenRecord.account.governingTokenDepositAmount.gt(new BN(0)) + + const availableTokens = + depositTokenRecord && mintInfo + ? fmtMintAmount( + mintInfo, + 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(mintInfo, depositTokenAccount.account.amount) + : hasTokensInWallet + ? availableTokens + : 0 + + // Do not show deposits for mints with zero supply because nobody can deposit anyway + if (!mintInfo || mintInfo.supply.isZero()) { + return null + } + + return ( +
+ {(availableTokens != '0' || inAccountDetails) && ( +
+ +
+ )} +
+ You have {tokensToShow} {hasTokensDeposited ? `more ` : ``} tokens + available to deposit. +
+ { + role === "community" + ?
{PARCL_INSTRUCTIONS}
+ : null + } + { + !isDormant + ? + : null + } +
+ {!isMembership && // Membership tokens can't be withdrawn (that is their whole point, actually) + !isDormant && + inAccountDetails && ( + + )} +
+
+ ) +} + +const ParclAccountDetails = () => { + const realm = useRealmQuery().data?.result + const communityMint = useRealmCommunityMintInfoQuery().data?.result + const councilMint = useRealmCouncilMintInfoQuery().data?.result; + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + const councilMintAddress = realm?.account.config.councilMint; + const hasLoaded = communityMint && councilMint && realm && councilMintAddress; + + return ( + <> + {hasLoaded ? ( +
+ {!connected ? ( +
+ Connect your wallet to see governance power +
+ ) : + ( + <> + + + + )} +
+ ) : ( + <> +
+
+ + )} + + ) +} + +export default ParclAccountDetails diff --git a/ParclVotePlugin/components/ParclVotingPower.tsx b/ParclVotePlugin/components/ParclVotingPower.tsx new file mode 100644 index 0000000000..7d9649f2e8 --- /dev/null +++ b/ParclVotePlugin/components/ParclVotingPower.tsx @@ -0,0 +1,113 @@ +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 { getParclGovPower } 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 useParclScalingFactor from '@hooks/parcl/useScalingFactor' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { useUserTokenAccountsQuery } from '@hooks/queries/tokenAccount' + +interface Props { + className?: string + role: 'community' | 'council' + hideIfZero?: boolean + children?: React.ReactNode +} + +export default function ParclVotingPower({ + role, + hideIfZero, + children, + ...props +}: Props) { + const realm = useRealmQuery().data?.result + const realmConfig = useRealmConfigQuery().data?.result + const { data: tokenAccounts } = useUserTokenAccountsQuery() + 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 && role === 'community' + ? getParclGovPower(connection, wallet.publicKey) + : tokenAccounts?.find( + (a) => relevantMint && a.account.mint.equals(relevantMint) + )?.account.amount as BN, + [connection, wallet, role, relevantMint, tokenAccounts] + ) + + const parclScalingFactor = useParclScalingFactor() ?? 1; + + const totalAmount = personalAmount ?? new BN(0) + + const formattedTotal = useMemo( + () => + mintInfo && totalAmount !== undefined + ? new BigNumber(totalAmount.toString()) + .multipliedBy( + role === 'community' + ? parclScalingFactor + : 1 + ) + .shiftedBy(-mintInfo.decimals) + .integerValue() + .toString() + : undefined, + [totalAmount, mintInfo] + ) + + const tokenName = + getMintMetadata(relevantMint)?.name ?? realm?.account.name ?? '' + + const disabled = + realmConfig?.account.councilTokenConfig.tokenType === + GoverningTokenType.Dormant + + return ( +
+
+
+ {tokenName} + {role === 'council' ? ' Council' : ''} Votes +
+
+
+
+ {formattedTotal ?? 0} +
+
+ + {mintInfo && ( + + )} +
+
+ {children} +
+ ) +} 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/QuadraticPlugin/sdk/api.ts b/QuadraticPlugin/sdk/api.ts new file mode 100644 index 0000000000..1edbff051f --- /dev/null +++ b/QuadraticPlugin/sdk/api.ts @@ -0,0 +1,100 @@ +import { PublicKey } from '@solana/web3.js' +import {Coefficients, QuadraticClient } from '@solana/governance-program-library' +import { + ProgramAccount, + Realm, + SYSTEM_PROGRAM_ID, +} from '@solana/spl-governance' +import { getRegistrarPDA } from '@utils/plugin/accounts' + +// By default, the quadratic plugin will use a function ax-2 + bx - c +// resulting in a vote weight that is the square root of the token balance +// The `a` coefficient is set to 1000, which, assuming the governance token has 6 decimals, +// will result in a vote weight that is the square root of the token balance in major denomination. +// For example, if the token balance is 100, then the vote weight will be: +// sqrt(100 * 10^6) = 10,000 * 10^3 = 10,000,000 = 10 votes +// This should be handled dynamically by the UI in the future. +export const DEFAULT_COEFFICIENTS: Coefficients = [1000, 0, 0] + +export const toAnchorType = (coefficients: Coefficients) => ({ + a: coefficients[0], + b: coefficients[1], + c: coefficients[2], +}) + +export type AnchorParams = { + quadraticCoefficients: { + a: number; + b: number; + c: number; + } +} + +// Create an instruction to create a registrar account for a given realm +export const createQuadraticRegistrarIx = async ( + realm: ProgramAccount, + payer: PublicKey, + quadraticClient: QuadraticClient, + coefficients?: Coefficients, + predecessor?: PublicKey +) => { + const { registrar } = getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + quadraticClient.program.programId + ) + + const remainingAccounts = predecessor + ? [{ pubkey: predecessor, isSigner: false, isWritable: false }] + : [] + + return quadraticClient!.program.methods + .createRegistrar( + toAnchorType(coefficients || DEFAULT_COEFFICIENTS), + !!predecessor + ) + .accounts({ + registrar, + realm: realm.pubkey, + governanceProgramId: realm.owner, + realmAuthority: realm.account.authority!, + governingTokenMint: realm.account.communityMint!, + payer, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .remainingAccounts(remainingAccounts) + .instruction() +} +// Create an instruction to configure a registrar account for a given realm +export const configureQuadraticRegistrarIx = async ( + realm: ProgramAccount, + quadraticClient: QuadraticClient, + coefficients?: Coefficients, + predecessor?: PublicKey +) => { + const { registrar } = getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + quadraticClient.program.programId + ) + const remainingAccounts = predecessor + ? [{ pubkey: predecessor, isSigner: false, isWritable: false }] + : [] + return quadraticClient.program.methods + .configureRegistrar( + toAnchorType(coefficients || DEFAULT_COEFFICIENTS), + !!predecessor + ) + .accounts({ + registrar, + realm: realm.pubkey, + realmAuthority: realm.account.authority!, + }) + .remainingAccounts(remainingAccounts) + .instruction() +} + +export const coefficientsEqual = (x: Coefficients, y: Coefficients | undefined): boolean => { + if (!y) return false + return x[0] === y[0] && x[1] === y[1] && x[2] === y[2] +} \ No newline at end of file diff --git a/README.md b/README.md index e69de29bb2..084e2251f5 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,12 @@ +# governance-ui + +This repo still exists in archived form, but the maintained version has now relocated to: https://github.com/Mythic-Project/governance-ui + + +### Using custom Swap API endpoints + +You can set custom URLs via the configuration for any self-hosted Jupiter APIs, like the [V6 Swap API](https://station.jup.ag/docs/apis/self-hosted) or [Paid Hosted APIs](https://station.jup.ag/docs/apis/self-hosted#paid-hosted-apis) Here is an example: + +``` +NEXT_PUBLIC_JUPTER_SWAP_API_ENDPOINT=https://quote-api.jup.ag/v6 +``` diff --git a/Strategies/components/psyfi/Deposit.tsx b/Strategies/components/psyfi/Deposit.tsx index 08f3338e02..7577d0c54a 100644 --- a/Strategies/components/psyfi/Deposit.tsx +++ b/Strategies/components/psyfi/Deposit.tsx @@ -25,7 +25,6 @@ import BigNumber from 'bignumber.js' import { useRouter } from 'next/router' import { pdas } from 'psyfi-euros-test' import React, { useCallback, useEffect, useState } from 'react' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { Action, CreatePsyFiStrategy, @@ -45,6 +44,8 @@ import { } from '@hooks/queries/mintInfo' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import {useVotingClients} from "@hooks/useVotingClients"; +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const SOL_BUFFER = 0.02 @@ -73,9 +74,7 @@ export const Deposit: React.FC<{ canUseTransferInstruction, governedTokenAccountsWithoutNfts, } = useGovernanceAssets() - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients(); const connection = useLegacyConnectionContext() const wallet = useWalletOnePointOh() const [ownedStrategyTokenAccount, setOwnedStrategyTokenAccount] = useState< @@ -89,7 +88,7 @@ export const Deposit: React.FC<{ >() const [depositReceiptPubkey, setDepositReceiptPubkey] = useState() const [isDepositing, setIsDepositing] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, setVoteByCouncil } = useVoteByCouncilToggle(); const [form, setForm] = useState({ strategy: proposedInvestment, title: '', @@ -254,7 +253,7 @@ export const Deposit: React.FC<{ governedTokenAccount!.governance!.account!.proposalCount, false, connection, - client + votingClients(voteByCouncil? 'council' : 'community') ) const url = fmtUrlWithCluster( `/dao/${symbol}/proposal/${proposalAddress}` @@ -268,7 +267,7 @@ export const Deposit: React.FC<{ } // 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 }, [ - client, + votingClients, config, connection, councilMint, diff --git a/Strategies/components/solend/SolendDeposit.tsx b/Strategies/components/solend/SolendDeposit.tsx index f9edc05517..765aa20904 100644 --- a/Strategies/components/solend/SolendDeposit.tsx +++ b/Strategies/components/solend/SolendDeposit.tsx @@ -30,7 +30,6 @@ import { getReserveData, SolendSubStrategy, } from 'Strategies/protocols/solend' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { PublicKey } from '@solana/web3.js' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' @@ -42,6 +41,8 @@ import { import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { useRealmProposalsQuery } from '@hooks/queries/proposal' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import {useVotingClients} from "@hooks/useVotingClients"; +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const SOL_BUFFER = 0.02 @@ -70,10 +71,8 @@ const SolendDeposit = ({ const [deposits, setDeposits] = useState<{ [reserveAddress: string]: number }>({}) - const [voteByCouncil, setVoteByCouncil] = useState(false) - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const { voteByCouncil, setVoteByCouncil } = useVoteByCouncilToggle(); + const votingClients = useVotingClients(); const connection = useLegacyConnectionContext() const wallet = useWalletOnePointOh() const tokenInfo = tokenPriceService.getTokenInfo(handledMint) @@ -249,7 +248,7 @@ const SolendDeposit = ({ governedTokenAccount!.governance!.account!.proposalCount, false, connection, - client + votingClients(voteByCouncil? 'council' : 'community') ) const url = fmtUrlWithCluster( `/dao/${symbol}/proposal/${proposalAddress}` diff --git a/Strategies/components/solend/SolendWithdraw.tsx b/Strategies/components/solend/SolendWithdraw.tsx index 79afbfe3f1..8733c75ead 100644 --- a/Strategies/components/solend/SolendWithdraw.tsx +++ b/Strategies/components/solend/SolendWithdraw.tsx @@ -18,7 +18,6 @@ import BigNumber from 'bignumber.js' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { SolendStrategy } from 'Strategies/types/types' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import AdditionalProposalOptions from '@components/AdditionalProposalOptions' import { validateInstruction } from '@utils/instructionTools' import * as yup from 'yup' @@ -41,6 +40,8 @@ import { import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { useRealmProposalsQuery } from '@hooks/queries/proposal' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import {useVotingClients} from "@hooks/useVotingClients"; +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const SolendWithdraw = ({ proposedInvestment, @@ -68,13 +69,11 @@ const SolendWithdraw = ({ const { result: ownVoterWeight } = useLegacyVoterWeight() const { realmInfo } = useRealm() const [isWithdrawing, setIsWithdrawing] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, setVoteByCouncil } = useVoteByCouncilToggle(); const [deposits, setDeposits] = useState<{ [reserveAddress: string]: { amount: number; amountExact: number } }>({}) - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients(); const proposals = useRealmProposalsQuery().data const connection = useLegacyConnectionContext() const wallet = useWalletOnePointOh() @@ -259,7 +258,7 @@ const SolendWithdraw = ({ governedTokenAccount!.governance!.account!.proposalCount, false, connection, - client + votingClients(voteByCouncil? 'council' : 'community'), ) const url = fmtUrlWithCluster( `/dao/${symbol}/proposal/${proposalAddress}` diff --git a/Strategies/protocols/foresight/tools.ts b/Strategies/protocols/foresight/tools.ts deleted file mode 100644 index db42d1ef84..0000000000 --- a/Strategies/protocols/foresight/tools.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const FORESIGHT_MINT_DEVNET = - 'H7uqouPsJkeEiLpCEoC1qYVVquDrZan6ZfdPK2gS44zm' diff --git a/TokenHaverPlugin/TokenHaverClient.ts b/TokenHaverPlugin/TokenHaverClient.ts new file mode 100644 index 0000000000..7b575a6c8e --- /dev/null +++ b/TokenHaverPlugin/TokenHaverClient.ts @@ -0,0 +1,151 @@ +import { BN, Program, Provider } from '@coral-xyz/anchor' +import { Client } from '@solana/governance-program-library' +import { SYSTEM_PROGRAM_ID } from '@solana/spl-governance' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' + +import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount' +import { fetchRealmByPubkey } from '@hooks/queries/realm' +import { IDL, TokenHaver } from './idl/token_haver' +import { getAssociatedTokenAddress } from '@blockworks-foundation/mango-v4' +import { TOKEN_HAVER_PLUGIN } from './constants' + +export class TokenHaverClient extends Client { + readonly requiresInputVoterWeight = true + + constructor(public program: Program, public devnet: boolean) { + super(program, devnet) + } + + async calculateMaxVoterWeight( + _realm: PublicKey, + _mint: PublicKey + ): Promise { + const { result: realm } = await fetchRealmByPubkey( + this.program.provider.connection, + _realm + ) + return realm?.account.config?.communityMintMaxVoteWeightSource.value ?? null // TODO this code should not actually be called because this is not a max voter weight plugin + } + + async calculateVoterWeight( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey + ): Promise { + const { registrar: registrarPk } = this.getRegistrarPDA(realm, mint) + const registrar = await this.program.account.registrar.fetch(registrarPk) + const countOfTokensUserHas = ( + await Promise.all( + registrar.mints.map(async (mint) => { + const tokenAccountPk = await getAssociatedTokenAddress(mint, voter) + const tokenAccount = await fetchTokenAccountByPubkey( + this.program.provider.connection, + tokenAccountPk + ) + return (tokenAccount.result?.amount ?? new BN(0)).gt(new BN(0)) + ? 1 + : 0 + }) + ) + ).reduce((acc, curr) => acc + curr, 0) + return new BN(countOfTokensUserHas).muln(10 ** 6) + } + + async updateVoterWeightRecord( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey + //action?: VoterWeightAction | undefined, + //inputRecordCallback?: (() => Promise) | undefined + ): Promise<{ + pre: TransactionInstruction[] + post?: TransactionInstruction[] | undefined + }> { + const connection = this.program.provider.connection + const { result: realmAccount } = await fetchRealmByPubkey(connection, realm) + if (!realmAccount) throw new Error('Realm not found') + + const { voterWeightPk } = await this.getVoterWeightRecordPDA( + realm, + mint, + voter + ) + const { registrar: registrarPk } = this.getRegistrarPDA(realm, mint) + const registrar = await this.program.account.registrar.fetch(registrarPk) + + const tokenAccounts = ( + await Promise.all( + registrar.mints.map(async (mint) => { + const tokenAccountPk = await getAssociatedTokenAddress(mint, voter) + // filter out empty accounts + const account = await fetchTokenAccountByPubkey( + this.program.provider.connection, + tokenAccountPk + ) + return account.found ? tokenAccountPk : null + }) + ) + ).filter((x) => x !== null) as PublicKey[] + + const ix = await this.program.methods + .updateVoterWeightRecord() + .accountsStrict({ + voterWeightRecord: voterWeightPk, + registrar: registrarPk, + }) + .remainingAccounts( + tokenAccounts.map((pubkey) => ({ + pubkey, + isSigner: false, + isWritable: false, + })) + ) + .instruction() + + return { pre: [ix] } + } + + // NO-OP + async createMaxVoterWeightRecord(): Promise { + return null + } + + // NO-OP + async updateMaxVoterWeightRecord(): Promise { + return null + } + + static async connect( + provider: Provider, + programId = new PublicKey(TOKEN_HAVER_PLUGIN), + devnet = false + ) { + return new TokenHaverClient( + new Program(IDL, programId, provider), + devnet + ) + } + + async createVoterWeightRecord( + voter: PublicKey, + realm: PublicKey, + mint: PublicKey + ): Promise { + const { voterWeightPk } = await this.getVoterWeightRecordPDA( + realm, + mint, + voter + ) + const { registrar } = this.getRegistrarPDA(realm, mint) + + return this.program.methods + .createVoterWeightRecord(voter) + .accounts({ + voterWeightRecord: voterWeightPk, + registrar, + payer: voter, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .instruction() + } +} diff --git a/TokenHaverPlugin/constants.ts b/TokenHaverPlugin/constants.ts new file mode 100644 index 0000000000..2969211106 --- /dev/null +++ b/TokenHaverPlugin/constants.ts @@ -0,0 +1,5 @@ +import { PublicKey } from '@solana/web3.js' + +export const TOKEN_HAVER_PLUGIN = new PublicKey( + '7gobfUihgoxA14RUnVaseoah89ggCgYAzgz1JoaPAXam' +) diff --git a/TokenHaverPlugin/idl/token_haver.ts b/TokenHaverPlugin/idl/token_haver.ts new file mode 100644 index 0000000000..3cefd2367e --- /dev/null +++ b/TokenHaverPlugin/idl/token_haver.ts @@ -0,0 +1,867 @@ +export type TokenHaver = { + version: '0.0.1' + name: 'token_haver' + instructions: [ + { + name: 'createRegistrar' + accounts: [ + { + name: 'registrar' + isMut: true + isSigner: false + docs: [ + 'The Realm Voter Registrar', + 'There can only be a single registrar per governance Realm and governing mint of the Realm' + ] + }, + { + name: 'governanceProgramId' + isMut: false + isSigner: false + docs: [ + 'The program id of the spl-governance program the realm belongs to' + ] + }, + { + name: 'realm' + isMut: false + isSigner: false + docs: [ + 'An spl-governance Realm', + '', + 'Realm is validated in the instruction:', + '- Realm is owned by the governance_program_id', + '- governing_token_mint must be the community or council mint', + '- realm_authority is realm.authority' + ] + }, + { + name: 'governingTokenMint' + isMut: false + isSigner: false + docs: [ + 'Either the realm community mint or the council mint.', + 'It must match Realm.community_mint or Realm.config.council_mint', + '', + 'Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity', + 'for the voting population and the tokens of that are no longer used' + ] + }, + { + name: 'realmAuthority' + isMut: false + isSigner: true + docs: ['realm_authority must sign and match Realm.authority'] + }, + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'mints' + type: { + vec: 'publicKey' + } + } + ] + }, + { + name: 'createVoterWeightRecord' + accounts: [ + { + name: 'registrar' + isMut: false + isSigner: false + }, + { + name: 'voterWeightRecord' + isMut: true + isSigner: false + }, + { + name: 'payer' + isMut: true + isSigner: true + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'governingTokenOwner' + type: 'publicKey' + } + ] + }, + { + name: 'updateVoterWeightRecord' + accounts: [ + { + name: 'registrar' + isMut: false + isSigner: false + docs: ['The RealmVoter voting Registrar'] + }, + { + name: 'voterWeightRecord' + isMut: true + isSigner: false + } + ] + args: [] + }, + { + name: 'configureMints' + accounts: [ + { + name: 'registrar' + isMut: true + isSigner: false + docs: ['The Registrar for the given realm and governing_token_mint'] + }, + { + name: 'realm' + isMut: false + isSigner: false + }, + { + name: 'payer' + isMut: false + isSigner: true + }, + { + name: 'realmAuthority' + isMut: false + isSigner: true + docs: ['Authority of the Realm must sign and match realm.authority'] + }, + { + name: 'systemProgram' + isMut: false + isSigner: false + } + ] + args: [ + { + name: 'mints' + type: { + vec: 'publicKey' + } + } + ] + } + ] + accounts: [ + { + name: 'maxVoterWeightRecord' + docs: [ + 'MaxVoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide max voting power to the governance program from external addin contracts' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'realm' + docs: ['The Realm the MaxVoterWeightRecord belongs to'] + type: 'publicKey' + }, + { + name: 'governingTokenMint' + docs: [ + 'Governing Token Mint the MaxVoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only' + ] + type: 'publicKey' + }, + { + name: 'maxVoterWeight' + docs: [ + 'Max voter weight', + 'The max voter weight provided by the addin for the given realm and governing_token_mint' + ] + type: 'u64' + }, + { + name: 'maxVoterWeightExpiry' + docs: [ + 'The slot when the max voting weight expires', + 'It should be set to None if the weight never expires', + 'If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight' + ] + type: { + option: 'u64' + } + }, + { + name: 'reserved' + docs: ['Reserved space for future versions'] + type: { + array: ['u8', 8] + } + } + ] + } + }, + { + name: 'registrar' + docs: [ + 'Registrar which stores spl-governance configurations for the given Realm' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'governanceProgramId' + docs: ['spl-governance program the Realm belongs to'] + type: 'publicKey' + }, + { + name: 'realm' + docs: ['Realm of the Registrar'] + type: 'publicKey' + }, + { + name: 'governingTokenMint' + docs: [ + 'Governing token mint the Registrar is for', + 'It can either be the Community or the Council mint of the Realm', + 'When the plugin is enabled the mint is only used as the identity of the governing power (voting population)', + 'and the actual token of the mint is not used' + ] + type: 'publicKey' + }, + { + name: 'mints' + type: { + vec: 'publicKey' + } + } + ] + } + }, + { + name: 'voterWeightRecord' + docs: [ + 'VoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide voting power to the governance program from external addin contracts' + ] + type: { + kind: 'struct' + fields: [ + { + name: 'realm' + docs: ['The Realm the VoterWeightRecord belongs to'] + type: 'publicKey' + }, + { + name: 'governingTokenMint' + docs: [ + 'Governing Token Mint the VoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only' + ] + type: 'publicKey' + }, + { + name: 'governingTokenOwner' + docs: [ + 'The owner of the governing token and voter', + 'This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner' + ] + type: 'publicKey' + }, + { + name: 'voterWeight' + docs: [ + "Voter's weight", + 'The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)' + ] + type: 'u64' + }, + { + name: 'voterWeightExpiry' + docs: [ + 'The slot when the voting weight expires', + 'It should be set to None if the weight never expires', + 'If the voter weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight' + ] + type: { + option: 'u64' + } + }, + { + name: 'weightAction' + docs: [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + 'When the action is provided then the governance program asserts the executing action is the same as specified by the addin' + ] + type: { + option: { + defined: 'VoterWeightAction' + } + } + }, + { + name: 'weightActionTarget' + docs: [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + 'For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target', + 'When the target is provided then the governance program asserts the target is the same as specified by the addin' + ] + type: { + option: 'publicKey' + } + }, + { + name: 'reserved' + docs: ['Reserved space for future versions'] + type: { + array: ['u8', 8] + } + } + ] + } + } + ] + types: [ + { + name: 'CollectionItemChangeType' + docs: ['Enum defining collection item change type'] + type: { + kind: 'enum' + variants: [ + { + name: 'Upsert' + }, + { + name: 'Remove' + } + ] + } + }, + { + name: 'VoterWeightAction' + docs: [ + 'VoterWeightAction enum as defined in spl-governance-addin-api', + "It's redefined here for Anchor to export it to IDL" + ] + type: { + kind: 'enum' + variants: [ + { + name: 'CastVote' + }, + { + name: 'CommentProposal' + }, + { + name: 'CreateGovernance' + }, + { + name: 'CreateProposal' + }, + { + name: 'SignOffProposal' + } + ] + } + } + ] + errors: [ + { + code: 6000 + name: 'InvalidRealmAuthority' + msg: 'Invalid Realm Authority' + }, + { + code: 6001 + name: 'InvalidRealmForRegistrar' + msg: 'Invalid Realm for Registrar' + }, + { + code: 6002 + name: 'InvalidVoterWeightRecordRealm' + msg: 'Invalid VoterWeightRecord Realm' + }, + { + code: 6003 + name: 'InvalidVoterWeightRecordMint' + msg: 'Invalid VoterWeightRecord Mint' + }, + { + code: 6004 + name: 'GoverningTokenOwnerMustMatch' + msg: 'Governing TokenOwner must match' + }, + { + code: 6005 + name: 'TokenAccountWrongOwner' + msg: 'All token accounts must be owned by the governing token owner' + }, + { + code: 6006 + name: 'TokenAccountWrongMint' + msg: "All token accounts' mints must be included in the registrar" + }, + { + code: 6007 + name: 'TokenAccountNotLocked' + msg: "All token accounts' mints must be included in the registrar" + } + ] +} + +export const IDL: TokenHaver = { + version: '0.0.1', + name: 'token_haver', + instructions: [ + { + name: 'createRegistrar', + accounts: [ + { + name: 'registrar', + isMut: true, + isSigner: false, + docs: [ + 'The Realm Voter Registrar', + 'There can only be a single registrar per governance Realm and governing mint of the Realm', + ], + }, + { + name: 'governanceProgramId', + isMut: false, + isSigner: false, + docs: [ + 'The program id of the spl-governance program the realm belongs to', + ], + }, + { + name: 'realm', + isMut: false, + isSigner: false, + docs: [ + 'An spl-governance Realm', + '', + 'Realm is validated in the instruction:', + '- Realm is owned by the governance_program_id', + '- governing_token_mint must be the community or council mint', + '- realm_authority is realm.authority', + ], + }, + { + name: 'governingTokenMint', + isMut: false, + isSigner: false, + docs: [ + 'Either the realm community mint or the council mint.', + 'It must match Realm.community_mint or Realm.config.council_mint', + '', + 'Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity', + 'for the voting population and the tokens of that are no longer used', + ], + }, + { + name: 'realmAuthority', + isMut: false, + isSigner: true, + docs: ['realm_authority must sign and match Realm.authority'], + }, + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'mints', + type: { + vec: 'publicKey', + }, + }, + ], + }, + { + name: 'createVoterWeightRecord', + accounts: [ + { + name: 'registrar', + isMut: false, + isSigner: false, + }, + { + name: 'voterWeightRecord', + isMut: true, + isSigner: false, + }, + { + name: 'payer', + isMut: true, + isSigner: true, + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'governingTokenOwner', + type: 'publicKey', + }, + ], + }, + { + name: 'updateVoterWeightRecord', + accounts: [ + { + name: 'registrar', + isMut: false, + isSigner: false, + docs: ['The RealmVoter voting Registrar'], + }, + { + name: 'voterWeightRecord', + isMut: true, + isSigner: false, + }, + ], + args: [], + }, + { + name: 'configureMints', + accounts: [ + { + name: 'registrar', + isMut: true, + isSigner: false, + docs: ['The Registrar for the given realm and governing_token_mint'], + }, + { + name: 'realm', + isMut: false, + isSigner: false, + }, + { + name: 'payer', + isMut: false, + isSigner: true, + }, + { + name: 'realmAuthority', + isMut: false, + isSigner: true, + docs: ['Authority of the Realm must sign and match realm.authority'], + }, + { + name: 'systemProgram', + isMut: false, + isSigner: false, + }, + ], + args: [ + { + name: 'mints', + type: { + vec: 'publicKey', + }, + }, + ], + }, + ], + accounts: [ + { + name: 'maxVoterWeightRecord', + docs: [ + 'MaxVoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide max voting power to the governance program from external addin contracts', + ], + type: { + kind: 'struct', + fields: [ + { + name: 'realm', + docs: ['The Realm the MaxVoterWeightRecord belongs to'], + type: 'publicKey', + }, + { + name: 'governingTokenMint', + docs: [ + 'Governing Token Mint the MaxVoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only', + ], + type: 'publicKey', + }, + { + name: 'maxVoterWeight', + docs: [ + 'Max voter weight', + 'The max voter weight provided by the addin for the given realm and governing_token_mint', + ], + type: 'u64', + }, + { + name: 'maxVoterWeightExpiry', + docs: [ + 'The slot when the max voting weight expires', + 'It should be set to None if the weight never expires', + 'If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight', + ], + type: { + option: 'u64', + }, + }, + { + name: 'reserved', + docs: ['Reserved space for future versions'], + type: { + array: ['u8', 8], + }, + }, + ], + }, + }, + { + name: 'registrar', + docs: [ + 'Registrar which stores spl-governance configurations for the given Realm', + ], + type: { + kind: 'struct', + fields: [ + { + name: 'governanceProgramId', + docs: ['spl-governance program the Realm belongs to'], + type: 'publicKey', + }, + { + name: 'realm', + docs: ['Realm of the Registrar'], + type: 'publicKey', + }, + { + name: 'governingTokenMint', + docs: [ + 'Governing token mint the Registrar is for', + 'It can either be the Community or the Council mint of the Realm', + 'When the plugin is enabled the mint is only used as the identity of the governing power (voting population)', + 'and the actual token of the mint is not used', + ], + type: 'publicKey', + }, + { + name: 'mints', + type: { + vec: 'publicKey', + }, + }, + ], + }, + }, + { + name: 'voterWeightRecord', + docs: [ + 'VoterWeightRecord account as defined in spl-governance-addin-api', + "It's redefined here without account_discriminator for Anchor to treat it as native account", + '', + 'The account is used as an api interface to provide voting power to the governance program from external addin contracts', + ], + type: { + kind: 'struct', + fields: [ + { + name: 'realm', + docs: ['The Realm the VoterWeightRecord belongs to'], + type: 'publicKey', + }, + { + name: 'governingTokenMint', + docs: [ + 'Governing Token Mint the VoterWeightRecord is associated with', + 'Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only', + ], + type: 'publicKey', + }, + { + name: 'governingTokenOwner', + docs: [ + 'The owner of the governing token and voter', + 'This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner', + ], + type: 'publicKey', + }, + { + name: 'voterWeight', + docs: [ + "Voter's weight", + 'The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)', + ], + type: 'u64', + }, + { + name: 'voterWeightExpiry', + docs: [ + 'The slot when the voting weight expires', + 'It should be set to None if the weight never expires', + 'If the voter weight decays with time, for example for time locked based weights, then the expiry must be set', + 'As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction', + 'and the expiry set to the current slot to provide up to date weight', + ], + type: { + option: 'u64', + }, + }, + { + name: 'weightAction', + docs: [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + 'When the action is provided then the governance program asserts the executing action is the same as specified by the addin', + ], + type: { + option: { + defined: 'VoterWeightAction', + }, + }, + }, + { + name: 'weightActionTarget', + docs: [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + 'For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target', + 'When the target is provided then the governance program asserts the target is the same as specified by the addin', + ], + type: { + option: 'publicKey', + }, + }, + { + name: 'reserved', + docs: ['Reserved space for future versions'], + type: { + array: ['u8', 8], + }, + }, + ], + }, + }, + ], + types: [ + { + name: 'CollectionItemChangeType', + docs: ['Enum defining collection item change type'], + type: { + kind: 'enum', + variants: [ + { + name: 'Upsert', + }, + { + name: 'Remove', + }, + ], + }, + }, + { + name: 'VoterWeightAction', + docs: [ + 'VoterWeightAction enum as defined in spl-governance-addin-api', + "It's redefined here for Anchor to export it to IDL", + ], + type: { + kind: 'enum', + variants: [ + { + name: 'CastVote', + }, + { + name: 'CommentProposal', + }, + { + name: 'CreateGovernance', + }, + { + name: 'CreateProposal', + }, + { + name: 'SignOffProposal', + }, + ], + }, + }, + ], + errors: [ + { + code: 6000, + name: 'InvalidRealmAuthority', + msg: 'Invalid Realm Authority', + }, + { + code: 6001, + name: 'InvalidRealmForRegistrar', + msg: 'Invalid Realm for Registrar', + }, + { + code: 6002, + name: 'InvalidVoterWeightRecordRealm', + msg: 'Invalid VoterWeightRecord Realm', + }, + { + code: 6003, + name: 'InvalidVoterWeightRecordMint', + msg: 'Invalid VoterWeightRecord Mint', + }, + { + code: 6004, + name: 'GoverningTokenOwnerMustMatch', + msg: 'Governing TokenOwner must match', + }, + { + code: 6005, + name: 'TokenAccountWrongOwner', + msg: 'All token accounts must be owned by the governing token owner', + }, + { + code: 6006, + name: 'TokenAccountWrongMint', + msg: "All token accounts' mints must be included in the registrar", + }, + { + code: 6007, + name: 'TokenAccountNotLocked', + msg: "All token accounts' mints must be included in the registrar", + }, + ], +} diff --git a/TokenHaverPlugin/readme.md b/TokenHaverPlugin/readme.md new file mode 100644 index 0000000000..bb8a3c0fbc --- /dev/null +++ b/TokenHaverPlugin/readme.md @@ -0,0 +1 @@ +This plugin simply detects if token accounts for a list of mints are present and nonzero. It was used for Voshy's "Greed Experiment" DAO. The contract can be found on the governance-program-library. \ No newline at end of file diff --git a/VoteStakeRegistry/actions/closeDeposit.ts b/VoteStakeRegistry/actions/closeDeposit.ts index 6305ba16d4..77158520a4 100644 --- a/VoteStakeRegistry/actions/closeDeposit.ts +++ b/VoteStakeRegistry/actions/closeDeposit.ts @@ -27,12 +27,12 @@ export const closeDeposit = async ({ const instructions: TransactionInstruction[] = [] const clientProgramId = client!.program.programId - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realmPk, communityMintPk, client!.program.programId ) - const { voter } = await getVoterPDA( + const { voter } = getVoterPDA( registrar, wallet!.publicKey!, clientProgramId diff --git a/VoteStakeRegistry/actions/getClawbackInstruction.ts b/VoteStakeRegistry/actions/getClawbackInstruction.ts index f73ec97f6e..c468363c83 100644 --- a/VoteStakeRegistry/actions/getClawbackInstruction.ts +++ b/VoteStakeRegistry/actions/getClawbackInstruction.ts @@ -29,12 +29,12 @@ export const getClawbackInstruction = async ({ }) => { const clientProgramId = client!.program.programId - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realmPk, realmCommunityMintPk, clientProgramId ) - const { voter } = await getVoterPDA( + const { voter } = getVoterPDA( registrar, voterWalletAddress, clientProgramId diff --git a/VoteStakeRegistry/actions/getGrantInstruction.ts b/VoteStakeRegistry/actions/getGrantInstruction.ts index 0460bbfcb1..ed37997754 100644 --- a/VoteStakeRegistry/actions/getGrantInstruction.ts +++ b/VoteStakeRegistry/actions/getGrantInstruction.ts @@ -46,17 +46,17 @@ export const getGrantInstruction = async ({ const systemProgram = SystemProgram.programId const clientProgramId = client!.program.programId - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realmPk, communityMintPk, clientProgramId ) - const { voter, voterBump } = await getVoterPDA( + const { voter, voterBump } = getVoterPDA( registrar, toPk, clientProgramId ) - const { voterWeightPk, voterWeightBump } = await getVoterWeightPDA( + const { voterWeightPk, voterWeightBump } = getVoterWeightPDA( registrar, toPk, clientProgramId @@ -73,7 +73,7 @@ export const getGrantInstruction = async ({ .grant( voterBump, voterWeightBump, - { [lockupKind]: {} }, + { [lockupKind]: {} } as any, // The cast to any works around an anchor issue with interpreting enums new BN(startTime), lockupPeriod, allowClawback, diff --git a/VoteStakeRegistry/actions/voteRegistryLockDeposit.ts b/VoteStakeRegistry/actions/voteRegistryLockDeposit.ts index 83dc685111..0488cbb34d 100644 --- a/VoteStakeRegistry/actions/voteRegistryLockDeposit.ts +++ b/VoteStakeRegistry/actions/voteRegistryLockDeposit.ts @@ -114,7 +114,8 @@ export const voteRegistryLockDeposit = async ({ if (!amountFromVoteRegistryDeposit.isZero()) { const period = getPeriod(lockUpPeriodInDays, lockupKind) const resetLockup = await client?.program.methods - .resetLockup(depositIdx, { [lockupKind]: {} }, period) + // The cast to any works around an anchor issue with interpreting enums + .resetLockup(depositIdx, { [lockupKind]: {} } as any, period) .accounts({ registrar: registrar, voter: voter, diff --git a/VoteStakeRegistry/components/Account/DepositCard.tsx b/VoteStakeRegistry/components/Account/DepositCard.tsx index 9c77485096..5ccf139dd5 100644 --- a/VoteStakeRegistry/components/Account/DepositCard.tsx +++ b/VoteStakeRegistry/components/Account/DepositCard.tsx @@ -7,6 +7,7 @@ import { voteRegistryWithdraw } from 'VoteStakeRegistry/actions/voteRegistryWith import { DepositWithMintAccount, LockupType, + Registrar, } from 'VoteStakeRegistry/sdk/accounts' import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import tokenPriceService from '@utils/services/tokenPrice' @@ -15,7 +16,6 @@ import { useState } from 'react' import { closeDeposit } from 'VoteStakeRegistry/actions/closeDeposit' import { abbreviateAddress } from '@utils/formatting' import { notify } from '@utils/notifications' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import dayjs from 'dayjs' import { getMinDurationFmt, @@ -31,20 +31,23 @@ import { useRealmQuery } from '@hooks/queries/realm' import { useConnection } from '@solana/wallet-adapter-react' import queryClient from '@hooks/queries/queryClient' import { tokenAccountQueryKeys } from '@hooks/queries/tokenAccount' +import {useVsrClient} from "../../../VoterWeightPlugins/useVsrClient"; const DepositCard = ({ deposit, vsrClient, + registrar }: { deposit: DepositWithMintAccount - vsrClient?: VsrClient | undefined + vsrClient?: VsrClient | undefined, + registrar?: Registrar | undefined }) => { const { getOwnedDeposits } = useDepositStore() const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const client = useVotePluginsClientStore((s) => s.state.vsrClient) + const { vsrClient: client } = useVsrClient() const actualClient = vsrClient || client const wallet = useWalletOnePointOh() const { connection } = useConnection() @@ -146,6 +149,7 @@ const DepositCard = ({ const tokenInfo = tokenPriceService.getTokenInfo( deposit.mint.publicKey.toBase58() ) + return (
@@ -209,7 +213,7 @@ const DepositCard = ({ )}`} value={`${dayjs( deposit!.nextVestingTimestamp!.toNumber() * 1000 - ).format('DD-MM-YYYY HH:mm')}`} + ).format('MM-DD-YYYY HH:mm')}`} /> )} {isRealmCommunityMint && ( @@ -217,7 +221,16 @@ const DepositCard = ({ label="Vote Multiplier" value={(deposit.votingPower.isZero() || deposit.votingPowerBaseline.isZero() - ? 0 + ? + registrar && deposit.amountDepositedNative.gt(new BN(0)) ? + deposit.votingPower.mul(new BN(100)).div( + deposit.amountDepositedNative.mul( + new BN(10).pow( + new BN(registrar!.votingMints[deposit.votingMintConfigIdx].digitShift) + ) + ) + ).toNumber() / 100 + : 0 : deposit.votingPower.mul(new BN(100)).div(deposit.votingPowerBaseline).toNumber() / 100 ).toFixed(2)} /> diff --git a/VoteStakeRegistry/components/Account/LockTokensAccount.tsx b/VoteStakeRegistry/components/Account/LockTokensAccount.tsx index c486b37120..57a96382e4 100644 --- a/VoteStakeRegistry/components/Account/LockTokensAccount.tsx +++ b/VoteStakeRegistry/components/Account/LockTokensAccount.tsx @@ -17,10 +17,9 @@ import { MintInfo } from '@solana/spl-token' import { BN } from '@coral-xyz/anchor' import tokenPriceService from '@utils/services/tokenPrice' import { getDeposits } from 'VoteStakeRegistry/tools/deposits' -import { DepositWithMintAccount } from 'VoteStakeRegistry/sdk/accounts' +import {DepositWithMintAccount, Registrar} from 'VoteStakeRegistry/sdk/accounts' import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import { notify } from '@utils/notifications' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { getTokenOwnerRecordAddress, GoverningTokenRole, @@ -44,6 +43,7 @@ import { } from '@hooks/queries/mintInfo' import { useConnection } from '@solana/wallet-adapter-react' import { useVsrGovpower } from '@hooks/queries/plugins/vsr' +import {useVsrClient} from "../../../VoterWeightPlugins/useVsrClient"; interface DepositBox { mintPk: PublicKey @@ -63,10 +63,9 @@ const LockTokensAccount: React.FC<{ const councilMint = useRealmCouncilMintInfoQuery().data?.result const { realmInfo } = useRealm() const [isLockModalOpen, setIsLockModalOpen] = useState(false) - const client = useVotePluginsClientStore((s) => s.state.vsrClient) - const registrar = useVotePluginsClientStore( - (s) => s.state.voteStakeRegistryRegistrar - ) + const { vsrClient: client, plugin } = useVsrClient(); + const registrar = plugin?.params as Registrar | undefined; + const isZeroMultiplierConfig = !registrar?.votingMints.filter( (x) => !x.maxExtraLockupVoteWeightScaledFactor.isZero() ).length @@ -366,7 +365,7 @@ const LockTokensAccount: React.FC<{ )?.index ) ?.map((x, idx) => ( - + ))} {!isZeroMultiplierConfig && (
@@ -415,7 +414,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..7662e523a0 100644 --- a/VoteStakeRegistry/components/Account/LockTokensModal.tsx +++ b/VoteStakeRegistry/components/Account/LockTokensModal.tsx @@ -17,7 +17,7 @@ import { import { precision } from '@utils/formatting' import { useCallback, useEffect, useMemo, useState } from 'react' import { voteRegistryLockDeposit } from 'VoteStakeRegistry/actions/voteRegistryLockDeposit' -import { DepositWithMintAccount } from 'VoteStakeRegistry/sdk/accounts' +import { DepositWithMintAccount, Registrar } from 'VoteStakeRegistry/sdk/accounts' import { yearsToDays, daysToMonths, @@ -26,6 +26,7 @@ import { getFormattedStringFromDays, secsToDays, yearsToSecs, + daysToSecs, } from '@utils/dateTools' import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import { voteRegistryStartUnlock } from 'VoteStakeRegistry/actions/voteRegistryStartUnlock' @@ -39,7 +40,6 @@ import { vestingPeriods, } from 'VoteStakeRegistry/tools/types' import BigNumber from 'bignumber.js' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { calcMintMultiplier } from 'VoteStakeRegistry/tools/deposits' import ButtonGroup from '@components/ButtonGroup' import InlineNotification from '@components/InlineNotification' @@ -52,6 +52,7 @@ import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' import { useConnection } from '@solana/wallet-adapter-react' import { tokenAccountQueryKeys } from '@hooks/queries/tokenAccount' import queryClient from '@hooks/queries/queryClient' +import {useVsrClient} from "../../../VoterWeightPlugins/useVsrClient"; const YES = 'Yes' const NO = 'No' @@ -71,24 +72,42 @@ const LockTokensModal = ({ const { realmTokenAccount, realmInfo } = useRealm() const { data: tokenOwnerRecordPk } = useAddressQuery_CommunityTokenOwner() - const client = useVotePluginsClientStore((s) => s.state.vsrClient) - const voteStakeRegistryRegistrar = useVotePluginsClientStore( - (s) => s.state.voteStakeRegistryRegistrar - ) + const { vsrClient: client, plugin } = useVsrClient(); + const voteStakeRegistryRegistrar = plugin?.params as Registrar | undefined; + const saturationSecs = realm && voteStakeRegistryRegistrar ? + voteStakeRegistryRegistrar.votingMints.find(x => x.mint.equals( + realm.account.communityMint + ))?.lockupSaturationSecs : + undefined + const { connection } = useConnection() const endpoint = connection.rpcEndpoint const wallet = useWalletOnePointOh() const deposits = useDepositStore((s) => s.state.deposits) const fiveYearsSecs = yearsToSecs(5) - const maxLockupSecs = - (realm && - voteStakeRegistryRegistrar?.votingMints - .find((x) => x.mint.equals(realm.account.communityMint)) - ?.lockupSaturationSecs.toNumber()) || - fiveYearsSecs const lockupPeriods: Period[] = useMemo(() => { return [ + { + defaultValue: 30, + display: '30d', + }, + { + defaultValue: 60, + display: '60d', + }, + { + defaultValue: 90, + display: '90d', + }, + { + defaultValue: 120, + display: '120d', + }, + { + defaultValue: 180, + display: '180d', + }, { defaultValue: yearsToDays(1), display: '1y', @@ -110,7 +129,14 @@ const LockTokensModal = ({ display: '5y', }, { - defaultValue: 1, + defaultValue: depositToUnlock + ? Math.ceil( + secsToDays( + depositToUnlock?.lockup.endTs.toNumber() - + depositToUnlock.lockup.startTs.toNumber() + ) + ) + : 1, display: 'Custom', }, ] @@ -122,8 +148,17 @@ const LockTokensModal = ({ ) <= x.defaultValue || x.display === 'Custom' : true ) - .filter((x) => x.defaultValue <= secsToDays(maxLockupSecs)) - }, [depositToUnlock, maxLockupSecs]) + .filter((x) => { + return x.defaultValue <= secsToDays(fiveYearsSecs) + }) + }, [depositToUnlock, fiveYearsSecs]) + + const lockupLen = lockupPeriods.length + const fixedlockupPeriods = lockupPeriods.slice(0, lockupLen-1) + + const withinPeriod = saturationSecs ? + lockupPeriods.findIndex(p => daysToSecs(p.defaultValue) >= saturationSecs.toNumber()) : + 5 const maxNonCustomDaysLockup = lockupPeriods .map((x) => x.defaultValue) @@ -132,7 +167,7 @@ const LockTokensModal = ({ }) const maxMultiplier = calcMintMultiplier( maxNonCustomDaysLockup * SECS_PER_DAY, - voteStakeRegistryRegistrar, + voteStakeRegistryRegistrar ?? null, realm ) @@ -142,6 +177,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 +205,7 @@ const LockTokensModal = ({ depositToUnlock?.amountInitiallyLockedNative ) : 0 + const maxAmountToLock = depositRecord && mint ? wantToLockMoreThenDeposited @@ -207,7 +244,7 @@ const LockTokensModal = ({ : '' const currentMultiplier = calcMintMultiplier( lockupPeriodDays * SECS_PER_DAY, - voteStakeRegistryRegistrar, + voteStakeRegistryRegistrar ?? null, realm, lockupType.value !== 'constant' ) @@ -428,10 +465,19 @@ const LockTokensModal = ({ lockupPeriods.find((p) => p.display === period) ) } - values={lockupPeriods.map((p) => p.display)} + values={ + withinPeriod === -1 ? + [...fixedlockupPeriods.filter((_, i) => i%2 === 0), lockupPeriods[lockupLen-1]] + .map((p) => p.display) : + [ + ...fixedlockupPeriods.slice(Math.floor(withinPeriod/2), Math.floor(withinPeriod/2)+6), + lockupPeriods[lockupLen-1] + ] + .map((p) => p.display) + } />
- {lockupPeriod.defaultValue === 1 && ( + {lockupPeriod.display === 'Custom' && ( <>
Number of days diff --git a/VoteStakeRegistry/components/TokenBalance/DepositCommunityTokensBtn.tsx b/VoteStakeRegistry/components/TokenBalance/DepositCommunityTokensBtn.tsx index 1712297797..d5faea2244 100644 --- a/VoteStakeRegistry/components/TokenBalance/DepositCommunityTokensBtn.tsx +++ b/VoteStakeRegistry/components/TokenBalance/DepositCommunityTokensBtn.tsx @@ -9,20 +9,19 @@ import { notify } from '@utils/notifications' import { useState } from 'react' import { voteRegistryDepositWithoutLockup } from 'VoteStakeRegistry/actions/voteRegistryDepositWithoutLockup' import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import { useUserCommunityTokenOwnerRecord } from '@hooks/queries/tokenOwnerRecord' import { useConnection } from '@solana/wallet-adapter-react' import queryClient from '@hooks/queries/queryClient' import { tokenAccountQueryKeys } from '@hooks/queries/tokenAccount' +import {useVsrClient} from "../../../VoterWeightPlugins/useVsrClient"; const DepositCommunityTokensBtn = ({ className = '', inAccountDetails }) => { const { getOwnedDeposits } = useDepositStore() const realm = useRealmQuery().data?.result const { realmInfo, realmTokenAccount } = useRealm() - const client = useVotePluginsClientStore((s) => s.state.vsrClient) const [isLoading, setIsLoading] = useState(false) const wallet = useWalletOnePointOh() const connected = !!wallet?.connected @@ -30,6 +29,7 @@ const DepositCommunityTokensBtn = ({ className = '', inAccountDetails }) => { const endpoint = connection.rpcEndpoint const currentTokenOwnerRecord = useUserCommunityTokenOwnerRecord().data ?.result + const {vsrClient} = useVsrClient(); const depositAllTokens = async function () { if (!realm) { @@ -57,14 +57,14 @@ const DepositCommunityTokensBtn = ({ className = '', inAccountDetails }) => { programVersion: realmInfo?.programVersion!, amount: realmTokenAccount!.account.amount, tokenOwnerRecordPk, - client: client, + client: vsrClient, communityMintPk: realm.account.communityMint, }) await getOwnedDeposits({ realmPk: realm!.pubkey, communityMintPk: realm!.account.communityMint, walletPk: wallet!.publicKey!, - client: client!, + client: vsrClient!, connection, }) queryClient.invalidateQueries( 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..05c0be0f3b 100644 --- a/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx +++ b/VoteStakeRegistry/components/TokenBalance/VSRVotingPower.tsx @@ -7,7 +7,7 @@ import { getMintDecimalAmount } from '@tools/sdk/units' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' import BN from 'bn.js' -import { useVsrGovpower, useVsrGovpowerMulti } from '@hooks/queries/plugins/vsr' +import { useVsrGovpowerMulti } from '@hooks/queries/plugins/vsr' import VotingPowerBox from 'VoteStakeRegistry/components/TokenBalance/VotingPowerBox' import { getMintMetadata } from '@components/instructions/programs/splToken' import { useTokenOwnerRecordsDelegatedToUser } from '@hooks/queries/tokenOwnerRecord' @@ -15,20 +15,18 @@ import { useMemo } from 'react' import { useSelectedDelegatorStore } from 'stores/useSelectedDelegatorStore' interface Props { - className?: string + className?: string, + votingPower: BN | undefined, + votingPowerLoading: boolean + isLastPlugin: boolean } -export default function VSRCommunityVotingPower(props: Props) { +export default function VSRCommunityVotingPower({ className, votingPower, votingPowerLoading, isLastPlugin }: Props) { const realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result const deposits = useDepositStore((s) => s.state.deposits) - const { - data: votingPowerResult, - isLoading: votingPowerLoading, - } = useVsrGovpower() - const votingPower = votingPowerResult?.result ?? new BN(0) const votingPowerFromDeposits = useDepositStore( (s) => s.state.votingPowerFromDeposits ) @@ -68,7 +66,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 ) @@ -104,7 +102,7 @@ export default function VSRCommunityVotingPower(props: Props) { return (
@@ -112,11 +110,12 @@ export default function VSRCommunityVotingPower(props: Props) { } return ( -
+
diff --git a/VoteStakeRegistry/components/TokenBalance/VotingPowerBox.tsx b/VoteStakeRegistry/components/TokenBalance/VotingPowerBox.tsx index 2cede87c18..4a4c38a995 100644 --- a/VoteStakeRegistry/components/TokenBalance/VotingPowerBox.tsx +++ b/VoteStakeRegistry/components/TokenBalance/VotingPowerBox.tsx @@ -5,17 +5,20 @@ import { getMintDecimalAmount } from '@tools/sdk/units' import { LightningBoltIcon } from '@heroicons/react/solid' import Tooltip from '@components/Tooltip' import VotingPowerPct from '@components/ProposalVotingPower/VotingPowerPct' +import clsx from "clsx"; const VotingPowerBox = ({ votingPower, mint, votingPowerFromDeposits, + isLastPlugin = true, className = '', style, }: { votingPower: BN mint: MintInfo votingPowerFromDeposits: BN + isLastPlugin?: boolean className?: string style?: any }) => { @@ -38,8 +41,8 @@ const VotingPowerBox = ({ style={style} >
-

Votes

- +

{ isLastPlugin ? 'Votes' : 'Token Power via Locking'}

+ {votingPowerBigNum.toFormat(2)}{' '} {!votingPowerFromDeposits.isZero() && !votingPower.isZero() && ( diff --git a/VoteStakeRegistry/components/TokenBalance/WithdrawCommunityTokensBtn.tsx b/VoteStakeRegistry/components/TokenBalance/WithdrawCommunityTokensBtn.tsx index 6d530505c6..01112eff22 100644 --- a/VoteStakeRegistry/components/TokenBalance/WithdrawCommunityTokensBtn.tsx +++ b/VoteStakeRegistry/components/TokenBalance/WithdrawCommunityTokensBtn.tsx @@ -15,7 +15,6 @@ import { withVoteRegistryWithdraw } from 'VoteStakeRegistry/sdk/withVoteRegistry import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import { getProgramVersionForRealm } from '@models/registry/api' import { notify } from '@utils/notifications' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { useState } from 'react' import Loading from '@components/Loading' import { useMaxVoteRecord } from '@hooks/useMaxVoteRecord' @@ -28,12 +27,13 @@ import { proposalQueryKeys } from '@hooks/queries/proposal' import queryClient from '@hooks/queries/queryClient' import asFindable from '@utils/queries/asFindable' import { tokenAccountQueryKeys } from '@hooks/queries/tokenAccount' +import { useVsrClient } from '../../../VoterWeightPlugins/useVsrClient' const WithDrawCommunityTokens = () => { const { getOwnedDeposits } = useDepositStore() - const client = useVotePluginsClientStore((s) => s.state.vsrClient) const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result const realm = useRealmQuery().data?.result + const { vsrClient } = useVsrClient() const { realmInfo, @@ -91,7 +91,10 @@ const WithDrawCommunityTokens = () => { ) ).result if (!governance) throw new Error('failed to fetch governance') - if (proposal.account.getTimeToVoteEnd(governance.account) > 0) { + if ( + proposal.account.getTimeToVoteEnd(governance.account) > 0 && + governance.account.realm.equals(realm!.pubkey) + ) { setIsLoading(false) // Note: It's technically possible to withdraw the vote here but I think it would be confusing and people would end up unconsciously withdrawing their votes notify({ @@ -147,7 +150,7 @@ const WithDrawCommunityTokens = () => { tokenOwnerRecordPubKey: ownTokenRecord!.pubkey, depositIndex: depositRecord!.index, connection, - client: client, + client: vsrClient, splProgramId: realm!.owner, splProgramVersion: realmInfo!.programVersion, }) @@ -176,7 +179,7 @@ const WithDrawCommunityTokens = () => { realmPk: realm!.pubkey, communityMintPk: realm!.account.communityMint, walletPk: wallet!.publicKey!, - client: client!, + client: vsrClient!, connection, }) queryClient.invalidateQueries( diff --git a/VoteStakeRegistry/components/instructions/Clawback.tsx b/VoteStakeRegistry/components/instructions/Clawback.tsx index 49a13b802f..dbfd23c180 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, @@ -22,7 +22,6 @@ import { NewProposalContext } from 'pages/dao/[symbol]/proposal/new' import GovernedAccountSelect from 'pages/dao/[symbol]/proposal/components/GovernedAccountSelect' import * as yup from 'yup' import { - Deposit, DepositWithMintAccount, getRegistrarPDA, emptyPk, @@ -34,11 +33,11 @@ import { fmtMintAmount } from '@tools/sdk/units' import tokenPriceService from '@utils/services/tokenPrice' import { getClawbackInstruction } from 'VoteStakeRegistry/actions/getClawbackInstruction' import { abbreviateAddress } from '@utils/formatting' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { AssetAccount } from '@utils/uiTypes/assets' import { useRealmQuery } from '@hooks/queries/realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import Input from '@components/inputs/Input' +import {useVsrClient} from "VoterWeightPlugins/useVsrClient"; const Clawback = ({ index, @@ -47,7 +46,7 @@ const Clawback = ({ index: number governance: ProgramAccount | null }) => { - const client = useVotePluginsClientStore((s) => s.state.vsrClient) + const { vsrClient } = useVsrClient(); const connection = useLegacyConnectionContext() const realm = useRealmQuery().data?.result @@ -111,7 +110,7 @@ const Clawback = ({ voterDepositIndex: form.deposit.index, grantMintPk: form.deposit.mint.publicKey, realmCommunityMintPk: realm!.account.communityMint, - client, + client: vsrClient, }) serializedInstruction = serializeInstructionToBase64(clawbackIx!) } @@ -124,7 +123,7 @@ const Clawback = ({ customHoldUpTime: form.holdupTime, } return obj - }, [client, form, realmAuthorityGov, realm, schema]) + }, [vsrClient, form, realmAuthorityGov, realm, schema]) useEffect(() => { handleSetInstructions( @@ -142,12 +141,12 @@ const Clawback = ({ }, [form.governedTokenAccount, governancesArray, realm?.account.authority]) useEffect(() => { const getVoters = async () => { - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - client!.program.programId + const { registrar } = getRegistrarPDA( + realm!.pubkey, + realm!.account.communityMint, + vsrClient!.program.programId ) - const resp = await client?.program.account.voter.all([ + const resp = await vsrClient?.program.account.voter.all([ { memcmp: { offset: 40, @@ -159,26 +158,27 @@ const Clawback = ({ resp ?.filter( (x) => - (x.account.deposits as Deposit[]).filter( + (x.account.deposits).filter( (depo) => depo.allowClawback ).length ) - .map((x) => x.account as Voter) || [] + // The cast works around an anchor issue with interpreting enums + .map((x) => x.account as unknown as Voter) || [] setVoters([...voters]) } - if (client) { + if (vsrClient) { getVoters() } - }, [client, realm]) + }, [vsrClient, realm]) useEffect(() => { const getOwnedDepositsInfo = async () => { - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - client!.program.programId + const { registrar } = getRegistrarPDA( + realm!.pubkey, + realm!.account.communityMint, + vsrClient!.program.programId ) - const existingRegistrar = await tryGetRegistrar(registrar, client!) + const existingRegistrar = await tryGetRegistrar(registrar, vsrClient!) const mintCfgs = existingRegistrar?.votingMints const mints = {} if (mintCfgs) { @@ -211,7 +211,7 @@ const Clawback = ({ deposit: null, governedTokenAccount: undefined, })) - }, [client, connection, form.voter, realm]) + }, [vsrClient, connection, form.voter, realm]) useEffect(() => { setForm((prevForm) => ({ ...prevForm, governedTokenAccount: undefined })) @@ -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']} + /> @@ -232,13 +253,13 @@ const UpgradeProgram = ({ program }: { program: AssetAccount }) => { }) } /> - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - /> + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/ButtonGroup.tsx b/components/ButtonGroup.tsx index 9fa8aa559e..d9a2d4e746 100644 --- a/components/ButtonGroup.tsx +++ b/components/ButtonGroup.tsx @@ -44,7 +44,7 @@ const ButtonGroup: FunctionComponent = ({ key={`${v}${i}`} onClick={() => onChange(v)} style={{ - width: `${100 / values.length}%`, + width: `${98 / values.length}%`, }} > {names ? (unit ? names[i] + unit : names[i]) : unit ? v + unit : v} diff --git a/components/DepositTokensButton.tsx b/components/DepositTokensButton.tsx index cc9c977995..e84d34957e 100644 --- a/components/DepositTokensButton.tsx +++ b/components/DepositTokensButton.tsx @@ -2,7 +2,7 @@ import { BigNumber } from 'bignumber.js' import Button, { ButtonProps, SecondaryButton } from '@components/Button' import BN from 'bn.js' import useUserGovTokenAccountQuery from '@hooks/useUserGovTokenAccount' -import { useDepositCallback } from './GovernancePower/Vanilla/useDepositCallback' +import { useDepositCallback } from './GovernancePower/Power/Vanilla/useDepositCallback' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import Modal from './Modal' import { useState, useEffect } from 'react' @@ -94,7 +94,7 @@ export const DepositTokensButton = ({ await deposit(nativeAmount) setOpenModal(false) }} - disabled={humanReadableMax !== undefined && (parseInt(amount) > humanReadableMax || parseInt(amount)<= 0)} + disabled={humanReadableMax !== undefined && (parseFloat(amount) > humanReadableMax || parseFloat(amount)<= 0)} > Confirm diff --git a/components/Dialect/index.tsx b/components/Dialect/index.tsx new file mode 100644 index 0000000000..b1f0bc4e8f --- /dev/null +++ b/components/Dialect/index.tsx @@ -0,0 +1,17 @@ +'use client' + +import { web3 } from '@coral-xyz/anchor' +import { DialectSolanaSdk } from '@dialectlabs/react-sdk-blockchain-solana' +import { NotificationsButton } from '@dialectlabs/react-ui' + +const REALMS_PUBLIC_KEY = new web3.PublicKey( + 'BUxZD6aECR5B5MopyvvYqJxwSKDBhx2jSSo1U32en6mj' +) + +export default function DialectNotifications() { + return ( + + + + ) +} diff --git a/components/DialectNotificationsModal/index.tsx b/components/DialectNotificationsModal/index.tsx deleted file mode 100644 index d972c59755..0000000000 --- a/components/DialectNotificationsModal/index.tsx +++ /dev/null @@ -1,152 +0,0 @@ -import { - ConfigProps, - defaultVariables, - DialectThemeProvider, - DialectUiManagementProvider, - IncomingThemeVariables, - Notifications, -} from '@dialectlabs/react-ui' -import { - DialectSolanaSdk, - DialectSolanaWalletAdapter, - SolanaConfigProps, -} from '@dialectlabs/react-sdk-blockchain-solana' -import { SignerWalletAdapter } from '@solana/wallet-adapter-base' -import { useTheme } from 'next-themes' -import { useEffect, useMemo, useState } from 'react' -import { web3 } from '@coral-xyz/anchor' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' - -const REALMS_PUBLIC_KEY = new web3.PublicKey( - 'BUxZD6aECR5B5MopyvvYqJxwSKDBhx2jSSo1U32en6mj' -) - -const themeVariables: IncomingThemeVariables = { - dark: { - bellButton: - '!bg-bkg-2 !shadow-none text-fgd-1 h-10 rounded-full w-10 hover:bg-bkg-3', - iconButton: `${defaultVariables.dark.iconButton} hover:opacity-100`, - buttonLoading: `${defaultVariables.dark.buttonLoading} rounded-full min-h-[40px]`, - adornmentButton: `${defaultVariables.dark.adornmentButton} !text-bkg-1 bg-primary-light border-primary-light font-bold rounded-full hover:bg-fgd-1 hover:opacity-100`, - colors: { - ...defaultVariables.dark.colors, - bg: 'bg-bkg-1', - toggleBackgroundActive: 'bg-primary-light', - }, - textStyles: { - input: 'text-primary-1 bg-bkg-1 border-none hover:border-none', - }, - outlinedInput: `${defaultVariables.dark.outlinedInput} focus-within:border-primary-light`, - disabledButton: `${defaultVariables.dark.disabledButton} border-primary-light font-bold rounded-full border-fgd-3 text-fgd-3 cursor-not-allowed`, - modal: `${defaultVariables.dark.modal} bg-bkg-1 sm:border sm:border-fgd-4 shadow-md sm:rounded-md`, - modalWrapper: `${defaultVariables.dark.modalWrapper} sm:top-14 rounded-md`, - secondaryDangerButton: `${defaultVariables.dark.secondaryDangerButton} rounded-full`, - }, - light: { - bellButton: - '!bg-bkg-2 !shadow-none text-fgd-1 h-10 rounded-full w-10 hover:bg-bkg-3', - iconButton: `${defaultVariables.light.iconButton} hover:opacity-100`, - buttonLoading: `${defaultVariables.dark.buttonLoading} rounded-full min-h-[40px]`, - adornmentButton: `${defaultVariables.light.adornmentButton} bg-primary-light border-primary-light font-bold rounded-full hover:bg-fgd-1 hover:opacity-100`, - colors: { - ...defaultVariables.light.colors, - toggleBackgroundActive: 'bg-primary-light', - }, - textStyles: { - input: `${defaultVariables.light.textStyles.input} text-fgd-1 placeholder:text-fgd-3`, - body: `${defaultVariables.light.textStyles.body} text-fgd-1`, - }, - outlinedInput: `${defaultVariables.light.outlinedInput} focus-within:border-primary-light`, - modal: `${defaultVariables.light.modal} sm:border sm:rounded-md sm:border-fgd-4 sm:shadow-md`, - modalWrapper: `${defaultVariables.dark.modalWrapper} sm:top-14`, - secondaryDangerButton: `${defaultVariables.light.secondaryDangerButton} rounded-full`, - }, -} - -const solanaWalletToDialectWallet = ( - wallet?: SignerWalletAdapter -): DialectSolanaWalletAdapter | null => { - if (!wallet || !wallet.connected || wallet.connecting || !wallet.publicKey) { - return null - } - - return { - publicKey: wallet.publicKey!, - // @ts-ignore - signMessage: wallet?.signMessage - ? // @ts-ignore - (msg) => wallet.signMessage(msg) - : undefined, - - signTransaction: wallet.signTransaction as any, - signAllTransactions: wallet.signAllTransactions as any, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - diffieHellman: wallet.wallet?.adapter?._wallet?.diffieHellman - ? async (pubKey: any) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return wallet.wallet?.adapter?._wallet?.diffieHellman(pubKey) - } - : undefined, - } -} - -interface DialectNotificationsModalProps { - onBackClick?: () => void - onModalClose: () => void -} - -export default function DialectNotificationsModal( - props: DialectNotificationsModalProps -) { - const { theme } = useTheme() - const wallet = useWalletOnePointOh() - - const [ - dialectSolanaWalletAdapter, - setDialectSolanaWalletAdapter, - ] = useState(() => - solanaWalletToDialectWallet(wallet) - ) - - useEffect(() => { - setDialectSolanaWalletAdapter(solanaWalletToDialectWallet(wallet)) - }, [wallet]) - - const dialectConfig = useMemo( - (): ConfigProps => ({ - environment: 'production', - dialectCloud: { - tokenStore: 'local-storage', - }, - }), - [] - ) - - const solanaConfig: SolanaConfigProps = useMemo( - () => ({ - wallet: dialectSolanaWalletAdapter, - }), - [dialectSolanaWalletAdapter] - ) - - return ( - - - - - - - - ) -} diff --git a/components/Footer.tsx b/components/Footer.tsx index 892a9166ff..26ea1dba66 100644 --- a/components/Footer.tsx +++ b/components/Footer.tsx @@ -67,7 +67,7 @@ const Footer = () => {
- © 2023 Solana Technology Services LLC + © 2024 Realms Today Ltd
| diff --git a/components/Gateway/GatewayButton.tsx b/components/Gateway/GatewayButton.tsx index b0b91b86c5..6031376932 100644 --- a/components/Gateway/GatewayButton.tsx +++ b/components/Gateway/GatewayButton.tsx @@ -1,29 +1,8 @@ -import { IdentityButton, useGateway } from '@civic/solana-gateway-react' -import { FC, useEffect } from 'react' -import useGatewayPluginStore from '../../GatewayPlugin/store/gatewayPluginStore' -import useVotePluginsClientStore from '../../stores/useVotePluginsClientStore' +import { IdentityButton } from '@civic/solana-gateway-react' +import { FC } from 'react' export const GatewayButton: FC = () => { - const { setGatewayToken, state } = useGatewayPluginStore() - const currentClient = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - - const { gatewayToken } = useGateway() - - // As soon as the Civic GatewayProvider finds a gateway token - // add it to the state, so that the voting plugin can use it - useEffect(() => { - if ( - gatewayToken && - state.gatewayToken?.toBase58() !== gatewayToken.publicKey.toBase58() - ) { - setGatewayToken(gatewayToken.publicKey, currentClient) - } - // 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 - }, [gatewayToken]) - return ( - + ) } diff --git a/components/Gateway/GatewayCard.tsx b/components/Gateway/GatewayCard.tsx index faa256cde7..e5d37d1997 100644 --- a/components/Gateway/GatewayCard.tsx +++ b/components/Gateway/GatewayCard.tsx @@ -1,162 +1,134 @@ -/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ -import Button from '@components/Button' -import Loading from '@components/Loading' -import useRealm from '@hooks/useRealm' -import { GatewayClient } from '@solana/governance-program-library' -import { - getTokenOwnerRecordAddress, - SYSTEM_PROGRAM_ID, - withCreateTokenOwnerRecord, -} from '@solana/spl-governance' -import { Transaction, TransactionInstruction } from '@solana/web3.js' -import { sendTransaction } from '@utils/send' -import { useState, useEffect, useMemo } from 'react' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import useGatewayPluginStore from '../../GatewayPlugin/store/gatewayPluginStore' import { GatewayButton } from '@components/Gateway/GatewayButton' -import { getRegistrarPDA, getVoterWeightRecord } from '@utils/plugin/accounts' -import { useRecords } from '@components/Gateway/useRecords' +import Modal from '@components/Modal' +import { InformationCircleIcon } from '@heroicons/react/solid' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { useRealmQuery } from '@hooks/queries/realm' +import { useState } from 'react' +import { useGatewayVoterWeightPlugin } from '../../VoterWeightPlugins' import { - useRealmCommunityMintInfoQuery, - useRealmCouncilMintInfoQuery, -} from '@hooks/queries/mintInfo' -import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' + useRealmVoterWeightPlugins, + useRealmVoterWeights, +} from '@hooks/useRealmVoterWeightPlugins' +import { BN } from '@coral-xyz/anchor' +import { GatewayStatus, useGateway } from '@civic/solana-gateway-react' +import useUserGovTokenAccountQuery from '@hooks/useUserGovTokenAccount' +import BigNumber from 'bignumber.js' +import PluginVotingPower from '@components/ProposalVotingPower/PluginVotingPower' + +interface Props { + role: 'community' | 'council' +} -// TODO lots of overlap with NftBalanceCard here - we need to separate the logic for creating the Token Owner Record -// from the rest of this logic -const GatewayCard = () => { +const GatewayCard = ({ role }: Props) => { + const [showGatewayModal, setShowGatewayModal] = useState(false) const wallet = useWalletOnePointOh() const connected = !!wallet?.connected - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - const gatekeeperNetwork = useGatewayPluginStore( - (s) => s.state.gatekeeperNetwork - ) - const isLoading = useGatewayPluginStore((s) => s.state.isLoadingGatewayToken) - const connection = useLegacyConnectionContext() - const [, setTokenOwneRecordPk] = useState('') //@asktree: ????????????????????????????????????????? - const realm = useRealmQuery().data?.result - const mint = useRealmCommunityMintInfoQuery().data?.result - const councilMint = useRealmCouncilMintInfoQuery().data?.result - - const { realmInfo } = useRealm() - const records = useRecords() - - // show the join button if any of the records required by the chain of plugins are not yet created - const showJoinButton = useMemo(() => { - return ( - (!records.tokenOwnerRecord.accountExists && - records.tokenOwnerRecord.accountRequired) || - (!records.voteWeightRecord.accountExists && - records.voteWeightRecord.accountRequired) - ) - // 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 - }, [records, client]) - - const handleRegister = async () => { - const instructions: TransactionInstruction[] = [] - const { voterWeightPk } = await getVoterWeightRecord( - realm!.pubkey, - realm!.account.communityMint, - wallet!.publicKey!, - client.client!.program.programId - ) - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - client.client!.program.programId - ) - // If a vote weight record is needed (i.e. the realm has a voter weight plugin) - // but doesn't exist yet, add the instruction to create it to the list - if ( - !records.voteWeightRecord.accountExists && - records.voteWeightRecord.accountRequired - ) { - const createVoterWeightRecordIx = await (client.client as GatewayClient).program.methods - .createVoterWeightRecord(wallet!.publicKey!) - .accounts({ - voterWeightRecord: voterWeightPk, - registrar, - payer: wallet!.publicKey!, - systemProgram: SYSTEM_PROGRAM_ID, - }) - .instruction() + const { gatewayStatus } = useGateway() - instructions.push(createVoterWeightRecordIx) - } + const { + gatekeeperNetwork, + isReady, + isEnabled, + } = useGatewayVoterWeightPlugin() + const { communityWeight, councilWeight } = useRealmVoterWeights() - // If a token owner record doesn't exist yet, - // add the instruction to create it to the list - if ( - !records.tokenOwnerRecord.accountExists && - records.tokenOwnerRecord.accountRequired - ) { - await withCreateTokenOwnerRecord( - instructions, - realm!.owner!, - realmInfo?.programVersion!, - realm!.pubkey, - wallet!.publicKey!, - realm!.account.communityMint, - wallet!.publicKey! - ) - } - const transaction = new Transaction() - transaction.add(...instructions) + const { plugins } = useRealmVoterWeightPlugins(role) - await sendTransaction({ - transaction: transaction, - wallet: wallet!, - connection: connection.current, - signers: [], - sendingMessage: `Registering`, - successMessage: `Registered`, - }) - } + const userAta = useUserGovTokenAccountQuery('community').data?.result + const depositAmount = userAta?.amount + ? new BigNumber(userAta.amount.toString()) + : new BigNumber(0) - useEffect(() => { - const getTokenOwnerRecord = async () => { - const defaultMint = !mint?.supply.isZero() - ? realm!.account.communityMint - : !councilMint?.supply.isZero() - ? realm!.account.config.councilMint - : undefined - const tokenOwnerRecordAddress = await getTokenOwnerRecordAddress( - realm!.owner, - realm!.pubkey, - defaultMint!, - wallet!.publicKey! - ) - setTokenOwneRecordPk(tokenOwnerRecordAddress.toBase58()) - } - if (realm && wallet?.connected) { - getTokenOwnerRecord() - } - // 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 - }, [realm?.pubkey.toBase58(), wallet?.connected]) + const hasTokens = + depositAmount.isGreaterThan(0) || + councilWeight?.value?.gt(new BN(0)) || + communityWeight?.value?.gt(new BN(0)) - return ( -
-
- {!connected && ( + if (!connected) { + return ( +
+
Please connect your wallet
+
+
+ ) + } + if (hasTokens) { + return ( +
+
+
+

Verify to vote

+ + setShowGatewayModal(true)} + /> + +
+ {isEnabled && + isReady && + wallet && + wallet.publicKey && + gatekeeperNetwork && + hasTokens && } +
+

+ {gatewayStatus === GatewayStatus.ACTIVE + ? 'You are approved to vote' + : 'Verify your personhood with Civic Pass to vote.'} +

+ { + // check if the last plugin is gateway to show the voting power + plugins?.voterWeight[plugins.voterWeight.length - 1].name === + 'gateway' && + } + {showGatewayModal && ( + setShowGatewayModal(false)} + isOpen={showGatewayModal} + > +
+

Verify to vote

+
+
+ 1 +
+
+

Connect Governance Wallet

+
+ Connect the wallet with your governance token(s). + Consolidate multiple tokens into one wallet before voting. +
+
+
+
+
+ 2 +
+
+

Verify Identity

+
+ Verify your identity using Civic Pass to prevent voting + abuse, such as Sybil attacks. +
+
+
+
+
+ 3 +
+
+

Vote

+
Vote with confidence in a fair system.
+
+
+
+
)} - {isLoading && } - {!isLoading && - connected && - wallet && - wallet.publicKey && - gatekeeperNetwork && }
- {connected && showJoinButton && ( - - )} -
- ) + ) + } + return null } export default GatewayCard diff --git a/components/Gateway/GatewayProvider.tsx b/components/Gateway/GatewayProvider.tsx index c7f9017ad8..39b0e3a957 100644 --- a/components/Gateway/GatewayProvider.tsx +++ b/components/Gateway/GatewayProvider.tsx @@ -1,9 +1,9 @@ import { FC } from 'react' import { GatewayProvider as InternalGatewayProvider } from '@civic/solana-gateway-react' -import useVotePluginsClientStore from '../../stores/useVotePluginsClientStore' -import useGatewayPluginStore from '../../GatewayPlugin/store/gatewayPluginStore' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { useGatewayVoterWeightPlugin } from 'VoterWeightPlugins' +import { useConnection } from '@solana/wallet-adapter-react' +import {getNetworkFromEndpoint} from "@utils/connection"; /** * Wrapper for the Civic Gateway Provider react component. This component is responsible for @@ -14,22 +14,19 @@ import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' */ export const GatewayProvider: FC = ({ children }) => { const wallet = useWalletOnePointOh() - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - const gatekeeperNetwork = useGatewayPluginStore( - (s) => s.state.gatekeeperNetwork - ) - const connection = useLegacyConnectionContext() - const cluster = - connection.cluster === 'mainnet' ? 'mainnet-beta' : connection.cluster + const { gatekeeperNetwork, isReady } = useGatewayVoterWeightPlugin() + const { connection } = useConnection() + const network = getNetworkFromEndpoint(connection.rpcEndpoint); + const cluster = network === 'mainnet' + ? 'mainnet-beta' + : network - if (!wallet || !wallet.publicKey || !client || !gatekeeperNetwork) + if (!wallet || !wallet.publicKey || !isReady || !gatekeeperNetwork) return <>{children} return ( { - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - const wallet = useWalletOnePointOh() - const connection = useLegacyConnectionContext() - const realm = useRealmQuery().data?.result - const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result - - // TODO replace these with useDispatch - const [tokenOwnerRecord, setTokenOwnerRecord] = useState({ - publicKey: null, - accountExists: false, - accountRequired: true, - }) - const [voteWeightRecord, setVoteWeightRecord] = useState({ - publicKey: null, - accountExists: false, - accountRequired: true, - }) - - const getVoteWeightRecordPK = useCallback( - async (client: Client) => { - if (realm && wallet && wallet.publicKey) { - const { voterWeightPk } = await getPluginVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - wallet.publicKey, - client.program.programId - ) - return voterWeightPk - } else { - return undefined - } - }, - // 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 - [realm, wallet, client] - ) - - const accountExists = useCallback( - async (publicKey: PublicKey) => { - const account = await connection.current.getAccountInfo(publicKey) - return !!account - }, - [connection] - ) - - useEffect(() => { - const func = async () => { - // tokenOwnerRecord - if (ownTokenRecord) { - setTokenOwnerRecord({ - publicKey: ownTokenRecord.pubkey, - accountExists: true, - accountRequired: true, - }) - } else { - console.log('useRecords: token owner record not found') - } - - // voteWeightRecord - if (client && client.client) { - const voteWeightRecordPK = await getVoteWeightRecordPK(client.client) - if (voteWeightRecordPK) { - setVoteWeightRecord({ - publicKey: voteWeightRecordPK, - accountExists: await accountExists(voteWeightRecordPK), - accountRequired: true, - }) - } else { - console.log('useRecords: voter weight record not found') - } - } else { - console.log('useRecords: voter weight record not needed') - setVoteWeightRecord({ - publicKey: null, - accountExists: false, - accountRequired: true, - }) - } - } - func() - // 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 - }, [client, wallet]) - - return { - tokenOwnerRecord, - voteWeightRecord, - } -} diff --git a/components/GovernancePower/GovernancePowerCard.tsx b/components/GovernancePower/GovernancePowerCard.tsx index 1465eceebf..ae2686428f 100644 --- a/components/GovernancePower/GovernancePowerCard.tsx +++ b/components/GovernancePower/GovernancePowerCard.tsx @@ -1,5 +1,4 @@ import { ChevronRightIcon } from '@heroicons/react/solid' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import useQueryContext from '@hooks/useQueryContext' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' @@ -7,6 +6,7 @@ import { GoverningTokenType } from '@solana/spl-governance' import Link from 'next/link' import { useRouter } from 'next/router' import GovernancePowerForRole from './GovernancePowerForRole' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const GovernancePowerTitle = () => { const { symbol } = useRouter().query @@ -47,10 +47,9 @@ const VanillaDeposit = ({ role }: { role: 'community' | 'council' }) => { const GovernancePowerCard = () => { const connected = useWalletOnePointOh()?.connected ?? false - const communityPower = useGovernancePowerAsync('community') - const councilPower = useGovernancePowerAsync('council') - - const bothLoading = communityPower.loading && councilPower.loading + const { isReady: communityIsReady } = useRealmVoterWeightPlugins('community') + const { isReady: councilIsReady } = useRealmVoterWeightPlugins('council') + const isReady = communityIsReady && councilIsReady const realmConfig = useRealmConfigQuery().data?.result @@ -61,7 +60,7 @@ const GovernancePowerCard = () => {
Connect your wallet to see governance power
- ) : bothLoading ? ( + ) : !isReady ? ( <>
diff --git a/components/GovernancePower/GovernancePowerForRole.tsx b/components/GovernancePower/GovernancePowerForRole.tsx index 6b627cbc9f..ebfdbafa8c 100644 --- a/components/GovernancePower/GovernancePowerForRole.tsx +++ b/components/GovernancePower/GovernancePowerForRole.tsx @@ -3,15 +3,13 @@ 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 VanillaVotingPower from './Power/Vanilla/VanillaVotingPower' +import { Deposit } from './Power/Vanilla/Deposit' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { PluginName } from '@constants/plugins' +import { VotingPowerCards } from '@components/GovernancePower/Power/VotingPowerCards' + +type VotingPowerDisplayType = PluginName | 'composite' export default function GovernancePowerForRole({ role, @@ -23,59 +21,30 @@ 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 - //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() - + const { plugins } = useRealmVoterWeightPlugins(role) const wallet = useWalletOnePointOh() const connected = !!wallet?.connected - const { result: kind } = useAsync(async () => { + const { result: kind } = useAsync< + VotingPowerDisplayType | undefined + >(async () => { if (realmPk === undefined) return undefined - return didWithdrawFromVanillaSetup - ? determineVotingPowerType(connection, realmPk, role) - : 'vanilla' - }, [connection, realmPk, role, didWithdrawFromVanillaSetup]) + // if there are multiple plugins, show the generic plugin voting power + if ((plugins?.voterWeight.length ?? 0) > 1) return 'composite' + return determineVotingPowerType(connection, realmPk, role) + }, [connection, plugins?.voterWeight.length, realmPk, role]) if (connected && kind === undefined && !props.hideIfZero) { return (
) } - return ( <> {role === 'community' ? ( - kind === 'vanilla' ? ( -
- - - {isVsr && !didWithdrawFromVanillaSetup && ( - - - Please withdraw your tokens and deposit again to get governance - power - - )} -
- ) : kind === 'VSR' ? ( - - ) : kind === 'NFT' ? ( - - ) : kind === 'HeliumVSR' ? ( - - ) : null - ) : kind === 'vanilla' ? ( + + ) : // council + kind === 'vanilla' ? (
diff --git a/components/GovernancePower/Power/VSRCard.tsx b/components/GovernancePower/Power/VSRCard.tsx new file mode 100644 index 0000000000..c9cbbd09b9 --- /dev/null +++ b/components/GovernancePower/Power/VSRCard.tsx @@ -0,0 +1,40 @@ +import {FC} from "react"; +import {useUserCommunityTokenOwnerRecord} from "@hooks/queries/tokenOwnerRecord"; +import LockedCommunityVotingPower from "@components/ProposalVotingPower/LockedCommunityVotingPower"; +import VanillaVotingPower from "@components/GovernancePower/Power/Vanilla/VanillaVotingPower"; +import {ExclamationIcon} from "@heroicons/react/solid"; +import VanillaWithdrawTokensButton from "@components/TokenBalance/VanillaWithdrawTokensButton"; +import {VotingCardProps} from "@components/GovernancePower/Power/VotingPowerCards"; + +export const VSRCard: FC = ({role, ...props}) => { + const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result + + //VSR if dao transited to use plugin and some users have still deposited tokens they should withdraw before + //depositing to plugin + const didWithdrawFromVanillaSetup = + !ownTokenRecord || + ownTokenRecord.account.governingTokenDepositAmount.isZero() + + return ( + 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 + +
+
+ +
+
+ + ) + ) +} \ No newline at end of file diff --git a/components/GovernancePower/Vanilla/Deposit.tsx b/components/GovernancePower/Power/Vanilla/Deposit.tsx similarity index 94% rename from components/GovernancePower/Vanilla/Deposit.tsx rename to components/GovernancePower/Power/Vanilla/Deposit.tsx index f51433d19c..36c1dcec3f 100644 --- a/components/GovernancePower/Vanilla/Deposit.tsx +++ b/components/GovernancePower/Power/Vanilla/Deposit.tsx @@ -29,7 +29,7 @@ export const Deposit = ({ role }: { role: 'community' | 'council' }) => { {mintInfo ? depositAmount.shiftedBy(-mintInfo.decimals).toFormat() : depositAmount.toFormat()}{' '} - more {tokenName} votes in your wallet. Do you want to deposit them to + more {tokenName} tokens in your wallet. Do you want to deposit them to increase your voting power in this Dao?
diff --git a/components/GovernancePower/Power/Vanilla/VanillaCard.tsx b/components/GovernancePower/Power/Vanilla/VanillaCard.tsx new file mode 100644 index 0000000000..79f896ac80 --- /dev/null +++ b/components/GovernancePower/Power/Vanilla/VanillaCard.tsx @@ -0,0 +1,11 @@ +import VanillaVotingPower from "@components/GovernancePower/Power/Vanilla/VanillaVotingPower"; +import {Deposit} from "@components/GovernancePower/Power/Vanilla/Deposit"; +import { VotingCardProps } from "../VotingPowerCards"; +import {FC} from "react"; + +export const VanillaCard:FC = (props) => ( +
+ + +
+) \ No newline at end of file diff --git a/components/GovernancePower/Vanilla/VanillaVotingPower.tsx b/components/GovernancePower/Power/Vanilla/VanillaVotingPower.tsx similarity index 84% rename from components/GovernancePower/Vanilla/VanillaVotingPower.tsx rename to components/GovernancePower/Power/Vanilla/VanillaVotingPower.tsx index 938df7198b..6a0b8a8a34 100644 --- a/components/GovernancePower/Vanilla/VanillaVotingPower.tsx +++ b/components/GovernancePower/Power/Vanilla/VanillaVotingPower.tsx @@ -5,7 +5,7 @@ import { useTokenOwnerRecordsDelegatedToUser } from '@hooks/queries/tokenOwnerRe import { useRealmQuery } from '@hooks/queries/realm' import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' import { useConnection } from '@solana/wallet-adapter-react' -import { getVanillaGovpower } from '@hooks/queries/governancePower' +import { getVanillaGovpower, useVanillaGovpower } from '@hooks/queries/governancePower' import { useAddressQuery_CommunityTokenOwner, useAddressQuery_CouncilTokenOwner, @@ -19,11 +19,14 @@ import { abbreviateAddress } from '@utils/formatting' import clsx from 'clsx' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import { GoverningTokenType } from '@solana/spl-governance' +import {ExclamationIcon, QuestionMarkCircleIcon} from "@heroicons/react/outline"; +import Tooltip from "@components/Tooltip"; interface Props { className?: string role: 'community' | 'council' hideIfZero?: boolean + unrecognizedPlugin?: boolean children?: React.ReactNode } @@ -31,6 +34,7 @@ export default function VanillaVotingPower({ role, hideIfZero, children, + unrecognizedPlugin = false, ...props }: Props) { const realm = useRealmQuery().data?.result @@ -49,17 +53,14 @@ export default function VanillaVotingPower({ const mintInfo = useMintInfoByPubkeyQuery(relevantMint).data?.result - const { result: personalAmount } = useAsync( - async () => relevantTOR && getVanillaGovpower(connection, relevantTOR), - [connection, relevantTOR] - ) + const personalAmount = useVanillaGovpower(relevantTOR) // If the user is using a delegator, we want to show that and not count the other delegators const selectedDelegator = useSelectedDelegatorStore((s) => role === 'community' ? s.communityDelegator : s.councilDelegator ) - const torsDelegatedToUser = useTokenOwnerRecordsDelegatedToUser() + const { data: torsDelegatedToUser } = useTokenOwnerRecordsDelegatedToUser() const { result: delegatorsAmount } = useAsync( async () => @@ -121,10 +122,17 @@ export default function VanillaVotingPower({ disabled && 'hidden' )} > + {unrecognizedPlugin &&
+ + Unrecognized plugin + + + +
}
{tokenName} - {role === 'council' ? ' Council' : ''} Votes + {role === 'council' ? ' Council' : ''} votes
diff --git a/components/GovernancePower/Vanilla/useDepositCallback.tsx b/components/GovernancePower/Power/Vanilla/useDepositCallback.tsx similarity index 70% rename from components/GovernancePower/Vanilla/useDepositCallback.tsx rename to components/GovernancePower/Power/Vanilla/useDepositCallback.tsx index 08b47f7bde..94a69be61f 100644 --- a/components/GovernancePower/Vanilla/useDepositCallback.tsx +++ b/components/GovernancePower/Power/Vanilla/useDepositCallback.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { fetchRealmByPubkey } from '@hooks/queries/realm' import { useConnection } from '@solana/wallet-adapter-react' -import { Keypair, Transaction, TransactionInstruction } from '@solana/web3.js' +import { Keypair, TransactionInstruction } from '@solana/web3.js' import { approveTokenTransfer } from '@utils/tokens' import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' import { withDepositGoverningTokens } from '@solana/spl-governance' @@ -12,12 +12,15 @@ import { TOKEN_PROGRAM_ID, } from '@solana/spl-token' import BN from 'bn.js' -import { sendTransaction } from '@utils/send' import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery' +import queryClient from "@hooks/queries/queryClient"; +import {useJoinRealm} from "@hooks/useJoinRealm"; +import { SequenceType, sendTransactionsV3 } from '@utils/sendTransactions' export const useDepositCallback = ( role: 'community' | 'council' | 'undefined' ) => { + const { handleRegister } = useJoinRealm(); const wallet = useWalletOnePointOh() const walletPk = wallet?.publicKey ?? undefined const realmPk = useSelectedRealmPubkey() @@ -75,17 +78,32 @@ export const useDepositCallback = ( amount ) - const transaction = new Transaction() - transaction.add(...instructions) + // instructions required to create voter weight records for any plugins connected to the realm + // no need to create the TOR, as it is already created by the deposit. + const pluginRegisterInstructions = await handleRegister(false) - await sendTransaction({ + const txes = [[...instructions, ...pluginRegisterInstructions]].map((txBatch) => { + return { + instructionsSet: txBatch.map((x) => { + return { + transactionInstruction: x, + signers: signers, + } + }), + sequenceType: SequenceType.Sequential, + } + }) + + await sendTransactionsV3({ connection, wallet: wallet!, - transaction, - signers, - sendingMessage: 'Depositing tokens', - successMessage: 'Tokens have been deposited', + transactionInstructions: txes, }) + + // Force the UI to recalculate voter weight + queryClient.invalidateQueries({ + queryKey: ['calculateVoterWeight'], + }) }, [connection, realmPk, role, wallet, walletPk] ) diff --git a/components/GovernancePower/Power/VotingPowerCards.tsx b/components/GovernancePower/Power/VotingPowerCards.tsx new file mode 100644 index 0000000000..01d34b4c58 --- /dev/null +++ b/components/GovernancePower/Power/VotingPowerCards.tsx @@ -0,0 +1,114 @@ +import { FC, ReactNode } from 'react' +import { PluginName } from '@constants/plugins' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import PythVotingPower from '../../../PythVotePlugin/components/PythVotingPower' +import GatewayCard from '@components/Gateway/GatewayCard' +import NftVotingPower from '@components/ProposalVotingPower/NftVotingPower' +import LockedCommunityNFTRecordVotingPower from '@components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower' +import QuadraticVotingPower from '@components/ProposalVotingPower/QuadraticVotingPower' +import { VSRCard } from '@components/GovernancePower/Power/VSRCard' +import { VanillaCard } from '@components/GovernancePower/Power/Vanilla/VanillaCard' +import DriftVotingPower from 'DriftStakeVoterPlugin/components/DriftVotingPower' +import TokenHaverVotingPower from '@components/ProposalVotingPower/TokenHaverVotingPower' +import ParclVotingPower from 'ParclVotePlugin/components/ParclVotingPower' + +/**** + * Note to plugin implementors. + * + * To add a plugin with a dedicated Vote Power UI, add the plugin name to the `pluginsWithDedicatedVotingPowerUI` list below. + * Then register the dedicated UI in CardForPlugin + * + ***/ + +// A list of all the plugins that have a dedicated voting power UI in realms. +// Plugins will use the vanilla voting power UI if they are not in this list. +// The vanilla voting power UI will: +// - assume the user can "deposit" tokens into the DAO +// - show the votes simply using the plucin's calculatedVoteWeight without explanation +// This is a reasonable placeholder for some plugins, but to make life easier for users, +// plugin developers may want to add their own. +const pluginsWithDedicatedVotingPowerUI = [ + 'NFT', + 'pyth', + 'HeliumVSR', + 'VSR', + 'gateway', + 'QV', + 'drift', + 'token_haver', + "parcl" +] as const + +export type VotingCardProps = { + role: 'community' | 'council' + hideIfZero?: boolean + className?: string +} + +// True if the plugin has a dedicated voting power UI +// The type assertion here does the following: +// - pass any plugin name +// - narrow the type to a plugin that requires a dedicated UI +// - adding to the pluginsWithDedicatedVotingPowerUI list forces the CardForPlugin component to be updated +const hasDedicatedVotingPowerUI = ( + plugin: PluginName +): plugin is typeof pluginsWithDedicatedVotingPowerUI[number] => + pluginsWithDedicatedVotingPowerUI.includes( + plugin as typeof pluginsWithDedicatedVotingPowerUI[number] + ) + +const CardForPlugin: FC< + { plugin: typeof pluginsWithDedicatedVotingPowerUI[number] } & VotingCardProps +> = ({ plugin, role, ...props }) => { + switch (plugin) { + case 'NFT': + return + case 'pyth': + return + case 'HeliumVSR': + return + case 'VSR': + return + case 'gateway': + return + case 'QV': + return + case 'drift': + return + case 'token_haver': + return + case 'parcl': + return + } +} + +/** + * A component that renders the voting power cards for a given set of plugins. + * + * NOTE: This applies only to the community role at present, as practically plugins are only applied to community + * governances. However, there is little reason why this could not be extended to the council role, so to ensure + * future-compatibility we are passing the role here. + */ +export const VotingPowerCards: FC = (props) => { + const { plugins } = useRealmVoterWeightPlugins(props.role) + const cards = (plugins?.voterWeight ?? []) + .map((plugin, pluginIdx): ReactNode | undefined => { + return hasDedicatedVotingPowerUI(plugin.name) ? ( + + ) : undefined + }) + .filter(Boolean) // filter out undefined + + const includesUnrecognizedPlugin = plugins?.voterWeight.some( + (plugin) => plugin.name === 'unknown' + ) + + if (!cards.length) { + // No dedicated plugin cards - add the vanilla card + cards.push( + + ) + } + + return <>{cards} +} 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/Members/AddMemberForm.tsx b/components/Members/AddMemberForm.tsx index 178f4ff356..672de73e32 100644 --- a/components/Members/AddMemberForm.tsx +++ b/components/Members/AddMemberForm.tsx @@ -5,7 +5,7 @@ import Button, { SecondaryButton } from '@components/Button' import VoteBySwitch from 'pages/dao/[symbol]/proposal/components/VoteBySwitch' import { abbreviateAddress, precision } from 'utils/formatting' import { getMintSchema } from 'utils/validations' -import { FC, useMemo, useState } from 'react' +import React, { FC, useMemo, useState } from 'react' import { MintForm, UiInstruction } from 'utils/uiTypes/proposalCreationTypes' import useGovernanceAssets from 'hooks/useGovernanceAssets' import { @@ -32,6 +32,7 @@ import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import { DEFAULT_GOVERNANCE_PROGRAM_VERSION } from '@components/instructions/tools' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; interface AddMemberForm extends Omit { description: string @@ -43,7 +44,6 @@ const AddMemberForm: FC<{ close: () => void; mintAccount: AssetAccount }> = ({ mintAccount, }) => { const programVersion = useProgramVersion() - const [voteByCouncil, setVoteByCouncil] = useState(false) const [showOptions, setShowOptions] = useState(false) const [isLoading, setIsLoading] = useState(false) const [formErrors, setFormErrors] = useState({}) @@ -51,12 +51,13 @@ const AddMemberForm: FC<{ close: () => void; mintAccount: AssetAccount }> = ({ const router = useRouter() const connection = useLegacyConnectionContext() const wallet = useWalletOnePointOh() + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const { fmtUrlWithCluster } = useQueryContext() const { symbol } = router.query const realm = useRealmQuery().data?.result - const { realmInfo, canChooseWhoVote } = useRealm() + const { realmInfo } = useRealm() const { data: mintInfo } = useMintInfoByPubkeyQuery(mintAccount.pubkey) const programId: PublicKey | undefined = realmInfo?.programId @@ -242,6 +243,7 @@ const AddMemberForm: FC<{ close: () => void; mintAccount: AssetAccount }> = ({ router.push(url) } catch (error) { + console.log('Error creating proposal', error); notify({ type: 'error', message: `${error}`, @@ -343,13 +345,13 @@ const AddMemberForm: FC<{ close: () => void; mintAccount: AssetAccount }> = ({ onBlur={validateAmountOnBlur} /> - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - /> + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/Members/MemberOverview.tsx b/components/Members/MemberOverview.tsx index 08e9128011..2446768d97 100644 --- a/components/Members/MemberOverview.tsx +++ b/components/Members/MemberOverview.tsx @@ -53,7 +53,7 @@ import { } from '@hooks/queries/digitalAssets' import { useNftRegistrarCollection } from '@hooks/useNftRegistrarCollection' import { NFT_PLUGINS_PKS } from '@constants/plugins' -import {ProfileName} from "@components/Profile/ProfileName"; +import { ProfileName } from '@components/Profile/ProfileName' const RevokeMembership: FC<{ member: PublicKey; mint: PublicKey }> = ({ member, @@ -221,9 +221,11 @@ const NftDisplayList = ({ const MemberOverview = ({ member, activeMembers, + vsrDisplay }: { member: Member - activeMembers: any[] | undefined + activeMembers: any[] | undefined, + vsrDisplay?: boolean }) => { const programVersion = useProgramVersion() const realm = useRealmQuery().data?.result @@ -436,9 +438,9 @@ const MemberOverview = ({
- {(communityAmount || !councilAmount) && ( + {(communityAmount || !councilAmount && !vsrDisplay) && (
-

{tokenName} Votes

+

{tokenName} votes

{communityAmount || 0}{' '} {hasCommunityTokenOutsideRealm && ( @@ -449,9 +451,9 @@ const MemberOverview = ({

Vote Power Rank: {memberVotePowerRank}

)} - {councilAmount && ( + {councilAmount && !vsrDisplay && (
-

Council Votes

+

Council votes

{councilAmount}{' '} {hasCouncilTokenOutsideRealm && ( diff --git a/components/Members/MembersTabs.tsx b/components/Members/MembersTabs.tsx index 175b97465c..f33188870c 100644 --- a/components/Members/MembersTabs.tsx +++ b/components/Members/MembersTabs.tsx @@ -12,19 +12,21 @@ import { } from '@hooks/queries/mintInfo' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import { NFT_PLUGINS_PKS } from '@constants/plugins' -import {ProfileName} from "@components/Profile/ProfileName"; -import {ProfileImage} from "@components/Profile"; +import { ProfileName } from '@components/Profile/ProfileName' +import { ProfileImage } from '@components/Profile' interface MembersTabsProps { activeTab: Member onChange: (x) => void tabs: Array + vsrMode?: boolean } const MembersTabs: FunctionComponent = ({ activeTab, onChange, tabs, + vsrMode }) => { const realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result @@ -69,6 +71,7 @@ const MembersTabs: FunctionComponent = ({ activeTab={activeTab} tokenName={tokenName || nftName || ''} onChange={onChange} + vsrMode={vsrMode} > ) ) @@ -86,13 +89,15 @@ const MemberItems = ({ activeTab, tokenName, onChange, + vsrMode }: { member: Member mint?: MintInfo councilMint?: MintInfo activeTab: Member tokenName: string - onChange: (member: Member) => void + onChange: (member: Member) => void, + vsrMode?: boolean }) => { const { walletAddress, @@ -123,7 +128,11 @@ const MemberItems = ({ }, [walletAddress]) const renderAddressImage = useMemo( () => ( - + ), // 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 [walletAddress] @@ -145,25 +154,27 @@ const MemberItems = ({

{renderAddressName}

- {/*

Votes Cast: {votesCasted}

*/} - - {(communityAmount || !councilAmount) && ( - - {tokenName} Votes {communityAmount || 0} - {hasCommunityTokenOutsideRealm && ( - - )} - - )} - {councilAmount && ( - - Council Votes {councilAmount}{' '} - {hasCouncilTokenOutsideRealm && ( - - )} - - )} - + {vsrMode ? + '' : + + {(communityAmount || !councilAmount) && ( + + {tokenName} votes {communityAmount || 0} + {hasCommunityTokenOutsideRealm && ( + + )} + + )} + {councilAmount && ( + + Council votes {councilAmount}{' '} + {hasCouncilTokenOutsideRealm && ( + + )} + + )} + + }
diff --git a/components/Members/RevokeMyMembership.tsx b/components/Members/RevokeMyMembership.tsx index 27d3304288..a5618f43b2 100644 --- a/components/Members/RevokeMyMembership.tsx +++ b/components/Members/RevokeMyMembership.tsx @@ -5,7 +5,6 @@ import Modal from '@components/Modal' import { ExclamationCircleIcon, XCircleIcon } from '@heroicons/react/outline' import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' import { useRealmQuery } from '@hooks/queries/realm' -import useGovernanceForGovernedAddress from '@hooks/useGovernanceForGovernedAddress' import useProgramVersion from '@hooks/useProgramVersion' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { createRevokeGoverningTokens } from '@solana/spl-governance' @@ -62,9 +61,9 @@ const Form: FC<{ closeModal: () => void }> = ({ closeModal }) => { : (membershipTypes[selectedMembershipType] as PublicKey | undefined), [membershipTypes, selectedMembershipType] ) + const { data: mintInfo } = useMintInfoByPubkeyQuery(selectedMint) - const governance = useGovernanceForGovernedAddress(selectedMint) - + // erase errors on dirtying useEffect(() => { setFormErrors({}) @@ -94,7 +93,6 @@ const Form: FC<{ closeModal: () => void }> = ({ closeModal }) => { if ( realm === undefined || mintInfo?.result === undefined || - governance === undefined || !wallet?.publicKey ) { throw new Error('proposal created before necessary data is fetched') @@ -134,7 +132,6 @@ const Form: FC<{ closeModal: () => void }> = ({ closeModal }) => { closeModal, connection, form.amount, - governance, mintInfo?.result, programVersion, realm, diff --git a/components/Members/useMembers.tsx b/components/Members/useMembers.tsx index f4579d56bf..40bec70b02 100644 --- a/components/Members/useMembers.tsx +++ b/components/Members/useMembers.tsx @@ -9,13 +9,13 @@ import { BN_ZERO } from '@solana/spl-governance' import { getMultipleAccountInfoChunked, getTokenAccountsByMint, - parseTokenAccountData, TokenProgramAccount, } from '@utils/tokens' +import { parseTokenAccountData } from '@utils/parseTokenAccountData' import { capitalize } from '@utils/helpers' import { Member } from 'utils/uiTypes/members' import { useRealmQuery } from '@hooks/queries/realm' -import { useTokenOwnerRecordsForRealmQuery } from '@hooks/queries/tokenOwnerRecord' +import { useCouncilTokenOwnerRecordsForRealmQuery } from '@hooks/queries/tokenOwnerRecord' import { useQuery } from '@tanstack/react-query' import { useConnection } from '@solana/wallet-adapter-react' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' @@ -31,7 +31,7 @@ import { BN } from '@coral-xyz/anchor' */ export const useMembersQuery = () => { const realm = useRealmQuery().data?.result - const { data: tors } = useTokenOwnerRecordsForRealmQuery() + const { data: tors } = useCouncilTokenOwnerRecordsForRealmQuery() const connection = useConnection() const config = useRealmConfigQuery().data?.result diff --git a/components/NFTVotePluginSettingsDisplay.tsx b/components/NFTVotePluginSettingsDisplay.tsx index 83268b11da..2dec9cf6c5 100644 --- a/components/NFTVotePluginSettingsDisplay.tsx +++ b/components/NFTVotePluginSettingsDisplay.tsx @@ -2,7 +2,6 @@ import { PublicKey } from '@solana/web3.js' import type BN from 'bn.js' import cx from 'classnames' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import NFTIcon from '@components/treasuryV2/icons/NFTCollectionPreviewIcon' import { useConnection } from '@solana/wallet-adapter-react' import { useAsync } from 'react-async-hook' @@ -10,6 +9,7 @@ import { fetchDigitalAssetById } from '@hooks/queries/digitalAssets' import { getNetworkFromEndpoint } from '@utils/connection' import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' import BigNumber from 'bignumber.js' +import {useNftRegistrar} from "@hooks/useNftRegistrar"; interface CollectionConfig { collection: PublicKey @@ -23,7 +23,7 @@ interface Props { export function NFTVotePluginSettingsDisplay(props: Props) { const { connection } = useConnection() - const registrar = useVotePluginsClientStore((s) => s.state.nftMintRegistrar) + const registrar = useNftRegistrar(); const { result: configsWithNames } = useAsync(async () => { const collectionConfigs = (registrar?.collectionConfigs || diff --git a/components/NavBar.tsx b/components/NavBar.tsx index f0802479f3..ab3a147c9d 100644 --- a/components/NavBar.tsx +++ b/components/NavBar.tsx @@ -1,9 +1,9 @@ import useQueryContext from '@hooks/useQueryContext' import Link from 'next/link' import dynamic from 'next/dynamic' -import NotificationsSwitch from './NotificationsSwitch' import ThemeSwitch from './ThemeSwitch' import { ExternalLinkIcon } from '@heroicons/react/outline' +import DialectNotifications from './Dialect' const ConnectWalletButtonDynamic = dynamic( async () => await import('./ConnectWalletButton'), @@ -38,7 +38,7 @@ const NavBar = () => { - +
diff --git a/components/NewRealmWizard/components/AdvancedOptionsDropdown.tsx b/components/NewRealmWizard/components/AdvancedOptionsDropdown.tsx index 79d3cf0dd3..144eed3fd2 100644 --- a/components/NewRealmWizard/components/AdvancedOptionsDropdown.tsx +++ b/components/NewRealmWizard/components/AdvancedOptionsDropdown.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { ReactNode, useState } from 'react' import { Transition } from '@headlessui/react' import Text from '@components/Text' @@ -6,6 +6,12 @@ export default function AdvancedOptionsDropdown({ className = 'mt-10 md:mt-16 w-fit', children, title = 'Advanced Options', + icon, +}: { + children: ReactNode + icon?: ReactNode + className?: string + title?: string }) { const [open, setOpen] = useState(false) return ( @@ -20,6 +26,7 @@ export default function AdvancedOptionsDropdown({ {title} + {icon}
diff --git a/components/NewRealmWizard/components/CivicPassSelector.tsx b/components/NewRealmWizard/components/CivicPassSelector.tsx new file mode 100644 index 0000000000..99e2172c4f --- /dev/null +++ b/components/NewRealmWizard/components/CivicPassSelector.tsx @@ -0,0 +1,100 @@ +import * as DropdownMenu from '@radix-ui/react-dropdown-menu' +import { useEffect, useState } from 'react' +interface Props { + className?: string + selectedPass: string + onPassSelected: (string) => void +} +import cx from '@hub/lib/cx' +import { availablePasses } from 'GatewayPlugin/config' +import { ChevronDownIcon } from '@heroicons/react/solid' + +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 iconStyles = cx('fill-neutral-500', 'h-5', 'transition-transform', 'w-4') +const descriptionStyles = cx('dark:text-neutral-400 text-sm') + +export default function CivicPassSelector({ + className, + onPassSelected, +}: Props) { + const [open, setOpen] = useState(false) + const [selectedPassState, setSelectedPass] = useState(availablePasses[0]) + + useEffect(() => { + onPassSelected(selectedPassState.value) + }, [onPassSelected, selectedPassState.value]) + + return ( +
+ +
+ +
+ {selectedPassState?.name || 'Select a Civic Pass'} +
+
+ {selectedPassState?.description || ''} +
+ +
+ + + {availablePasses.slice(0, -1).map((config, i) => ( + { + setSelectedPass(config) + }} + > +
{config.name}
+
{config.description}
+
+ ))} +
+
+
+
+ {!selectedPassState.isSybilResistance && ( +
+ Warning: This pass type does + not provide sybil resistance. +
+ )} +
+ ) +} diff --git a/components/NewRealmWizard/components/FormField.tsx b/components/NewRealmWizard/components/FormField.tsx index db40264e57..ef45925017 100644 --- a/components/NewRealmWizard/components/FormField.tsx +++ b/components/NewRealmWizard/components/FormField.tsx @@ -3,7 +3,7 @@ interface Props { advancedOption?: boolean children: React.ReactNode className?: string - description: string | React.ReactNode + description?: string | React.ReactNode disabled?: boolean optional?: boolean title: string @@ -59,14 +59,16 @@ export default function FormField({ {titleExtra}
- - {description} - + {description && ( + + {description} + + )}
{children}
) diff --git a/components/NewRealmWizard/components/FormSummary.tsx b/components/NewRealmWizard/components/FormSummary.tsx index 617664fd96..c73ffe76b7 100644 --- a/components/NewRealmWizard/components/FormSummary.tsx +++ b/components/NewRealmWizard/components/FormSummary.tsx @@ -240,6 +240,16 @@ export default function WizardSummary({ >
{formData?.name}
+ {formData?.isQuadratic && ( + + + Civic Plugin + + + Quadratic Voting Plugin + + + )} {type === MULTISIG_FORM ? (
@@ -298,8 +308,10 @@ export default function WizardSummary({ type === MULTISIG_FORM ? 'Create wallet' : `Create ${ - type === COMMUNITY_TOKEN_FORM + type === COMMUNITY_TOKEN_FORM && !formData?.isQuadratic ? 'Community Token' + : type === COMMUNITY_TOKEN_FORM && formData?.isQuadratic + ? 'Quadratic Voting' : 'NFT Community' } DAO` } diff --git a/components/NewRealmWizard/components/TokenInput.tsx b/components/NewRealmWizard/components/TokenInput.tsx index 3ac137120d..13a06a8df1 100644 --- a/components/NewRealmWizard/components/TokenInput.tsx +++ b/components/NewRealmWizard/components/TokenInput.tsx @@ -221,7 +221,7 @@ export default function TokenInput({ render={({ field, fieldState: { error } }) => ( () + useEffect(() => { + const fetchCoefficients = async () => { + const coefficients = await getCoefficients( + undefined, + new PublicKey(communityTokenMintAddress), + connection + ) + setValue('coefficientA', coefficients[0].toFixed(2)) + setValue('coefficientB', coefficients[1]) + setValue('coefficientC', coefficients[2]) + } + + // If the user wants to use a pre-existing token, we need to adjust the coefficients ot match the decimals of that token + if (communityTokenMintAddress) { + fetchCoefficients() + } + }, [connection, communityTokenMintAddress, setValue]) + useEffect(() => { updateUserInput(formData, CommunityTokenSchema, setValue) }, [formData, setValue]) @@ -221,7 +261,7 @@ export default function CommunityTokenForm({ render={({ field, fieldState: { error } }) => ( + {isQuadratic &&
+
+ Note:  + Quadratic Voting DAOs typically have a lower circulating supply factor + than non-quadratic DAOs. This is because the quadratic formula + reduces the weight of votes overall. +
+
+ Consider optionally setting a value < 1 here to increase the accuracy of approval thresholds. +
+
} )} + + ( +
+ + + +
+ )} + /> + + {isQuadratic && ( + + } + > +
+

+ Changes advised for advanced users only +

+
+ ( + +
+ +
+
+ )} + /> + + +
+

See Docs

+ + + +
+
+
+ ( + + { + preventNegativeNumberInput(ev) + field.onChange(ev) + }} + /> + + )} + /> + ( + + { + preventNegativeNumberInput(ev) + field.onChange(ev) + }} + /> + + )} + /> + ( + + { + preventNegativeNumberInput(ev) + field.onChange(ev) + }} + /> + + )} + /> +
+
+ )} { updateUserInput( @@ -97,6 +98,10 @@ export default function YesVotePercentageForm({ onSubmit({ step: currentStep, data: values }) } + useEffect(() => { + setValue(fieldName, percentageValue) + }, [fieldName, formData.isQuadratic, percentageValue, setValue]) + return (
( - + )} /> @@ -143,8 +144,9 @@ export default function YesVotePercentageForm({ > {forCommunity ? ( - Typically, newer DAOs start their community approval quorums around - 60% of total token supply. + {!formData.isQuadratic + ? 'Typically, newer DAOs start their community approval quorums around 60% of total token supply.' + : "Setting a high percentage approval quorum may result in proposals never passing in a quadratic voting DAO, as the voting power is influenced by token distribution. It's recomended to start with a low percentage and adjust as needed."} ) : forCouncil && formData?.memberAddresses?.length >= 0 ? ( <> diff --git a/components/NftVotingCountingModal.tsx b/components/NftVotingCountingModal.tsx index cc5b5745e6..64d3375c5d 100644 --- a/components/NftVotingCountingModal.tsx +++ b/components/NftVotingCountingModal.tsx @@ -2,12 +2,11 @@ import { useVotingNfts } from '@hooks/queries/plugins/nftVoter' import { usePrevious } from '@hooks/usePrevious' import useUserOrDelegator from '@hooks/useUserOrDelegator' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' import useNftProposalStore from 'NftVotePlugin/NftProposalStore' import { useEffect, useState } from 'react' import useTransactionsStore from 'stores/useTransactionStore' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import Modal from './Modal' +import {useNftClient} from "../VoterWeightPlugins/useNftClient"; const NftVotingCountingModal = () => { const votingInProgress = useNftProposalStore((s) => s.votingInProgress) @@ -22,9 +21,6 @@ const NftVotingComponent = () => { countedNftsForProposal, proposal, } = useNftProposalStore() - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) const wallet = useWalletOnePointOh() const userPk = useUserOrDelegator() const votingNfts = useVotingNfts(userPk) ?? [] @@ -36,6 +32,7 @@ const NftVotingComponent = () => { const lastTransactionNftsCount = 5 const maxNftsPerTransaction = 8 + const { nftClient } = useNftClient() const [usedNftsCount, setUsedNftsCount] = useState(0) const [remainingVotingPower, setRemainingVotingPower] = useState(0) const handleCalcCountedNfts = (val: number) => { @@ -83,7 +80,7 @@ const NftVotingComponent = () => { wrapperStyle={{ top: '-350px' }} onClose={() => closeNftVotingCountingModal( - (client.client as unknown) as NftVoterClient, + nftClient!, proposal!, wallet!.publicKey! ) diff --git a/components/NotifiIcon.tsx b/components/NotifiIcon.tsx deleted file mode 100644 index 6883c5f639..0000000000 --- a/components/NotifiIcon.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useTheme } from 'next-themes' -import NotifiIconDark from './NotificationsSwitch/NotifiIconDark' -import NotifiIconLight from './NotificationsSwitch/NotifiIconLight' - -const NotifiIcon = ({ height = '30' }) => { - const { theme } = useTheme() - return theme === 'Dark' ? ( - - ) : ( - - ) -} - -export default NotifiIcon diff --git a/components/NotificationsCard/NotifiFullLogo.tsx b/components/NotificationsCard/NotifiFullLogo.tsx deleted file mode 100644 index b97ddc2c9b..0000000000 --- a/components/NotificationsCard/NotifiFullLogo.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { useTheme } from 'next-themes' -import NotifiLogoFullDark from './NotifiLogoFullDark' -import NotifiLogoFullLight from './NotifiLogoFullLight ' - -const NotifiFullLogo = ({ height = '23', width = '340' }) => { - const { theme } = useTheme() - return theme === 'Dark' ? ( - - ) : ( - - ) -} - -export default NotifiFullLogo diff --git a/components/NotificationsCard/NotifiLogoFullDark.tsx b/components/NotificationsCard/NotifiLogoFullDark.tsx deleted file mode 100644 index 0022f6eabd..0000000000 --- a/components/NotificationsCard/NotifiLogoFullDark.tsx +++ /dev/null @@ -1,63 +0,0 @@ -const NotifiIconDark = ({ height = '40', width = '340' }) => { - return ( - - - - - - - - - - - - - - - - - ) -} - -export default NotifiIconDark diff --git a/components/NotificationsCard/NotifiLogoFullLight .tsx b/components/NotificationsCard/NotifiLogoFullLight .tsx deleted file mode 100644 index 93066a6eeb..0000000000 --- a/components/NotificationsCard/NotifiLogoFullLight .tsx +++ /dev/null @@ -1,63 +0,0 @@ -const NotifiIconDark = ({ height = '50', width = '340' }) => { - return ( - - - - - - - - - - - - - - - - - ) -} - -export default NotifiIconDark diff --git a/components/NotificationsCard/NotifiLogoLightLong.svg b/components/NotificationsCard/NotifiLogoLightLong.svg deleted file mode 100644 index e5edd54c09..0000000000 --- a/components/NotificationsCard/NotifiLogoLightLong.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/components/NotificationsCard/NotifiPreviewCard.tsx b/components/NotificationsCard/NotifiPreviewCard.tsx deleted file mode 100644 index aca28419b9..0000000000 --- a/components/NotificationsCard/NotifiPreviewCard.tsx +++ /dev/null @@ -1,203 +0,0 @@ -import Switch from './NotifiSwitch' -import { XIcon } from '@heroicons/react/solid' -import { Source, useNotifiClient } from '@notifi-network/notifi-react-hooks' -import React, { - FunctionComponent, - useCallback, - useEffect, - useMemo, - useState, -} from 'react' - -import NotifiFullLogo from './NotifiFullLogo' -type NotifiClientReturnType = ReturnType - -type NotifiPreviewCardProps = { - onClick: () => void - onClose: () => void - telegramEnabled: boolean - email: string - phoneNumber: string - telegram: string - handleDelete: (source: Source) => Promise -} & Pick - -const NotifiPreviewCard: FunctionComponent = ({ - createAlert, - data, - email, - handleDelete, - onClose, - onClick, - phoneNumber, - telegram, - telegramEnabled, - isAuthenticated, -}) => { - const alerts = data?.alerts - const sources = data?.sources - const [isLoading, setLoading] = useState(false) - - const handleEdit = useCallback(() => { - onClick() - }, [onClick]) - - const handleUnsubscribe = useCallback( - async (source: Source) => { - if (isLoading) { - return - } - handleDelete(source) - }, - [handleDelete, isLoading] - ) - - useEffect(() => { - if (!isAuthenticated) { - onClick() - } - // 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 - }, [isAuthenticated]) - - const handleSubscribe = useCallback( - async (source: Source) => { - if (isLoading) { - return - } - - if (!source) { - throw new Error('No source provided') - } - const filterId = source.applicableFilters[0].id - - if (!filterId) { - throw new Error('No filter id found') - } - try { - setLoading(true) - const alertResult = await createAlert({ - emailAddress: email === '' ? null : email, - filterId: filterId ?? '', - name: `${source.name} notification`, - phoneNumber: phoneNumber === '' ? null : phoneNumber, - sourceId: source.id ?? '', - telegramId: telegram === '' ? null : telegram, - }) - - if (alertResult) { - if (alertResult.targetGroup?.telegramTargets?.length > 0) { - const target = alertResult.targetGroup?.telegramTargets[0] - if (target && target.isConfirmed === false) { - if (target.confirmationUrl) { - window.open(target.confirmationUrl) - } - } - } - } - setLoading(false) - } catch (e) { - throw new Error(e) - } - }, - [createAlert, email, phoneNumber, telegram, isLoading] - ) - - const daoNotifications = useMemo( - () => (source: Source) => { - const handleClick = (source: Source) => { - isChecked ? handleUnsubscribe(source) : handleSubscribe(source) - } - const sourceId = source.id - - const isChecked = Boolean( - alerts?.some((alert) => - alert.sourceGroup.sources.some((source) => source.id === sourceId) - ) - ) - - return ( -
-
- {source.name} Notifications On -
-
- handleClick(source)} /> -
-
- ) - }, - // 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 - [alerts, handleDelete, handleSubscribe] - ) - - const notificationsToggle = useMemo( - () => - sources - ?.map((source) => { - if (source.type === 'DIRECT_PUSH') { - return - } - return daoNotifications(source) - }) - ?.filter((source) => source), - [daoNotifications, sources] - ) - - return ( -
-
-
-

Notifications

- -
- {data && data?.sources?.length > 0 ? ( -
-

{email}

-

{phoneNumber}

- {telegramEnabled &&

{telegram}

} -
- Edit Information -
-
- ) : ( -
-

No governance memberships found

-
- )} -
- {notificationsToggle && notificationsToggle.length >= 1 ? ( -
- {notificationsToggle} -
- ) : null} -
-
-

Powered by

- - - -
- -
-
- ) -} - -export default NotifiPreviewCard diff --git a/components/NotificationsCard/NotifiSwitch.tsx b/components/NotificationsCard/NotifiSwitch.tsx deleted file mode 100644 index 1ad9adf671..0000000000 --- a/components/NotificationsCard/NotifiSwitch.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { FunctionComponent } from 'react' - -interface SwitchProps { - checked: boolean - onChange: (x: boolean) => void -} - -const Switch: FunctionComponent = ({ - checked = false, - onChange, -}) => { - const handleClick = () => { - onChange(!checked) - } - - return ( -
- -
- ) -} - -export default Switch diff --git a/components/NotificationsCard/NotificationCardContainer.tsx b/components/NotificationsCard/NotificationCardContainer.tsx deleted file mode 100644 index fb54b149ee..0000000000 --- a/components/NotificationsCard/NotificationCardContainer.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import NotificationsCard from '@components/NotificationsCard' -import NotifiPreviewCard from '@components/NotificationsCard/NotifiPreviewCard' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { EndpointTypes } from '@models/types' -import { - BlockchainEnvironment, - Source, - useNotifiClient, -} from '@notifi-network/notifi-react-hooks' -import { firstOrNull } from '@utils/helpers' -import { useRouter } from 'next/router' -import { useCallback, useEffect, useState } from 'react' - -type Props = { - onClose: () => void - onBackClick: () => void -} - -const NotificationCardContainer: React.FC = ({ - onClose, - onBackClick, -}) => { - const [showPreview, setPreview] = useState(true) - const router = useRouter() - - const { cluster } = router.query - - const endpoint = cluster ? (cluster as EndpointTypes) : 'mainnet' - const wallet = useWalletOnePointOh() - const connected = !!wallet?.connected - let env = BlockchainEnvironment.MainNetBeta - - switch (endpoint) { - case 'mainnet': - break - case 'devnet': - env = BlockchainEnvironment.DevNet - break - case 'localnet': - env = BlockchainEnvironment.LocalNet - break - } - const notifiClient = useNotifiClient({ - dappAddress: 'solanarealmsdao', - env, - walletPublicKey: wallet?.publicKey?.toString() ?? '', - }) - - const { data, getConfiguration, deleteAlert, isInitialized } = notifiClient - - const [email, setEmail] = useState('') - const [phoneNumber, setPhone] = useState('') - const [telegram, setTelegram] = useState('') - const [telegramEnabled, setTelegramEnabled] = useState(false) - - useEffect(() => { - const targetGroup = firstOrNull(data?.targetGroups) - if (targetGroup) { - setEmail(firstOrNull(targetGroup?.emailTargets)?.emailAddress ?? '') - setPhone(firstOrNull(targetGroup?.smsTargets)?.phoneNumber ?? '') - setTelegram(firstOrNull(targetGroup?.telegramTargets)?.telegramId ?? '') - } else { - setEmail(firstOrNull(data?.emailTargets)?.emailAddress ?? '') - setPhone(firstOrNull(data?.smsTargets)?.phoneNumber ?? '') - setTelegram(firstOrNull(data?.telegramTargets)?.telegramId ?? '') - } - }, [data]) - - const updateTelegramSupported = useCallback(async () => { - const { supportedTargetTypes } = await getConfiguration() - const telegram = supportedTargetTypes.find( - (targetType) => targetType === 'TELEGRAM' - ) - setTelegramEnabled(telegram !== undefined) - }, [getConfiguration, setTelegramEnabled]) - - useEffect(() => { - updateTelegramSupported().catch((e) => { - console.error('Failed to get supported type information: ', e) - }) - }, [updateTelegramSupported]) - - useEffect(() => { - if (connected && isInitialized) { - const targetGroup = firstOrNull(data?.targetGroups) - - if (targetGroup) { - setEmail(firstOrNull(targetGroup?.emailTargets)?.emailAddress ?? '') - setPhone(firstOrNull(targetGroup?.smsTargets)?.phoneNumber ?? '') - setTelegram(firstOrNull(targetGroup?.telegramTargets)?.telegramId ?? '') - } else { - setEmail(firstOrNull(data?.emailTargets)?.emailAddress ?? '') - setPhone(firstOrNull(data?.smsTargets)?.phoneNumber ?? '') - setTelegram(firstOrNull(data?.telegramTargets)?.telegramId ?? '') - } - } - - if (data && data?.sources.length > 0) { - if (email || phoneNumber || telegram) { - setPreview(true) - } - } - }, [connected, data, email, setPreview, isInitialized, phoneNumber, telegram]) - - const handleDelete = useCallback( - async (source: Source) => { - try { - if (data?.alerts) { - const sourceId = source.id - const alertToDelete = data.alerts?.find((alert) => - alert.sourceGroup.sources.find((source) => source.id === sourceId) - ) - - alertToDelete?.id && - (await deleteAlert({ - alertId: alertToDelete.id, - keepSourceGroup: true, - keepTargetGroup: true, - })) - } - } catch (e) { - throw new Error(e) - } - }, - [data?.alerts, deleteAlert] - ) - - return ( -
-
-
- {!isInitialized && ( -
-
-
-
-
-
-
-
-
-
-
-
-
-
- )} - {showPreview && isInitialized && ( - setPreview(false)} - /> - )} - {!showPreview && isInitialized && ( - - )} -
-
-
- ) -} - -export default NotificationCardContainer diff --git a/components/NotificationsCard/PhoneInput.tsx b/components/NotificationsCard/PhoneInput.tsx deleted file mode 100644 index c9d79a1dc4..0000000000 --- a/components/NotificationsCard/PhoneInput.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import Input from '@components/inputs/Input' -import { Listbox, Transition } from '@headlessui/react' -import { ChatAltIcon, ChevronDownIcon } from '@heroicons/react/outline' -import { isValidPhoneNumber } from 'libphonenumber-js' -import { Dispatch, SetStateAction } from 'react' -import { Fragment, useCallback, useEffect, useState } from 'react' - -import { InputRow } from '.' -import { countryMap } from './data' -import { splitPhoneNumber } from './phoneUtils' - -type Props = { - handlePhone: (input: string) => void - phoneNumber: string - setErrorMessage: Dispatch> -} - -const PhoneInput = ({ handlePhone, phoneNumber, setErrorMessage }: Props) => { - const [selectedCountryCode, setCountryCode] = useState('US') - const [dialCode, setDialCode] = useState('+1') - const [baseNumber, setBaseNumber] = useState('') - - const selectCountryHandler = useCallback( - (value: string) => { - setCountryCode(value) - const dialCode = countryMap[value].dialCode - setDialCode(dialCode) - - const input = baseNumber !== '' ? dialCode + baseNumber : '' - handlePhone(input) - }, - [baseNumber, handlePhone] - ) - - const splitPhoneNumbers = useCallback( - (phoneNumber: string) => { - const { baseNumber, countryCode } = splitPhoneNumber(phoneNumber) - if (!countryCode || !baseNumber) { - setErrorMessage('Improper phone, please try again') - } - setBaseNumber(baseNumber) - setCountryCode(countryCode) - }, - [setErrorMessage] - ) - - useEffect(() => { - if (phoneNumber && isValidPhoneNumber(phoneNumber)) { - splitPhoneNumbers(phoneNumber) - } - // 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 - }, [phoneNumber, splitPhoneNumbers, isValidPhoneNumber]) - - const onChange = useCallback( - (event: React.ChangeEvent) => { - const onlyNumberInput = event.target.value.replace(/[^\d]/g, '') - - setBaseNumber(onlyNumberInput) - const input = onlyNumberInput !== '' ? dialCode + onlyNumberInput : '' - handlePhone(input) - }, - [dialCode, handlePhone] - ) - - const validatePhoneNumber = () => { - if (!isValidPhoneNumber(phoneNumber) && phoneNumber !== '') { - setErrorMessage('You have entered an invalid number') - } - } - - return ( - - } - label="phone" - > - setErrorMessage('')} - onBlur={validatePhoneNumber} - placeholder="XXX-XXX-XXXX" - type="tel" - value={baseNumber} - /> -
- -
- - {dialCode} - - - - - - {Object.entries(countryMap).map( - ([countryCode, countryMetadata], idx) => { - const { dialCode, flag, name } = countryMetadata - return ( - - `relative cursor-default select-none py-2 pl-2 pr-4 z-20 ${ - active - ? 'bg-gray-800 text-grey-300' - : 'text-gray-300' - }` - } - key={idx} - value={countryCode} - > - {({ selected }) => ( - <> - -
-
- {flag} - {name} -
-
{dialCode}
-
-
- - )} -
- ) - } - )} -
-
-
-
-
-
- ) -} - -export default PhoneInput diff --git a/components/NotificationsCard/data.tsx b/components/NotificationsCard/data.tsx deleted file mode 100644 index d7f90c2279..0000000000 --- a/components/NotificationsCard/data.tsx +++ /dev/null @@ -1,137 +0,0 @@ -type CountryMetadata = { - name: string - dialCode: string - flag: string -} - -type CountryMap = { - [countryCode: string]: CountryMetadata -} - -export const countryMap: CountryMap = { - US: { - dialCode: '+1', - flag: '🇺🇸', - name: 'United States', - }, - AU: { - dialCode: '+61', - flag: '🇦🇺', - name: 'Australia', - }, - AT: { - dialCode: '+43', - flag: '🇦🇹', - name: 'Austria', - }, - BE: { - dialCode: '+32', - flag: '🇧🇪', - name: 'Belgium', - }, - BR: { - dialCode: '+55', - flag: '🇧🇷', - name: 'Brazil', - }, - CA: { - dialCode: '+1', - flag: '🇨🇦', - name: 'Canada', - }, - DK: { - dialCode: '+45', - flag: '🇩🇰', - name: 'Denmark', - }, - FI: { - dialCode: '+358', - flag: '🇫🇮', - name: 'Finland', - }, - FR: { - dialCode: '+33', - flag: '🇫🇷', - name: 'France', - }, - DE: { - dialCode: '+49', - flag: '🇩🇪', - name: 'Germany', - }, - HK: { - dialCode: '+852', - flag: '🇭🇰', - name: 'Hong Kong', - }, - HU: { - dialCode: '+36', - flag: '🇭🇺', - name: 'Hungary', - }, - IS: { - dialCode: '+354', - flag: '🇮🇸', - name: 'Iceland', - }, - MY: { - dialCode: '+60', - flag: '🇲🇾', - name: 'Malaysia', - }, - NO: { - dialCode: '+47', - flag: '🇳🇴', - name: 'Norway', - }, - PH: { - dialCode: '+63', - flag: '🇵🇭', - name: 'Philippines', - }, - PL: { - dialCode: '+48', - flag: '🇵🇱', - name: 'Poland', - }, - PT: { - dialCode: '+351', - flag: '🇵🇹', - name: 'Portugal', - }, - SG: { - dialCode: '+65', - flag: '🇸🇬', - name: 'Singapore', - }, - KR: { - dialCode: '+82', - flag: '🇰🇷', - name: 'Korea, Republic of South Korea', - }, - ES: { - dialCode: '+34', - flag: '🇪🇸', - name: 'Spain', - }, - SE: { - dialCode: '+46', - flag: '🇸🇪', - name: 'Sweden', - }, - CH: { - dialCode: '+41', - flag: '🇨🇭', - name: 'Switzerland', - }, - TW: { - dialCode: '+886', - flag: '🇹🇼', - name: 'Taiwan', - }, - GB: { - dialCode: '+44', - flag: '🇬🇧', - name: 'United Kingdom', - }, -} diff --git a/components/NotificationsCard/index.tsx b/components/NotificationsCard/index.tsx deleted file mode 100644 index 7b1fdf8443..0000000000 --- a/components/NotificationsCard/index.tsx +++ /dev/null @@ -1,463 +0,0 @@ -import { - ArrowLeftIcon, - MailIcon, - PaperAirplaneIcon, -} from '@heroicons/react/solid' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { - Alert, - GqlError, - MessageSigner, - useNotifiClient, -} from '@notifi-network/notifi-react-hooks' -import { firstOrNull } from '@utils/helpers' -import { isValidPhoneNumber } from 'libphonenumber-js' -import React, { - Dispatch, - FunctionComponent, - SetStateAction, - useEffect, - useState, -} from 'react' -import { useCallback } from 'react' - -import Button from '../Button' -import Input from '../inputs/Input' -import NotifiFullLogo from './NotifiFullLogo' -import PhoneInput from './PhoneInput' - -type NotifiClientReturnType = ReturnType - -type NotificationCardProps = { - onBackClick: () => void - email: string - phoneNumber: string - telegram: string - setPreview: Dispatch> - setEmail: Dispatch> - setTelegram: Dispatch> - setPhone: Dispatch> -} & Pick< - NotifiClientReturnType, - | 'createAlert' - | 'logIn' - | 'fetchData' - | 'data' - | 'isAuthenticated' - | 'updateAlert' - | 'getConfiguration' -> - -const NotificationsCard = ({ - createAlert, - data, - email, - getConfiguration, - isAuthenticated, - logIn, - onBackClick, - phoneNumber, - setEmail, - setPhone, - setPreview, - setTelegram, - telegram, - updateAlert, -}: NotificationCardProps) => { - const [isLoading, setLoading] = useState(false) - const [hasUnsavedChanges, setUnsavedChanges] = useState(false) - const [errorMessage, setErrorMessage] = useState('') - const [telegramEnabled, setTelegramEnabled] = useState(false) - const [firstTimeUser, setFirstTimeUser] = useState(false) - - const wallet = useWalletOnePointOh() - const connected = !!wallet?.connected - - const alerts = data?.alerts - const sources = data?.sources - - const [localEmail, setLocalEmail] = useState('') - const [localPhoneNumber, setLocalPhone] = useState('') - const [localTelegram, setLocalTelegram] = useState('') - - const updateTelegramSupported = useCallback(async () => { - const { supportedTargetTypes } = await getConfiguration() - const telegram = supportedTargetTypes.find((it) => it === 'TELEGRAM') - setTelegramEnabled(telegram !== undefined) - }, [getConfiguration, setTelegramEnabled]) - - useEffect(() => { - updateTelegramSupported().catch((e) => { - console.error('Failed to get supported type information: ', e) - }) - }, [updateTelegramSupported]) - - useEffect(() => { - const targetGroup = firstOrNull(data?.targetGroups) - - if (email || telegram || phoneNumber) { - setLocalEmail(email ?? '') - setLocalTelegram(telegram ?? '') - setLocalPhone(phoneNumber ?? '') - setUnsavedChanges(true) - } else if (targetGroup) { - setLocalEmail(firstOrNull(targetGroup?.emailTargets)?.emailAddress ?? '') - setLocalPhone(firstOrNull(targetGroup?.smsTargets)?.phoneNumber ?? '') - setLocalTelegram( - firstOrNull(targetGroup?.telegramTargets)?.telegramId ?? '' - ) - setUnsavedChanges(true) - } else { - setLocalEmail(firstOrNull(data?.emailTargets)?.emailAddress ?? '') - setLocalPhone(firstOrNull(data?.smsTargets)?.phoneNumber ?? '') - setLocalTelegram(firstOrNull(data?.telegramTargets)?.telegramId ?? '') - setUnsavedChanges(true) - } - }, [ - data, - data?.emailTargets, - data?.smsTargets, - data?.telegramTargets, - email, - phoneNumber, - telegram, - ]) - - const checkTelegramUnconfirmed = useCallback((alertsResponse: Alert[]) => { - const hasTelegramAlert = alertsResponse.find( - (alert) => alert.targetGroup.telegramTargets.length >= 0 - ) - const target = hasTelegramAlert?.targetGroup.telegramTargets[0] - - if (target && !target.isConfirmed) { - if (target.confirmationUrl) { - window.open(target.confirmationUrl) - } - } - - return alertsResponse.some((alertResponse) => - alertResponse.targetGroup.telegramTargets.some( - (target) => !target.isConfirmed - ) - ) - }, []) - - const handleError = (errors: { message: string }[]) => { - const error = errors.length > 0 ? errors[0] : null - if (error instanceof GqlError) { - setErrorMessage( - `${error.message}: ${error.getErrorMessages().join(', ')}` - ) - } else { - setErrorMessage(error?.message ?? 'Unknown error') - } - setLoading(false) - } - - const handleRefresh = useCallback( - async function () { - setLoading(true) - setErrorMessage('') - // user is not authenticated - if (!isAuthenticated && wallet && wallet.publicKey) { - try { - await logIn((wallet as unknown) as MessageSigner) - } catch (e) { - handleError([e]) - } - setLoading(false) - } else { - setPreview(true) - } - setLoading(false) - }, - // 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 - [setLoading, isAuthenticated, wallet, setErrorMessage, logIn] - ) - - const handleUpdate = async () => { - if (alerts && alerts.length >= 1) { - const results: Alert[] = [] - - for (const alert of alerts) { - const alertRes = await updateAlert({ - alertId: alert.id ?? '', - emailAddress: localEmail === '' ? null : localEmail, - phoneNumber: isValidPhoneNumber(localPhoneNumber) - ? localPhoneNumber - : null, - telegramId: localTelegram === '' ? null : localTelegram, - }) - if (alertRes) { - results.push(alertRes) - } - } - if (results) { - setEmail(results[0].targetGroup?.emailTargets[0]?.emailAddress ?? '') - setPhone(results[0].targetGroup?.smsTargets[0]?.phoneNumber ?? '') - setTelegram( - results[0].targetGroup?.telegramTargets[0]?.telegramId ?? '' - ) - setPreview(true) - } - checkTelegramUnconfirmed(results) - if (results) { - setPreview(true) - } - } else { - const results: Alert[] = [] - if (sources && sources.length >= 1) { - for (const source of sources) { - const filterId = source.applicableFilters[0].id - const alertRes = await createAlert({ - emailAddress: localEmail === '' ? null : localEmail, - filterId: filterId ?? '', - name: `${source.name} notification`, - phoneNumber: isValidPhoneNumber(localPhoneNumber) - ? localPhoneNumber - : null, - sourceId: source?.id ?? '', - telegramId: localTelegram === '' ? null : localTelegram, - }) - if (alertRes) { - results.push(alertRes) - } - } - } - if (telegram) { - checkTelegramUnconfirmed(results) - } - if (results && results.length >= 1) { - setPreview(true) - setEmail(results[0].targetGroup?.emailTargets[0]?.emailAddress ?? '') - setPhone(results[0].targetGroup?.smsTargets[0]?.phoneNumber ?? '') - setTelegram( - results[0].targetGroup?.telegramTargets[0]?.telegramId ?? '' - ) - } - } - setUnsavedChanges(false) - } - - useEffect(() => { - const handleLogIn = async () => { - await logIn((wallet as unknown) as MessageSigner) - } - - const anotherhandleUpdate = async () => { - await handleUpdate() - } - - if (firstTimeUser && sources === undefined) { - handleLogIn() - } - if (firstTimeUser && sources) { - anotherhandleUpdate() - } - // 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 - }, [firstTimeUser, sources]) - - const handleSave = useCallback(async () => { - setLoading(true) - if (!isAuthenticated && wallet && wallet.publicKey) { - try { - setFirstTimeUser(true) - } catch (e) { - setPreview(false) - handleError([e]) - } - } - if (connected && isAuthenticated) { - try { - setFirstTimeUser(false) - await handleUpdate() - setUnsavedChanges(false) - } catch (e) { - setPreview(false) - handleError([e]) - } - } - setLoading(false) - // 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 - }, [ - alerts, - checkTelegramUnconfirmed, - connected, - createAlert, - isAuthenticated, - localEmail, - localPhoneNumber, - localTelegram, - logIn, - setEmail, - setPhone, - setPreview, - setTelegram, - sources, - telegram, - updateAlert, - wallet, - ]) - - const handleEmail = (e: React.ChangeEvent) => { - setLocalEmail(e.target.value) - setUnsavedChanges(true) - } - - const handlePhone = (input: string) => { - setLocalPhone(input) - setUnsavedChanges(true) - } - - const handleTelegram = (e: React.ChangeEvent) => { - setLocalTelegram(e.target.value) - setUnsavedChanges(true) - } - - const disabled = - (isAuthenticated && !hasUnsavedChanges) || - (localEmail === '' && localTelegram === '' && localPhoneNumber === '') || - errorMessage !== '' - - return ( -
-
- - -
- {!connected ? ( - <> -
- Connect wallet to see options -
- - ) : ( - <> -
- Get notifications for proposals, voting, and results. Add your email - address, phone number, and/or Telegram. -
-
- {errorMessage.length > 0 ? ( -
{errorMessage}
- ) : ( - !isAuthenticated && ( -
- When prompted, sign the transaction. -
- ) - )} -
-
- - } - label="email" - > - - - - {telegramEnabled && ( - - } - label="Telegram" - > - - - )} -
-
-
- Already Subscribed?{' '} - - Click here to load your alert details. - -
-
-
- - - -
- - )} -
- ) -} - -interface InputRowProps { - label: string - icon: React.ReactNode -} - -export const InputRow: FunctionComponent = ({ - children, - icon, - label, -}) => { - return ( - - ) -} - -export default NotificationsCard diff --git a/components/NotificationsCard/phoneUtils.tsx b/components/NotificationsCard/phoneUtils.tsx deleted file mode 100644 index 95746b2fa5..0000000000 --- a/components/NotificationsCard/phoneUtils.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { parsePhoneNumber } from 'libphonenumber-js' - -type PhoneData = { - countryCode: string - baseNumber: string -} - -export const splitPhoneNumber = (phoneNumber: string): PhoneData => { - const { country: countryCode, nationalNumber: baseNumber } = parsePhoneNumber( - phoneNumber - ) - if (!countryCode || !baseNumber) { - throw new Error('No country or phone found') - } - - return { baseNumber, countryCode } -} diff --git a/components/NotificationsSwitch/NotifiIconDark.tsx b/components/NotificationsSwitch/NotifiIconDark.tsx deleted file mode 100644 index 7e18a4ff2e..0000000000 --- a/components/NotificationsSwitch/NotifiIconDark.tsx +++ /dev/null @@ -1,37 +0,0 @@ -const NotifiIconDark = ({ height, width }) => { - return ( - - - - - - - - - - - ) -} - -export default NotifiIconDark diff --git a/components/NotificationsSwitch/NotifiIconLight.tsx b/components/NotificationsSwitch/NotifiIconLight.tsx deleted file mode 100644 index cfdf44e1cf..0000000000 --- a/components/NotificationsSwitch/NotifiIconLight.tsx +++ /dev/null @@ -1,37 +0,0 @@ -const NotifiIconLight = ({ height, width }) => { - return ( - - - - - - - - - - - ) -} - -export default NotifiIconLight diff --git a/components/NotificationsSwitch/TelegramIcon.tsx b/components/NotificationsSwitch/TelegramIcon.tsx deleted file mode 100644 index 7661c4f62f..0000000000 --- a/components/NotificationsSwitch/TelegramIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import * as React from 'react' -import { SVGProps } from 'react' - -const SvgComponent = (props: SVGProps) => ( - - - -) - -export default SvgComponent diff --git a/components/NotificationsSwitch/index.tsx b/components/NotificationsSwitch/index.tsx deleted file mode 100644 index 5835b00afd..0000000000 --- a/components/NotificationsSwitch/index.tsx +++ /dev/null @@ -1,210 +0,0 @@ -import Button from '@components/Button' -import NotifiIcon from '@components/NotifiIcon' -import { defaultVariables } from '@dialectlabs/react-ui' -import styled from '@emotion/styled' -import { Transition } from '@headlessui/react' -import { DeviceMobileIcon } from '@heroicons/react/outline' -import { BellIcon, KeyIcon, MailIcon } from '@heroicons/react/solid' - -import { useEffect, useRef, useState } from 'react' -import useNotificationStore, { ModalStates } from 'stores/useNotificationStore' - -import DialectNotificationsModal from '@components/DialectNotificationsModal' -import NotificationCardContainer from '@components/NotificationsCard/NotificationCardContainer' -import TelegramIcon from './TelegramIcon' - -function useOutsideAlerter( - ref: React.MutableRefObject, - bellRef: React.MutableRefObject, - setOpen: CallableFunction -) { - useEffect(() => { - /** - * Alert if clicked on outside of element - */ - function handleClickOutside(event: MouseEvent) { - if ( - ref.current && - !ref?.current.contains(event.target as Element) && - bellRef.current && - !bellRef?.current.contains(event.target as Element) - ) { - setOpen(false) - } - } - - // Bind the event listener - document.addEventListener('mousedown', handleClickOutside) - return () => { - // Unbind the event listener on clean up - document.removeEventListener('mousedown', handleClickOutside) - } - }, [ref, bellRef, setOpen]) -} - -const TagToIcon = { - Email: , - NotifiCenter: , - Telegram: , - Text: , - Wallet: , -} - -type ChannelType = 'Wallet' | 'Email' | 'Text' | 'Telegram' | 'Notifi Center' - -interface NotificationSolutionType { - name: string - channels: ChannelType[] - description: string - modalState: ModalStates -} - -const NotificationSolutions: NotificationSolutionType[] = [ - { - channels: ['Wallet', 'Email', 'Text', 'Telegram'], - description: `Get notifications when new proposals are created & when proposals are completed or canceled. By wallet, email, Telegram or text message.`, - modalState: ModalStates.Dialect, - name: 'Dialect', - }, - { - channels: ['Email', 'Text', 'Telegram', 'Notifi Center'], - description: ` - Get notifications for proposals, voting, and results. Add your email address, phone number, and/or Telegram.`, - modalState: ModalStates.Notifi, - name: 'notifi', - }, -] - -export default function NotificationsSwitch() { - const { modalState, set: setNotificationStore } = useNotificationStore( - (s) => s - ) - - const wrapperRef = useRef(null) - const bellRef = useRef(null) - const [openModal, setOpenModal] = useState(false) - useOutsideAlerter(wrapperRef, bellRef, setOpenModal) - - const StyledChannelName = styled.span` - font-size: 0.8rem; - white-space: nowrap; - ` - - const removeSpaces = (str: string): string => { - return str.split(' ').join('') - } - - const formatName = (str: string): string => { - return str[0].toUpperCase() + str.substring(1) - } - - const Tag = ({ channelName }: { channelName: ChannelType }) => { - return ( - -
- {TagToIcon[removeSpaces(channelName)]} - {channelName} -
-
- ) - } - - const NotificationBox = ({ - channels, - description, - modalState, - name, - }: NotificationSolutionType) => ( -
-
-
- {name === 'notifi' && } -

{name}

-
-
- {channels.map((channel) => ( - - ))} -
- -
-
-

{description}

-
-
- -
- -
-
-
- ) - - const DialectBellIcon = defaultVariables.dark.icons.bell - - return ( -
- - {modalState === ModalStates.Selection && ( -
-
-

Realms Notifications

- {NotificationSolutions.map((solution) => ( - - ))} -
-
- )} - - {modalState === ModalStates.Dialect && ( - { - setOpenModal(false) - }} - onBackClick={() => - setNotificationStore((state) => { - state.modalState = ModalStates.Selection - }) - } - /> - )} - {modalState === ModalStates.Notifi && ( - setOpenModal(!openModal)} - onBackClick={() => - setNotificationStore((state) => { - state.modalState = ModalStates.Selection - }) - } - /> - )} -
- -
- ) -} diff --git a/components/PageBodyContainer.tsx b/components/PageBodyContainer.tsx index ae6b27969f..5f3ee13697 100644 --- a/components/PageBodyContainer.tsx +++ b/components/PageBodyContainer.tsx @@ -1,10 +1,19 @@ import { useRouter } from 'next/router' import Footer from '@components/Footer' +import {PluginDebug} from "../VoterWeightPlugins/lib/PluginDebug"; +import React from "react"; const PageBodyContainer = ({ children }) => { - const { pathname } = useRouter() + const { pathname, query } = useRouter() const isNewRealmsWizard = /\/realms\/new\/\w+/.test(pathname) + // TODO TEMP DEBUG - REMOVE BEFORE MERGE + if ( + query['debug'] !== undefined + ) { + return + } + return ( <>
>() - -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 52c5b114b0..71085a4d26 100644 --- a/components/ProposalActions.tsx +++ b/components/ProposalActions.tsx @@ -17,10 +17,8 @@ import { Proposal } from '@solana/spl-governance' import { ProgramAccount } from '@solana/spl-governance' import { cancelProposal } from 'actions/cancelProposal' import { getProgramVersionForRealm } from '@models/registry/api' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import dayjs from 'dayjs' import { diffTime } from './ProposalRemainingVotingTime' -import { useMaxVoteRecord } from '@hooks/useMaxVoteRecord' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { proposalQueryKeys, @@ -38,6 +36,7 @@ import { InstructionDataWithHoldUpTime } from 'actions/createProposal' import { TransactionInstruction } from '@solana/web3.js' import useQueryContext from '@hooks/useQueryContext' import { useRouter } from 'next/router' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const ProposalActionsPanel = () => { const { propose } = useCreateProposal() @@ -56,11 +55,9 @@ const ProposalActionsPanel = () => { const hasVoteTimeExpired = useHasVoteTimeExpired(governance, proposal!) const connection = useLegacyConnectionContext() - const maxVoteRecordPk = useMaxVoteRecord()?.pubkey - const votePluginsClientMaxVoterWeight = useVotePluginsClientStore( - (s) => s.state.maxVoterWeight - ) - const maxVoterWeight = maxVoteRecordPk || votePluginsClientMaxVoterWeight + // TODO check the kind to be passed + const { maxVoterWeightPk } = useRealmVoterWeightPlugins() + const canFinalizeVote = hasVoteTimeExpired && proposal?.account.state === ProposalState.Voting const now = new Date().getTime() / 1000 // unix timestamp in seconds @@ -174,7 +171,7 @@ const ProposalActionsPanel = () => { rpcContext, governance?.account.realm, proposal, - maxVoterWeight, + maxVoterWeightPk, proposalOwner ) } @@ -259,12 +256,15 @@ 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, voteByCouncil: - proposal.account.governingTokenMint !== realmInfo.communityMint, + !realmInfo.communityMint || + !proposal.account.governingTokenMint.equals( + realmInfo.communityMint + ), instructionsData: transactions ? [ ...transactions.flatMap((tx) => @@ -282,7 +282,7 @@ const ProposalActionsPanel = () => { isValid: true, governance: undefined, customHoldUpTime: tx.account.holdUpTime, - chunkBy: 2, + chunkBy: 1, }, }) ) diff --git a/components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower.tsx b/components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower.tsx index 3ed4de72a6..992d0db0c8 100644 --- a/components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower.tsx +++ b/components/ProposalVotingPower/LockedCommunityNFTRecordVotingPower.tsx @@ -10,12 +10,12 @@ import { BN } from '@coral-xyz/anchor' import Link from 'next/link' import useQueryContext from '@hooks/useQueryContext' import InlineNotification from '@components/InlineNotification' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/tokenOwnerRecord' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useUserCommunityTokenOwnerRecord } from '@hooks/queries/tokenOwnerRecord' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' +import {useVotingClients} from "@hooks/useVotingClients"; interface Props { className?: string @@ -32,9 +32,8 @@ export default function LockedCommunityNFTRecordVotingPower(props: Props) { const wallet = useWalletOnePointOh() const connected = !!wallet?.connected const { data: tokenOwnerRecordPk } = useAddressQuery_CommunityTokenOwner() - const [currentClient] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - ]) + // this is only available for the community role as long as the rest of the hooks are hard-coding it + const votingClient = useVotingClients()('community') const [ loadingPositions, votingPower, @@ -50,10 +49,10 @@ export default function LockedCommunityNFTRecordVotingPower(props: Props) { ]) useEffect(() => { - if (currentClient.heliumVsrVotingPositions.length !== positions.length) { - propagatePositions({ votingClient: currentClient }) + if (votingClient.heliumVsrVotingPositions.length !== positions.length) { + propagatePositions({ votingClient }) } - }, [positions, currentClient, propagatePositions]) + }, [positions, votingClient, propagatePositions]) useEffect(() => { if (mint && votingPower) { diff --git a/components/ProposalVotingPower/LockedCommunityVotingPower.tsx b/components/ProposalVotingPower/LockedCommunityVotingPower.tsx index cafe39a128..d5178139a3 100644 --- a/components/ProposalVotingPower/LockedCommunityVotingPower.tsx +++ b/components/ProposalVotingPower/LockedCommunityVotingPower.tsx @@ -7,26 +7,38 @@ import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import { getMintMetadata } from '../instructions/programs/splToken' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' -import { useVsrGovpower } from '@hooks/queries/plugins/vsr' import VSRCommunityVotingPower from 'VoteStakeRegistry/components/TokenBalance/VSRVotingPower' import DepositCommunityTokensBtn from 'VoteStakeRegistry/components/TokenBalance/DepositCommunityTokensBtn' import useDelegators from '@components/VotePanel/useDelegators' +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {CalculatedWeight, VoterWeightPlugins} from "../../VoterWeightPlugins/lib/types"; +import { BN } from '@coral-xyz/anchor' interface Props { className?: string } +const findVSRVoterWeight = (calculatedVoterWeight: CalculatedWeight | undefined): BN|undefined => + calculatedVoterWeight?.details.find((detail) => detail.pluginName === 'VSR')?.pluginWeight ?? undefined; + +const isVSRLastVoterWeightPlugin = (plugins: VoterWeightPlugins | undefined) => plugins?.voterWeight[plugins.voterWeight.length - 1].name === 'VSR'; + 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() + const { totalCalculatedVoterWeight, isReady: votingPowerReady, plugins } = useRealmVoterWeightPlugins('community'); - const { - data: votingPowerResult, - isLoading: votingPowerLoading, - } = useVsrGovpower() - const votingPower = votingPowerResult?.result + // in case the VSR plugin is the last plugin, this is the final calculated voter weight. + // however, if it is one in a chain, we are just showing an intermediate calculation here. + // This affects how it appears in the UI + const votingPower = findVSRVoterWeight(totalCalculatedVoterWeight) + const isLastVoterWeightPlugin = isVSRLastVoterWeightPlugin(plugins); const isLoading = useDepositStore((s) => s.state.isLoading) @@ -41,7 +53,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 || !votingPowerReady || 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.
) : ( - + )} {depositAmount.isGreaterThan(0) && ( diff --git a/components/ProposalVotingPower/NftVotingPower.tsx b/components/ProposalVotingPower/NftVotingPower.tsx index b6d3ff6954..9ad5c03a43 100644 --- a/components/ProposalVotingPower/NftVotingPower.tsx +++ b/components/ProposalVotingPower/NftVotingPower.tsx @@ -1,28 +1,18 @@ /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ import classNames from 'classnames' import { BigNumber } from 'bignumber.js' -import { Transaction, TransactionInstruction } from '@solana/web3.js' -import { - SYSTEM_PROGRAM_ID, - withCreateTokenOwnerRecord, -} from '@solana/spl-governance' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' - -import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' +import { Transaction } from '@solana/web3.js' import Button from '@components/Button' -import { getVoterWeightRecord } from '@utils/plugin/accounts' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { sendTransaction } from '@utils/send' import VotingPowerPct from './VotingPowerPct' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { useUserCommunityTokenOwnerRecord } from '@hooks/queries/tokenOwnerRecord' import { useRealmQuery } from '@hooks/queries/realm' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' import useUserOrDelegator from '@hooks/useUserOrDelegator' -import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery' import { useConnection } from '@solana/wallet-adapter-react' import { useVotingNfts } from '@hooks/queries/plugins/nftVoter' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import {useJoinRealm} from "@hooks/useJoinRealm"; interface Props { className?: string @@ -36,50 +26,17 @@ const Join = () => { const wallet = useWalletOnePointOh() const connected = !!wallet?.connected const realm = useRealmQuery().data?.result + const { userNeedsTokenOwnerRecord, userNeedsVoterWeightRecords, handleRegister } = useJoinRealm(); - const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - - const handleRegister = async () => { - if (!realm || !wallet?.publicKey || !client.client) throw new Error() - - const programVersion = await fetchProgramVersion(connection, realm.owner) + const join = async () => { + if (!realm || !wallet?.publicKey) throw new Error() - const instructions: TransactionInstruction[] = [] - const { voterWeightPk } = await getVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - wallet.publicKey, - client.client.program.programId - ) - const createVoterWeightRecordIx = await (client.client as NftVoterClient).program.methods - .createVoterWeightRecord(wallet.publicKey) - .accounts({ - voterWeightRecord: voterWeightPk, - governanceProgramId: realm.owner, - realm: realm.pubkey, - realmGoverningTokenMint: realm.account.communityMint, - payer: wallet.publicKey, - systemProgram: SYSTEM_PROGRAM_ID, - }) - .instruction() - instructions.push(createVoterWeightRecordIx) - await withCreateTokenOwnerRecord( - instructions, - realm.owner, - programVersion, - realm.pubkey, - wallet.publicKey, - realm.account.communityMint, - wallet.publicKey - ) + const instructions = await handleRegister(); const transaction = new Transaction() transaction.add(...instructions) await sendTransaction({ - transaction: transaction, + transaction, wallet: wallet, connection: connection, signers: [], @@ -91,8 +48,8 @@ const Join = () => { return ( (actingAsWalletPk?.toString() === wallet?.publicKey?.toString() && connected && - !ownTokenRecord && ( - )) || @@ -103,20 +60,19 @@ const Join = () => { export default function NftVotingPower(props: Props) { const userPk = useUserOrDelegator() const nfts = useVotingNfts(userPk) - const { - result: votingPower, - loading: votingPowerLoading, - } = useGovernancePowerAsync('community') - const maxWeight = useNftPluginStore((s) => s.state.maxVoteRecord) + + const { isReady, totalCalculatedVoterWeight, calculatedMaxVoterWeight } = useRealmVoterWeightPlugins( + 'community', + ) const displayNfts = (nfts ?? []).slice(0, 3) const remainingCount = Math.max((nfts ?? []).length - 3, 0) - const max = maxWeight - ? new BigNumber(maxWeight.account.maxVoterWeight.toString()) + const max = calculatedMaxVoterWeight?.value + ? new BigNumber(calculatedMaxVoterWeight.value.toString()) : null - const amount = new BigNumber((votingPower ?? 0).toString()) + const amount = new BigNumber((totalCalculatedVoterWeight?.value ?? 0).toString()) - if (votingPowerLoading || nfts === undefined) { + if (!isReady || nfts === undefined) { return (
s.state.isLoading) + const { isReady } = useRealmVoterWeightPlugins(role) + const { result: ownVoterWeight } = useLegacyVoterWeight() + + const formattedTokenAmount = useMemo( + () => + mintInfo && ownVoterWeight?.communityTokenRecord + ? new BigNumber( + ownVoterWeight?.communityTokenRecord?.account?.governingTokenDepositAmount?.toString() + ) + .shiftedBy(-mintInfo.decimals) + .toFixed(2) + .toString() + : undefined, + [mintInfo, ownVoterWeight?.communityTokenRecord] + ) + + const relevantMint = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + + const tokenName = + getMintMetadata(relevantMint)?.name ?? realm?.account.name ?? '' + + const formattedTotal = useMemo( + () => + mintInfo && voterWeight?.value + ? new BigNumber(voterWeight?.value.toString()) + .shiftedBy(-mintInfo.decimals) + .toFixed(2) + .toString() + : undefined, + [mintInfo, voterWeight?.value] + ) + + if (isLoading || !isReady) { + return ( +
+ ) + } + + return ( +
+
+
+
+
+ {tokenName} + {role === 'council' ? ' Council' : ''} votes +
+
+

{formattedTotal ?? '0'}

+

+ ({formattedTokenAmount ?? '0'} tokens) +

+
+
+ {showDepositButton && ( +
+ +
+ )} +
+
+
+ ) +} diff --git a/components/ProposalVotingPower/QuadraticVotingInfoModal.tsx b/components/ProposalVotingPower/QuadraticVotingInfoModal.tsx new file mode 100644 index 0000000000..3f9ee6e488 --- /dev/null +++ b/components/ProposalVotingPower/QuadraticVotingInfoModal.tsx @@ -0,0 +1,90 @@ +import { useState } from 'react' + +import { InformationCircleIcon, UserGroupIcon } from '@heroicons/react/solid' +import Modal from '@components/Modal' + +interface QuadraticVotingInfoModalProps { + voteWeight: string + totalVoteWeight: string + totalMembers: number + tokenAmount: string +} + +export default function QuadraticVotingInfoModal({ + voteWeight, + totalVoteWeight, + totalMembers, + tokenAmount, +}: QuadraticVotingInfoModalProps) { + const [showQuadraticModal, setShowQuadraticModal] = useState(false) + + return ( +
+ + setShowQuadraticModal(true)} + /> + + {showQuadraticModal && ( + setShowQuadraticModal(false)} + isOpen={showQuadraticModal} + > +
+
+
+
+

+ {voteWeight ?? '0'} votes +

+

+ ({tokenAmount ?? '0'} tokens) +

+
+
+ +
+

{totalMembers} DAO members

+

holding {totalVoteWeight} tokens

+
+
+
+
+

What is Quadratic Voting?

+
+ Quadratic voting empowers individual voter groups, lessening + the influence of token-rich whales and giving more of a + proportional vote to smaller token holders. +
+
+
+
+
+

How is it calculated?

+
+ Quadratic voting is based on the square root of the amount of + tokens held by a member. The result is the number of{' '} + actual votes. +
+
+
+
+
+
Example Calculation:
+ +
+ 1 votes = 1 token +
+ 2 votes = 4 tokens +
3 votes = 9 tokens +
+
+
+
+
+ )} +
+ ) +} diff --git a/components/ProposalVotingPower/QuadraticVotingPower.tsx b/components/ProposalVotingPower/QuadraticVotingPower.tsx new file mode 100644 index 0000000000..b212c41949 --- /dev/null +++ b/components/ProposalVotingPower/QuadraticVotingPower.tsx @@ -0,0 +1,126 @@ +import classNames from 'classnames' +import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' + +import { GatewayStatus, useGateway } from '@civic/solana-gateway-react' +import { BN } from '@coral-xyz/anchor' +import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' +import { useRealmQuery } from '@hooks/queries/realm' +import { useDelegatorAwareVoterWeight } from '@hooks/useDelegatorAwareVoterWeight' +import { + useRealmVoterWeightPlugins, + useRealmVoterWeights, +} from '@hooks/useRealmVoterWeightPlugins' +import { BigNumber } from 'bignumber.js' +import { useMemo } from 'react' +import PluginVotingPower from './PluginVotingPower' +import QuadraticVotingInfoModal from './QuadraticVotingInfoModal' +import { useTokenOwnerRecordsForRealmQuery } from '@hooks/queries/tokenOwnerRecord' +import { Member } from '@utils/uiTypes/members' + +interface Props { + className?: string + role: 'community' | 'council' +} + +export default function QuadraticVotingPower({ role, className }: Props) { + const realm = useRealmQuery().data?.result + const { data: activeMembersData } = useTokenOwnerRecordsForRealmQuery() + const voterWeight = useDelegatorAwareVoterWeight(role) + + const mintInfo = useMintInfoByPubkeyQuery(realm?.account.communityMint).data + ?.result + + const activeMembers: Member[] | undefined = useMemo(() => activeMembersData?.map(member => ({ + walletAddress: member.account.governingTokenOwner.toBase58(), + communityVotes: new BN(0), + councilVotes: new BN(0) + })), [activeMembersData]) + + const isLoading = useDepositStore((s) => s.state.isLoading) + const { + isReady, + calculatedMaxVoterWeight, + plugins, + } = useRealmVoterWeightPlugins(role) + const { result: ownVoterWeight } = useLegacyVoterWeight() + + const formattedTokenAmount = useMemo( + () => + mintInfo && ownVoterWeight?.communityTokenRecord + ? new BigNumber( + ownVoterWeight?.communityTokenRecord?.account?.governingTokenDepositAmount?.toString() + ) + .shiftedBy(-mintInfo.decimals) + .toFixed(2) + .toString() + : undefined, + [mintInfo, ownVoterWeight?.communityTokenRecord] + ) + + const formattedMax = + mintInfo && calculatedMaxVoterWeight?.value + ? new BigNumber(calculatedMaxVoterWeight?.value.toString()) + .shiftedBy(-mintInfo.decimals) + .toString() + : undefined + + const formattedTotal = useMemo( + () => + mintInfo && voterWeight?.value + ? new BigNumber(voterWeight?.value.toString()) + .shiftedBy(-mintInfo.decimals) + .toFixed(2) + .toString() + : undefined, + [mintInfo, voterWeight?.value] + ) + + const { communityWeight, councilWeight } = useRealmVoterWeights() + const { gatewayStatus } = useGateway() + const isQVEnabled = plugins?.voterWeight.some((p) => p.name === 'QV') + const isGatewayEnabled = plugins?.voterWeight.some( + (p) => p.name === 'gateway' + ) + + const hasAnyVotingPower = + councilWeight?.value?.gt(new BN(0)) && communityWeight?.value?.gt(new BN(0)) + + if (isLoading || !isReady) { + return ( +
+ ) + } + + return ( +
+ {hasAnyVotingPower && isQVEnabled && ( +
+

Quadratic Voting

+ +
+ )} + { + // check if the last plugin is gateway to show the voting power + plugins?.voterWeight[plugins.voterWeight.length - 1].name === 'QV' && ( + + ) + } +
+ ) +} diff --git a/components/ProposalVotingPower/TokenHaverVotingPower.tsx b/components/ProposalVotingPower/TokenHaverVotingPower.tsx new file mode 100644 index 0000000000..6870c7e1a2 --- /dev/null +++ b/components/ProposalVotingPower/TokenHaverVotingPower.tsx @@ -0,0 +1,119 @@ +import classNames from 'classnames' +import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' + +import { getMintMetadata } from '@components/instructions/programs/splToken' +import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' +import { useRealmQuery } from '@hooks/queries/realm' +import { useDelegatorAwareVoterWeight } from '@hooks/useDelegatorAwareVoterWeight' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { BigNumber } from 'bignumber.js' +import clsx from 'clsx' +import { useMemo } from 'react' +import { useJoinRealm } from '@hooks/useJoinRealm' +import { sendTransaction } from '@utils/send' +import { Transaction } from '@solana/web3.js' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { useConnection } from '@solana/wallet-adapter-react' +import Button from '@components/Button' + +interface Props { + className?: string + role: 'community' | 'council' + showDepositButton?: boolean +} + +export default function TokenHaverVotingPower({ role, className }: Props) { + /** ideally this would all be removed and registration would be automatic upon acting */ + const wallet = useWalletOnePointOh() + const { connection } = useConnection() + const { + userNeedsTokenOwnerRecord, + userNeedsVoterWeightRecords, + handleRegister, + } = useJoinRealm() + const join = async () => { + const instructions = await handleRegister() + const transaction = new Transaction() + transaction.add(...instructions) + + await sendTransaction({ + transaction: transaction, + wallet: wallet!, + connection, + signers: [], + sendingMessage: `Registering`, + successMessage: `Registered`, + }) + } + const showJoinButton = + !!wallet?.connected && + (userNeedsTokenOwnerRecord || userNeedsVoterWeightRecords) + + /** */ + + const realm = useRealmQuery().data?.result + const voterWeight = useDelegatorAwareVoterWeight(role) + + const mintInfo = useMintInfoByPubkeyQuery(realm?.account.communityMint).data + ?.result + + const isLoading = useDepositStore((s) => s.state.isLoading) + const { isReady } = useRealmVoterWeightPlugins(role) + + const relevantMint = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + + const tokenName = + getMintMetadata(relevantMint)?.name ?? realm?.account.name ?? '' + + const formattedTotal = useMemo( + () => + mintInfo && voterWeight?.value + ? new BigNumber(voterWeight?.value.toString()) + .shiftedBy(-mintInfo.decimals) + .toFixed(0) + .toString() + : undefined, + [mintInfo, voterWeight?.value] + ) + + if (isLoading || !isReady) { + return ( +
+ ) + } + + return ( +
+
+
+
+
+
+ {tokenName} + {role === 'council' ? ' Council' : ''} votes +
+
+

+ {formattedTotal ?? '0'} +

+
+
+
+
+
+ {showJoinButton && ( + + )} +
+ ) +} diff --git a/components/QuorumProgress.tsx b/components/QuorumProgress.tsx index 489d3e49c8..7509d42f88 100644 --- a/components/QuorumProgress.tsx +++ b/components/QuorumProgress.tsx @@ -39,6 +39,7 @@ const QuorumProgress = ({ ).toLocaleString(undefined, { maximumFractionDigits: 0, })} ${(progress ?? 0) > 0 ? 'more' : ''} ${voteKindTitle} vote${ + //@ts-ignore (votesRequired ?? 0) > 1 ? 's' : '' } required`}

) : ( diff --git a/components/RealmHeader.tsx b/components/RealmHeader.tsx index f319c8d8cb..41f219c657 100644 --- a/components/RealmHeader.tsx +++ b/components/RealmHeader.tsx @@ -6,22 +6,20 @@ import Link from 'next/link' import useQueryContext from 'hooks/useQueryContext' import { ExternalLinkIcon } from '@heroicons/react/outline' import { getRealmExplorerHost } from 'tools/routing' - import { tryParsePublicKey } from '@tools/core/pubkey' import { useRealmQuery } from '@hooks/queries/realm' -import { useRealmConfigQuery } from '@hooks/queries/realmConfig' -import { NFT_PLUGINS_PKS } from '@constants/plugins' +import { useConnection } from '@solana/wallet-adapter-react' const RealmHeader = () => { const { fmtUrlWithCluster } = useQueryContext() const realm = useRealmQuery().data?.result - const config = useRealmConfigQuery().data?.result const { REALM } = process.env + const { connection } = useConnection() const { realmInfo, symbol, vsrMode } = useRealm() const explorerHost = getRealmExplorerHost(realmInfo) - const realmUrl = `https://${explorerHost}/#/realm/${realmInfo?.realmId.toBase58()}?programId=${realmInfo?.programId.toBase58()}` + const realmUrl = `https://${explorerHost}/account/${realmInfo?.realmId.toBase58()}${connection.rpcEndpoint.includes("devnet") ? "?cluster=devnet" : ""}` const [isBackNavVisible, setIsBackNavVisible] = useState(true) @@ -68,17 +66,6 @@ const RealmHeader = () => {
)}
- {(!config?.account.communityTokenConfig.voterWeightAddin || - NFT_PLUGINS_PKS.includes( - config?.account.communityTokenConfig.voterWeightAddin.toBase58() - )) && ( - - - - Members - - - )} {vsrMode === 'default' && ( @@ -90,6 +77,12 @@ const RealmHeader = () => { )} + + + + Members + + diff --git a/components/SelectPrimaryDelegators.tsx b/components/SelectPrimaryDelegators.tsx index 65435af856..6f58515587 100644 --- a/components/SelectPrimaryDelegators.tsx +++ b/components/SelectPrimaryDelegators.tsx @@ -22,7 +22,7 @@ const SelectPrimaryDelegators = () => { const walletId = wallet?.publicKey?.toBase58() 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/components/SendNft.tsx b/components/SendNft.tsx index 1ac4949ec8..255ee4df2b 100644 --- a/components/SendNft.tsx +++ b/components/SendNft.tsx @@ -1,10 +1,9 @@ import Button from '@components/Button' import Input from '@components/inputs/Input' -import useRealm from '@hooks/useRealm' import { PublicKey } from '@solana/web3.js' import { tryParseKey } from '@tools/validators/pubkey' import { abbreviateAddress } from '@utils/formatting' -import { useMemo, useState } from 'react' +import React, { useMemo, useState } from 'react' import { ArrowCircleDownIcon, ArrowCircleUpIcon, @@ -50,6 +49,7 @@ import { SUPPORT_CNFTS } from '@constants/flags' import clsx from 'clsx' import { getNetworkFromEndpoint } from '@utils/connection' import { buildTransferCnftInstruction } from '@hooks/instructions/useTransferCnftInstruction' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const SendNft = ({ initialNftAndGovernanceSelected, @@ -60,7 +60,6 @@ const SendNft = ({ }) => { const { connection } = useConnection() const realm = useRealmQuery().data?.result - const { canChooseWhoVote } = useRealm() const { propose } = useCreateProposal() const { canUseTransferInstruction } = useGovernanceAssets() const { fmtUrlWithCluster } = useQueryContext() @@ -75,7 +74,7 @@ const SendNft = ({ const [selectedGovernance, setSelectedGovernance] = useGovernanceSelect( initialNftAndGovernanceSelected?.[1] ) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [showOptions, setShowOptions] = useState(false) const [destination, setDestination] = useState('') const [title, setTitle] = useState('') @@ -283,13 +282,13 @@ const SendNft = ({ value={description} onChange={(evt) => setDescription(evt.target.value)} > - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - > + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/TermsPopup.tsx b/components/TermsPopup.tsx new file mode 100644 index 0000000000..a2360e0c6e --- /dev/null +++ b/components/TermsPopup.tsx @@ -0,0 +1,57 @@ +import Modal from "./Modal" +import Button, { SecondaryButton } from './Button' +import { useEffect, useState } from "react" +import { useRouter } from "next/router" + +const TermsPopupModal = () => { + const [openModal, setOpenModal] = useState(true) + const [isClient, setIsClient] = useState(false) + const router = useRouter() + + useEffect(() => { + setIsClient(true) + }, []) + + useEffect(() => { + if (localStorage) { + const isTermAccepted = typeof window !== "undefined" ? + localStorage.getItem("accept-terms") === "true" : + false + + if (isTermAccepted) { + setOpenModal(false) + } + } + }) + + const acceptTerms = () => { + localStorage.setItem("accept-terms", "true") + setOpenModal(false) + } + + const rejectTerms = () => { + localStorage.setItem("accept-terms", "false") + router.push("https://realms.today?terms=rejected") + } + + return ( + <> + {isClient && openModal ? + ( setOpenModal(false)} bgClickClose={false} hideClose={true}> +

+ The operating entity of this site and owner of the related intellectual property has + changed. The new operator is Realms Today Ltd. (the New Operator). We have accordingly + amended the Terms and the Private Policy governing the relationship between our users + and the New Operator. By clicking "accept", you represent and warrant that you agree to + the revised Terms and Private Policy. +

+
+ + Reject +
+
) : null + } + ) +} + +export default TermsPopupModal; \ No newline at end of file diff --git a/components/TokenBalance/ClaimUnreleasedNFTs.tsx b/components/TokenBalance/ClaimUnreleasedNFTs.tsx index 8c05dbdfa4..bc40cfdd23 100644 --- a/components/TokenBalance/ClaimUnreleasedNFTs.tsx +++ b/components/TokenBalance/ClaimUnreleasedNFTs.tsx @@ -1,17 +1,14 @@ import useRealm from '@hooks/useRealm' import { useEffect, useState } from 'react' -import { TransactionInstruction } from '@solana/web3.js' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' import { SecondaryButton } from '@components/Button' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' import { chunks } from '@utils/helpers' -import { getRegistrarPDA, getVoterWeightRecord } from '@utils/plugin/accounts' import { sendTransactionsV3, SequenceType, txBatchesToInstructionSetWithSigners, } from '@utils/sendTransactions' -import { ProposalState, getProposal } from '@solana/spl-governance' +import { ProgramAccount, Proposal, ProposalState, getProposal } from '@solana/spl-governance' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/tokenOwnerRecord' import { useRealmQuery } from '@hooks/queries/realm' @@ -22,9 +19,15 @@ import { proposalQueryKeys, useRealmProposalsQuery, } from '@hooks/queries/proposal' +import {useNftClient} from "../../VoterWeightPlugins/useNftClient"; const NFT_SOL_BALANCE = 0.0014616 +type NftRecordsSet = { + proposal: PublicKey, + records: PublicKey[] +} + const ClaimUnreleasedNFTs = ({ inAccountDetails, }: { @@ -37,9 +40,7 @@ const ClaimUnreleasedNFTs = ({ const [solToBeClaimed, setSolToBeClaimed] = useState(0) const ownNftVoteRecordsFilterd = ownNftVoteRecords const realm = useRealmQuery().data?.result - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const { nftClient } = useNftClient(); const { isNftMode } = useRealm() const { data: tokenOwnerRecord } = useAddressQuery_CommunityTokenOwner() @@ -49,63 +50,88 @@ const ClaimUnreleasedNFTs = ({ if (!wallet?.publicKey) throw new Error('no wallet') if (!realm) throw new Error() if (!tokenOwnerRecord) throw new Error() + if (!nftClient) throw new Error("not an NFT realm") setIsLoading(true) const instructions: TransactionInstruction[] = [] - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - client.client!.program.programId - ) - const { voterWeightPk } = await getVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - wallet.publicKey, - client.client!.program.programId - ) + const { registrar } = nftClient.getRegistrarPDA(realm.pubkey, realm.account.communityMint); + + const { voterWeightPk } = await nftClient.getVoterWeightRecordPDA(realm.pubkey, realm.account.communityMint, wallet.publicKey) const nfts = ownNftVoteRecordsFilterd.slice( 0, count ? count : ownNftVoteRecordsFilterd.length ) + + const fetchedProposals: ProgramAccount[] = []; + const nftRecordsSet: NftRecordsSet[] = []; + for (const i of nfts) { - const proposalQuery = await queryClient.fetchQuery({ - queryKey: proposalQueryKeys.byPubkey( - connection.rpcEndpoint, - i.account.proposal - ), - staleTime: 0, - queryFn: () => - asFindable(() => getProposal(connection, i.account.proposal))(), - }) - const proposal = proposalQuery.result + const isProposalFetched = fetchedProposals.find(proposal => proposal.pubkey.equals(i.account.proposal)) + let currentProposal: ProgramAccount | undefined; + + if (isProposalFetched) { + currentProposal = isProposalFetched + } else { + const proposalQuery = await queryClient.fetchQuery({ + queryKey: proposalQueryKeys.byPubkey( + connection.rpcEndpoint, + i.account.proposal + ), + staleTime: 0, + queryFn: () => + asFindable(() => getProposal(connection, i.account.proposal))(), + }) + currentProposal = proposalQuery.result + if (proposalQuery.result) { + fetchedProposals.push(proposalQuery.result) + nftRecordsSet.push({ + proposal: proposalQuery.result.pubkey, + records: [] + }) + } + } + if ( - proposal === undefined || - proposal.account.state === ProposalState.Voting + currentProposal === undefined || + currentProposal.account.state === ProposalState.Voting ) { // ignore this one as it's still in voting continue } - const relinquishNftVoteIx = await (client.client as NftVoterClient).program.methods - .relinquishNftVote() - .accounts({ - registrar, - voterWeightRecord: voterWeightPk, - governance: proposal.account.governance, - proposal: i.account.proposal, - voterTokenOwnerRecord: tokenOwnerRecord, - voterAuthority: wallet.publicKey, - voteRecord: i.publicKey, - beneficiary: wallet!.publicKey!, - }) - .remainingAccounts([ - { pubkey: i.publicKey, isSigner: false, isWritable: true }, - ]) - .instruction() - instructions.push(relinquishNftVoteIx) + const currentRecordsIndex = nftRecordsSet.findIndex(r => r.proposal.equals(currentProposal!.pubkey)) + nftRecordsSet[currentRecordsIndex].records.push(i.publicKey) + } + + for (const r of nftRecordsSet) { + const ixChunks = chunks(r.records, 25) + + for (const ix of ixChunks) { + const proposal = fetchedProposals.find(p => p.pubkey.equals(r.proposal)) + + const relinquishNftVoteIx = await nftClient.program.methods + .relinquishNftVote() + .accounts({ + registrar, + voterWeightRecord: voterWeightPk, + governance: proposal!.account.governance, + proposal: r.proposal, + voterTokenOwnerRecord: tokenOwnerRecord, + voterAuthority: wallet.publicKey!, + voteRecord: ix[0], + beneficiary: wallet!.publicKey!, + }) + .remainingAccounts(ix.map(c => ( + { pubkey: c, isSigner: false, isWritable: true } + ))) + .instruction() + + instructions.push(relinquishNftVoteIx) + } } + try { - const insertChunks = chunks(instructions, 10).map((txBatch, batchIdx) => { + const insertChunks = chunks(instructions, 1).map((txBatch, batchIdx) => { return { instructionsSet: txBatchesToInstructionSetWithSigners( txBatch, @@ -115,11 +141,13 @@ const ClaimUnreleasedNFTs = ({ sequenceType: SequenceType.Parallel, } }) + await sendTransactionsV3({ connection, wallet: wallet!, transactionInstructions: insertChunks, }) + setIsLoading(false) getNftsVoteRecord() } catch (e) { @@ -128,7 +156,7 @@ const ClaimUnreleasedNFTs = ({ } } const getNftsVoteRecord = async () => { - const nftClient = client.client as NftVoterClient + if (!nftClient) throw new Error("not an NFT realm"); const nftVoteRecords = await nftClient.program.account.nftVoteRecord?.all([ { memcmp: { @@ -149,15 +177,16 @@ const ClaimUnreleasedNFTs = ({ proposal.account.state !== ProposalState.Voting ) }) + setOwnNftVoteRecords(nftVoteRecordsFiltered) setSolToBeClaimed(nftVoteRecordsFiltered.length * NFT_SOL_BALANCE) } useEffect(() => { - if (wallet?.publicKey && isNftMode && client.client) { + if (wallet?.publicKey && isNftMode && nftClient) { getNftsVoteRecord() } // 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 - }, [client.clientType, isNftMode, wallet?.publicKey?.toBase58()]) + }, [nftClient, isNftMode, wallet?.publicKey?.toBase58()]) if (isNftMode) { return ( diff --git a/components/TokenBalance/TokenBalanceCardWrapper.tsx b/components/TokenBalance/TokenBalanceCardWrapper.tsx index 8d50160098..75de2f2fa9 100644 --- a/components/TokenBalance/TokenBalanceCardWrapper.tsx +++ b/components/TokenBalance/TokenBalanceCardWrapper.tsx @@ -2,18 +2,23 @@ import useRealm from '@hooks/useRealm' import dynamic from 'next/dynamic' import { ChevronRightIcon } from '@heroicons/react/solid' import useQueryContext from '@hooks/useQueryContext' -import { GATEWAY_PLUGINS_PKS, NFT_PLUGINS_PKS } from '@constants/plugins' import GatewayCard from '@components/Gateway/GatewayCard' import ClaimUnreleasedNFTs from './ClaimUnreleasedNFTs' import Link from 'next/link' import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/tokenOwnerRecord' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useUserCommunityTokenOwnerRecord } from '@hooks/queries/tokenOwnerRecord' -import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import ClaimUnreleasedPositions from 'HeliumVotePlugin/components/ClaimUnreleasedPositions' import VanillaAccountDetails from './VanillaAccountDetails' import GovernancePowerCard from '@components/GovernancePower/GovernancePowerCard' import SelectPrimaryDelegators from '@components/SelectPrimaryDelegators' +import PythAccountDetails from 'PythVotePlugin/components/PythAccountDetails' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { ReactNode } from 'react' +import QuadraticVotingPower from '@components/ProposalVotingPower/QuadraticVotingPower' +import VanillaVotingPower from '@components/GovernancePower/Power/Vanilla/VanillaVotingPower' +import React from 'react' +import ParclAccountDetails from 'ParclVotePlugin/components/ParclAccountDetails' const LockPluginTokenBalanceCard = dynamic( () => @@ -65,36 +70,40 @@ const TokenBalanceCardInner = ({ inAccountDetails?: boolean }) => { const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result - const config = useRealmConfigQuery().data?.result + const { plugins } = useRealmVoterWeightPlugins('community') + const requiredCards = plugins?.voterWeight.map((plugin) => plugin.name) - const { vsrMode } = useRealm() - const currentPluginPk = config?.account?.communityTokenConfig.voterWeightAddin - const isNftMode = - currentPluginPk && NFT_PLUGINS_PKS.includes(currentPluginPk?.toBase58()) - const isGatewayMode = - currentPluginPk && GATEWAY_PLUGINS_PKS.includes(currentPluginPk?.toBase58()) + const showHeliumCard = requiredCards?.includes('HeliumVSR') + const showDefaultVSRCard = requiredCards?.includes('VSR') + const showPythCard = requiredCards?.includes('pyth') + const showNftCard = requiredCards?.includes('NFT') + const showGatewayCard = requiredCards?.includes('gateway') + const showQvCard = requiredCards?.includes('QV') + const showParclCard = requiredCards?.includes('parcl'); - if (vsrMode === 'default' && inAccountDetails) { + if (showDefaultVSRCard && inAccountDetails) { return // does this ever actually occur in the component hierarchy? } + const cards: ReactNode[] = [] + if ( - vsrMode === 'helium' && + showHeliumCard && (!ownTokenRecord || ownTokenRecord.account.governingTokenDepositAmount.isZero()) ) { - return ( - <> + cards.push( + {!inAccountDetails && } - + ) } - if (isNftMode && inAccountDetails) { - return ( -
+ if (showNftCard && inAccountDetails) { + cards.push( +
@@ -104,14 +113,58 @@ const TokenBalanceCardInner = ({ ) } + if (showPythCard) { + cards.push( + + {inAccountDetails ? : } + + ) + } + + if (showGatewayCard) { + cards.push( + + {inAccountDetails ? ( + + ) : ( + + )} + + ) + } + + if (showQvCard) { + cards.push( + + {inAccountDetails && ( + <> + + + + )} + + ) + } + + if (showParclCard) { + cards.push( + + {!inAccountDetails && } + + + ) + } + //Default - return ( - <> - {inAccountDetails ? : } + if (cards.length === 0) { + cards.push( + + {inAccountDetails ? : } + + ) + } - {isGatewayMode && } - - ) + return <>{cards} } const TokenBalanceCardWrapper = ({ diff --git a/components/TokenBalance/TokenDeposit.tsx b/components/TokenBalance/TokenDeposit.tsx index ac8cc76d0e..ce6d35a150 100644 --- a/components/TokenBalance/TokenDeposit.tsx +++ b/components/TokenBalance/TokenDeposit.tsx @@ -1,34 +1,11 @@ -import { - ASSOCIATED_TOKEN_PROGRAM_ID, - MintInfo, - Token, - TOKEN_PROGRAM_ID, -} from '@solana/spl-token' -import { PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js' +import { MintInfo } from '@solana/spl-token' import BN from 'bn.js' import useRealm from '@hooks/useRealm' -import { - getProposal, - GoverningTokenType, - ProposalState, -} from '@solana/spl-governance' -import { getUnrelinquishedVoteRecords } from '@models/api' -import { withRelinquishVote } from '@solana/spl-governance' -import { withWithdrawGoverningTokens } from '@solana/spl-governance' -import { sendTransaction } from '@utils/send' -import { SecondaryButton } from '../Button' +import { GoverningTokenType } from '@solana/spl-governance' import { GoverningTokenRole } from '@solana/spl-governance' import { fmtMintAmount } from '@tools/sdk/units' import { getMintMetadata } from '../instructions/programs/splToken' -import { withFinalizeVote } from '@solana/spl-governance' -import { chunks } from '@utils/helpers' -import { getProgramVersionForRealm } from '@models/registry/api' -import { notify } from '@utils/notifications' -import { ExclamationIcon } from '@heroicons/react/outline' import { useEffect } from 'react' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { VSR_PLUGIN_PKS } from '@constants/plugins' -import { useMaxVoteRecord } from '@hooks/useMaxVoteRecord' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useUserCommunityTokenOwnerRecord, @@ -36,41 +13,41 @@ import { } from '@hooks/queries/tokenOwnerRecord' import { useRealmQuery } from '@hooks/queries/realm' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' -import { fetchGovernanceByPubkey } from '@hooks/queries/governance' -import { useConnection } from '@solana/wallet-adapter-react' -import queryClient from '@hooks/queries/queryClient' -import { proposalQueryKeys } from '@hooks/queries/proposal' -import asFindable from '@utils/queries/asFindable' -import VanillaVotingPower from '@components/GovernancePower/Vanilla/VanillaVotingPower' -import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount' +import VanillaVotingPower from '@components/GovernancePower/Power/Vanilla/VanillaVotingPower' import { DepositTokensButton } from '@components/DepositTokensButton' +import VanillaWithdrawTokensButton from './VanillaWithdrawTokensButton' +import Button from '@components/Button' +import { useJoinRealm } from '@hooks/useJoinRealm' +import { Transaction } from '@solana/web3.js' +import { sendTransaction } from '@utils/send' +import { useConnection } from '@solana/wallet-adapter-react' +/** deposit + withdraw for vanilla govtokens, used only in account view. plugin views still use this for council. */ export const TokenDeposit = ({ mint, tokenRole, - councilVote, inAccountDetails, setHasGovPower, + hideVotes, }: { mint: MintInfo | undefined tokenRole: GoverningTokenRole - councilVote?: boolean inAccountDetails?: boolean setHasGovPower?: (hasGovPower: boolean) => void + hideVotes?: boolean }) => { const wallet = useWalletOnePointOh() const connected = !!wallet?.connected - const { connection } = useConnection() - - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - - const maxVoterWeight = useMaxVoteRecord()?.pubkey || undefined + const { + userNeedsTokenOwnerRecord, + userNeedsVoterWeightRecords, + handleRegister, + } = useJoinRealm() const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result const ownCouncilTokenRecord = useUserCouncilTokenOwnerRecord().data?.result const realm = useRealmQuery().data?.result const config = useRealmConfigQuery().data?.result + const { connection } = useConnection() const relevantTokenConfig = tokenRole === GoverningTokenRole.Community @@ -79,13 +56,7 @@ export const TokenDeposit = ({ const isMembership = relevantTokenConfig?.tokenType === GoverningTokenType.Membership - const { - realmInfo, - realmTokenAccount, - councilTokenAccount, - toManyCommunityOutstandingProposalsForUser, - toManyCouncilOutstandingProposalsForUse, - } = useRealm() + const { realmTokenAccount, councilTokenAccount } = useRealm() const depositTokenRecord = tokenRole === GoverningTokenRole.Community @@ -108,152 +79,6 @@ export const TokenDeposit = ({ tokenRole === GoverningTokenRole.Community ? '' : 'Council' }` - const withdrawAllTokens = async function () { - const instructions: TransactionInstruction[] = [] - // If there are unrelinquished votes for the voter then let's release them in the same instruction as convenience - if (depositTokenRecord!.account!.unrelinquishedVotesCount > 0) { - const voteRecords = await getUnrelinquishedVoteRecords( - connection, - realmInfo!.programId, - depositTokenRecord!.account!.governingTokenOwner - ) - - for (const voteRecord of Object.values(voteRecords)) { - const proposalQuery = await queryClient.fetchQuery({ - queryKey: proposalQueryKeys.byPubkey( - connection.rpcEndpoint, - voteRecord.account.proposal - ), - staleTime: 0, - queryFn: () => - asFindable(() => - getProposal(connection, voteRecord.account.proposal) - )(), - }) - const proposal = proposalQuery.result - if (!proposal) { - continue - } - - if (proposal.account.state === ProposalState.Voting) { - if (proposal.account.state === ProposalState.Voting) { - const governance = ( - await fetchGovernanceByPubkey( - connection, - proposal.account.governance - ) - ).result - if (!governance) throw new Error('failed to fetch governance') - if (proposal.account.getTimeToVoteEnd(governance.account) > 0) { - // Note: It's technically possible to withdraw the vote here but I think it would be confusing and people would end up unconsciously withdrawing their votes - notify({ - type: 'error', - message: `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on. Please withdraw your vote first`, - }) - throw new Error( - `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on. Please withdraw your vote first` - ) - } else { - // finalize proposal before withdrawing tokens so we don't stop the vote from succeeding - await withFinalizeVote( - instructions, - realmInfo!.programId, - getProgramVersionForRealm(realmInfo!), - realm!.pubkey, - proposal.account.governance, - proposal.pubkey, - proposal.account.tokenOwnerRecord, - proposal.account.governingTokenMint, - maxVoterWeight - ) - } - } - } - // Note: We might hit single transaction limits here (accounts and size) if user has too many unrelinquished votes - // It's not going to be an issue for now due to the limited number of proposals so I'm leaving it for now - // As a temp. work around I'm leaving the 'Release Tokens' button on finalized Proposal to make it possible to release the tokens from one Proposal at a time - await withRelinquishVote( - instructions, - realmInfo!.programId, - realmInfo!.programVersion!, - realmInfo!.realmId, - proposal.account.governance, - proposal.pubkey, - depositTokenRecord!.pubkey, - proposal.account.governingTokenMint, - voteRecord.pubkey, - depositTokenRecord!.account.governingTokenOwner, - wallet!.publicKey! - ) - await client.withRelinquishVote( - instructions, - proposal, - voteRecord.pubkey, - depositTokenRecord!.pubkey - ) - } - } - - const ataPk = await Token.getAssociatedTokenAddress( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - depositMint!, - wallet!.publicKey!, - true - ) - const ata = await fetchTokenAccountByPubkey(connection, ataPk) - - if (!ata.found) { - const ataIx = Token.createAssociatedTokenAccountInstruction( - ASSOCIATED_TOKEN_PROGRAM_ID, - TOKEN_PROGRAM_ID, - depositMint!, - ataPk, - wallet!.publicKey!, - wallet!.publicKey! // fee payer - ) - instructions.push(ataIx) - } - - await withWithdrawGoverningTokens( - instructions, - realmInfo!.programId, - realmInfo!.programVersion!, - realm!.pubkey, - depositTokenAccount?.publicKey - ? depositTokenAccount!.publicKey - : new PublicKey(ataPk), - depositTokenRecord!.account.governingTokenMint, - wallet!.publicKey! - ) - - try { - // use chunks of 8 here since we added finalize, - // because previously 9 withdraws used to fit into one tx - const ixChunks = chunks(instructions, 8) - for (const [index, chunk] of ixChunks.entries()) { - const transaction = new Transaction().add(...chunk) - await sendTransaction({ - connection, - wallet: wallet!, - transaction, - sendingMessage: - index == ixChunks.length - 1 - ? 'Withdrawing tokens' - : `Releasing tokens (${index}/${ixChunks.length - 2})`, - successMessage: - index == ixChunks.length - 1 - ? 'Tokens have been withdrawn' - : `Released tokens (${index}/${ixChunks.length - 2})`, - }) - } - } catch (ex) { - //TODO change to more friendly notification - notify({ type: 'error', message: `${ex}` }) - console.error("Can't withdraw tokens", ex) - } - } - const hasTokensInWallet = depositTokenAccount && depositTokenAccount.account.amount.gt(new BN(0)) @@ -261,16 +86,6 @@ export const TokenDeposit = ({ depositTokenRecord && depositTokenRecord.account.governingTokenDepositAmount.gt(new BN(0)) - const withdrawTooltipContent = !connected - ? 'Connect your wallet to withdraw' - : !hasTokensDeposited - ? "You don't have any tokens deposited to withdraw." - : !councilVote && - (toManyCouncilOutstandingProposalsForUse || - toManyCommunityOutstandingProposalsForUser) - ? 'You have to many outstanding proposals to withdraw.' - : '' - const availableTokens = depositTokenRecord && mint ? fmtMintAmount( @@ -279,6 +94,21 @@ export const TokenDeposit = ({ ) : '0' + const join = async () => { + const instructions = await handleRegister() + const transaction = new Transaction() + transaction.add(...instructions) + + await sendTransaction({ + transaction: transaction, + wallet: wallet!, + connection, + signers: [], + sendingMessage: `Registering`, + successMessage: `Registered`, + }) + } + useEffect(() => { if (availableTokens != '0' || hasTokensDeposited || hasTokensInWallet) { if (setHasGovPower) setHasGovPower(true) @@ -292,12 +122,15 @@ export const TokenDeposit = ({ : hasTokensInWallet ? availableTokens : 0 - const isVsr = - config?.account?.communityTokenConfig?.voterWeightAddin && - VSR_PLUGIN_PKS.includes( - config?.account?.communityTokenConfig?.voterWeightAddin?.toBase58() - ) && - tokenRole === GoverningTokenRole.Community + + // There are two buttons available on this UI: + // The Deposit button - available if you have tokens to deposit + // The Join button - available if you have already deposited tokens (you have a Token Owner Record) + // but you may not have all your Voter Weight Records yet. + // This latter case may occur if the DAO changes its configuration and new Voter Weight Records are required. + // For example if a new plugin is added. + const showJoinButton = + !userNeedsTokenOwnerRecord && userNeedsVoterWeightRecords // Do not show deposits for mints with zero supply because nobody can deposit anyway if (!mint || mint.supply.isZero()) { @@ -306,7 +139,7 @@ export const TokenDeposit = ({ return (
- {(availableTokens != '0' || inAccountDetails) && ( + {(availableTokens != '0' || inAccountDetails) && !hideVotes && (
{tokenRole === GoverningTokenRole.Community ? ( @@ -316,57 +149,42 @@ export const TokenDeposit = ({
)} - { - <> -
- You have {tokensToShow} {hasTokensDeposited ? `more ` : ``} - {depositTokenName} tokens available to deposit. -
- -
- {hasTokensInWallet || inAccountDetails ? ( - - ) : null} - {!isMembership && // Membership tokens can't be withdrawn (that is their whole point, actually) - (inAccountDetails || isVsr) && ( - - Withdraw - - )} -
- - } - {isVsr && ( - - - Please withdraw your tokens and deposit again to get governance power - - )} +
+ You have {tokensToShow} {hasTokensDeposited ? `more ` : ``} + {depositTokenName} tokens available to deposit. +
+ +
+ {connected && showJoinButton ? ( + + ) : hasTokensInWallet || inAccountDetails ? ( + + ) : null} + {!isMembership && // Membership tokens can't be withdrawn (that is their whole point, actually) + inAccountDetails && ( + + )} +
) } diff --git a/components/TokenBalance/VanillaAccountDetails.tsx b/components/TokenBalance/VanillaAccountDetails.tsx index 7d35da1b41..0004c0bea2 100644 --- a/components/TokenBalance/VanillaAccountDetails.tsx +++ b/components/TokenBalance/VanillaAccountDetails.tsx @@ -34,7 +34,6 @@ const VanillaAccountDetails = () => { )} @@ -42,7 +41,6 @@ const VanillaAccountDetails = () => { )} diff --git a/components/TokenBalance/VanillaWithdrawTokensButton.tsx b/components/TokenBalance/VanillaWithdrawTokensButton.tsx new file mode 100644 index 0000000000..eb4fc438ee --- /dev/null +++ b/components/TokenBalance/VanillaWithdrawTokensButton.tsx @@ -0,0 +1,331 @@ +import { + ASSOCIATED_TOKEN_PROGRAM_ID, + Token, + TOKEN_PROGRAM_ID, +} from '@solana/spl-token' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' +import BN from 'bn.js' +import useRealm from '@hooks/useRealm' +import { + getProposal, + Governance, + GoverningTokenType, + ProgramAccount, +} from '@solana/spl-governance' +import { getProposalsAtVotingStateByTOR, getUnrelinquishedVoteRecords } from '@models/api' +import { withRelinquishVote } from '@solana/spl-governance' +import { withWithdrawGoverningTokens } from '@solana/spl-governance' +import { SecondaryButton } from '../Button' +import { withFinalizeVote } from '@solana/spl-governance' +import { chunks } from '@utils/helpers' +import { getProgramVersionForRealm } from '@models/registry/api' +import { notify } from '@utils/notifications' +import { useMaxVoteRecord } from '@hooks/useMaxVoteRecord' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { + useUserCommunityTokenOwnerRecord, + useUserCouncilTokenOwnerRecord, +} from '@hooks/queries/tokenOwnerRecord' +import { useRealmQuery } from '@hooks/queries/realm' +import { useRealmConfigQuery } from '@hooks/queries/realmConfig' +import { fetchGovernanceByPubkey } from '@hooks/queries/governance' +import { useConnection } from '@solana/wallet-adapter-react' +import queryClient from '@hooks/queries/queryClient' +import { proposalQueryKeys } from '@hooks/queries/proposal' +import asFindable from '@utils/queries/asFindable' +import { fetchTokenAccountByPubkey } from '@hooks/queries/tokenAccount' +import {useVotingClients} from "@hooks/useVotingClients"; +import { sendTransactionsV3, SequenceType } from '@utils/sendTransactions' +import { useState } from 'react' + +// TODO make this have reasonable props +// TODO, also just refactor it +const VanillaWithdrawTokensButton = ({ + role, +}: { + role: 'community' | 'council' +}) => { + const [disableButton, setDisableButton] = useState(false) + const wallet = useWalletOnePointOh() + const connected = !!wallet?.connected + const { connection } = useConnection() + const maxVoterWeight = useMaxVoteRecord()?.pubkey || undefined + const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result + const ownCouncilTokenRecord = useUserCouncilTokenOwnerRecord().data?.result + const realm = useRealmQuery().data?.result + const config = useRealmConfigQuery().data?.result + const votingClient = useVotingClients()(role); + + const relevantTokenConfig = + role === 'community' + ? config?.account.communityTokenConfig + : config?.account.councilTokenConfig + const isMembership = + relevantTokenConfig?.tokenType === GoverningTokenType.Membership + + const { + realmInfo, + realmTokenAccount, + councilTokenAccount, + toManyCommunityOutstandingProposalsForUser, + toManyCouncilOutstandingProposalsForUse, + } = useRealm() + + const depositTokenRecord = + role === 'community' ? ownTokenRecord : ownCouncilTokenRecord + + const depositTokenAccount = + role === 'community' ? realmTokenAccount : councilTokenAccount + + const depositMint = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + + const vetoMint = + role === 'community' + ? realm?.account.config.councilMint + : realm?.account.communityMint + + const withdrawAllTokens = async function () { + const instructions: TransactionInstruction[] = [] + setDisableButton(true) + + try { + if (depositTokenRecord!.account!.unrelinquishedVotesCount > 0) { + const voteRecords = await getUnrelinquishedVoteRecords( + connection, + realmInfo!.programId, + depositTokenRecord!.account!.governingTokenOwner + ) + + for (const voteRecord of Object.values(voteRecords)) { + const proposalQuery = await queryClient.fetchQuery({ + queryKey: proposalQueryKeys.byPubkey( + connection.rpcEndpoint, + voteRecord.account.proposal + ), + staleTime: 0, + queryFn: () => + asFindable(() => + getProposal(connection, voteRecord.account.proposal) + )(), + }) + + const proposal = proposalQuery.result + if (!proposal) { + continue + } + + if (voteRecord.account.vote?.veto) { + if (vetoMint && !proposal.account.governingTokenMint.equals(vetoMint)) { + continue; + } + } else { + if (!proposal.account.governingTokenMint.equals(depositMint!)) { + continue; + } + } + + const governance = ( + await fetchGovernanceByPubkey( + connection, + proposal.account.governance + ) + ).result + + if (!governance) throw new Error('failed to fetch governance') + + if (!governance.account.realm.equals(realm!.pubkey)) { + continue + } + + if (proposal.account.getTimeToVoteEnd(governance.account) > 0) { + notify({ + type: 'error', + message: `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on. Please withdraw your vote first`, + }) + throw new Error( + `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on. Please withdraw your vote first` + ) + } else { + await withRelinquishVote( + instructions, + realmInfo!.programId, + realmInfo!.programVersion!, + realmInfo!.realmId, + proposal.account.governance, + proposal.pubkey, + depositTokenRecord!.pubkey, + depositMint!, + voteRecord.pubkey, + depositTokenRecord!.account.governingTokenOwner, + wallet!.publicKey! + ) + await votingClient.withRelinquishVote( + instructions, + proposal, + voteRecord.pubkey, + depositTokenRecord!.pubkey + ) + } + } + } + + if (depositTokenRecord!.account.outstandingProposalCount > 0) { + const activeProposals = await getProposalsAtVotingStateByTOR( + connection, + realmInfo!.programId, + depositTokenRecord!.pubkey + ) + + for (const proposal of Object.values(activeProposals)) { + const fetchedGovernances: ProgramAccount[] = [] + const isGovernanceFetched = fetchedGovernances.find(governance => governance.pubkey.equals(proposal.pubkey)) + + const currentGovernance = isGovernanceFetched ? isGovernanceFetched : ( + await fetchGovernanceByPubkey( + connection, + proposal.account.governance + ) + ).result + + if (!currentGovernance) throw new Error('failed to fetch governance') + + if(fetchedGovernances.indexOf(currentGovernance) === -1) { + fetchedGovernances.push(currentGovernance) + } + + if (proposal.account.getTimeToVoteEnd(currentGovernance.account) > 0) { + notify({ + type: 'error', + message: `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on.`, + }) + throw new Error( + `Can't withdraw tokens while Proposal ${proposal.account.name} is being voted on.` + ) + } else { + await withFinalizeVote( + instructions, + realmInfo!.programId, + getProgramVersionForRealm(realmInfo!), + realm!.pubkey, + proposal.account.governance, + proposal.pubkey, + proposal.account.tokenOwnerRecord, + proposal.account.governingTokenMint, + maxVoterWeight + ) + } + } + } + + const ataPk = await Token.getAssociatedTokenAddress( + ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + depositMint!, + wallet!.publicKey!, + true + ) + const ata = await fetchTokenAccountByPubkey(connection, ataPk) + + if (!ata.found) { + const ataIx = Token.createAssociatedTokenAccountInstruction( + ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + depositMint!, + ataPk, + wallet!.publicKey!, + wallet!.publicKey! // fee payer + ) + instructions.push(ataIx) + } + + await withWithdrawGoverningTokens( + instructions, + realmInfo!.programId, + realmInfo!.programVersion!, + realm!.pubkey, + depositTokenAccount?.publicKey + ? depositTokenAccount!.publicKey + : new PublicKey(ataPk), + depositTokenRecord!.account.governingTokenMint, + wallet!.publicKey! + ) + + // Force the UI to recalculate voter weight + queryClient.invalidateQueries({ + queryKey: ['calculateVoterWeight'], + }) + + + try { + const ixChunks = chunks(instructions, 8) + for (const chunk of ixChunks.values()) { + const txes = [chunk].map((txBatch) => { + return { + instructionsSet: txBatch.map((x) => { + return { + transactionInstruction: x, + } + }), + sequenceType: SequenceType.Sequential, + } + }) + + await sendTransactionsV3({ + connection, + wallet: wallet!, + transactionInstructions: txes + }) + } + setDisableButton(false) + } catch (ex) { + setDisableButton(false) + //TODO change to more friendly notification + notify({ type: 'error', message: `${ex}` }) + console.error("Can't withdraw tokens", ex) + } + } catch(e) { + setDisableButton(false) + notify({ type: 'error', message: `${e}` }) + console.error("Can't withdraw tokens", e) + } + } + + + const hasTokensDeposited = + depositTokenRecord && + depositTokenRecord.account.governingTokenDepositAmount.gt(new BN(0)) + + const withdrawTooltipContent = !connected + ? 'Connect your wallet to withdraw' + : !hasTokensDeposited + ? "You don't have any tokens deposited to withdraw." + : role === 'community' && + (toManyCouncilOutstandingProposalsForUse || + toManyCommunityOutstandingProposalsForUser) + ? 'You have to many outstanding proposals to withdraw.' + : '' + + return ( + + Withdraw + + ) +} +export default VanillaWithdrawTokensButton diff --git a/components/TransactionLoader.tsx b/components/TransactionLoader.tsx index bd4dfb0aa2..ca01c57f53 100644 --- a/components/TransactionLoader.tsx +++ b/components/TransactionLoader.tsx @@ -48,7 +48,9 @@ const TransactionLoader = () => {
Error
-
{error}
+
+ {error} +
diff --git a/components/TreasuryAccount/ConvertToMsol.tsx b/components/TreasuryAccount/ConvertToMsol.tsx index 81bf6fc693..15ec4be60f 100644 --- a/components/TreasuryAccount/ConvertToMsol.tsx +++ b/components/TreasuryAccount/ConvertToMsol.tsx @@ -3,7 +3,7 @@ import useTreasuryAccountStore from 'stores/useTreasuryAccountStore' import AccountLabel from './AccountHeader' import GovernedAccountSelect from 'pages/dao/[symbol]/proposal/components/GovernedAccountSelect' import useGovernanceAssets from '@hooks/useGovernanceAssets' -import { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import { StakingViewForm, UiInstruction, @@ -27,10 +27,11 @@ import { AssetAccount } from '@utils/uiTypes/assets' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const ConvertToMsol = () => { const realm = useRealmQuery().data?.result - const { canChooseWhoVote, symbol } = useRealm() + const {symbol } = useRealm() const { canUseTransferInstruction } = useGovernanceAssets() const { governedTokenAccounts } = useGovernanceAssets() const { fmtUrlWithCluster } = useQueryContext() @@ -51,7 +52,7 @@ const ConvertToMsol = () => { description: '', }) const [showOptions, setShowOptions] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [isLoading, setIsLoading] = useState(false) const mSolTokenAccounts = governedTokenAccounts.filter( @@ -223,13 +224,13 @@ const ConvertToMsol = () => { }) } > - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - > + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/TreasuryAccount/ConvertToStSol.tsx b/components/TreasuryAccount/ConvertToStSol.tsx index 2a154c8f94..0fdef041b7 100644 --- a/components/TreasuryAccount/ConvertToStSol.tsx +++ b/components/TreasuryAccount/ConvertToStSol.tsx @@ -3,7 +3,7 @@ import useTreasuryAccountStore from 'stores/useTreasuryAccountStore' import AccountLabel from './AccountHeader' import GovernedAccountSelect from 'pages/dao/[symbol]/proposal/components/GovernedAccountSelect' import useGovernanceAssets from '@hooks/useGovernanceAssets' -import { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import { StakingViewForm, UiInstruction, @@ -32,6 +32,7 @@ import { LIDO_PROGRAM_ID, LIDO_PROGRAM_ID_DEVNET, } from '@constants/pubkeys/lido' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; const defaultFormState = { destinationAccount: undefined, @@ -55,7 +56,7 @@ const STSOL_MINT_DEVNET = '5nnLCgZn1EQaLj1ub8vYbQgBhkWi97x4JC5ARVPhci4V' const ConvertToStSol = () => { const realm = useRealmQuery().data?.result - const { canChooseWhoVote, symbol } = useRealm() + const {symbol } = useRealm() const { canUseTransferInstruction } = useGovernanceAssets() const { governedTokenAccounts } = useGovernanceAssets() const { fmtUrlWithCluster } = useQueryContext() @@ -72,7 +73,7 @@ const ConvertToStSol = () => { ) const [form, setForm] = useState(defaultFormState) const [showOptions, setShowOptions] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [isLoading, setIsLoading] = useState(false) const mintMinAmount = form.governedTokenAccount?.extensions?.mint @@ -260,13 +261,13 @@ const ConvertToStSol = () => { }) } /> - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - /> + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/TreasuryAccount/HoldTokensTotalPrice.tsx b/components/TreasuryAccount/HoldTokensTotalPrice.tsx index 040ed1ca7e..963a41c543 100644 --- a/components/TreasuryAccount/HoldTokensTotalPrice.tsx +++ b/components/TreasuryAccount/HoldTokensTotalPrice.tsx @@ -1,11 +1,14 @@ import { useTotalTreasuryPrice } from '@hooks/useTotalTreasuryPrice' +import { formatNumber } from '@utils/formatNumber' + const HoldTokensTotalPrice = () => { - const { totalPriceFormatted } = useTotalTreasuryPrice() + const { totalPriceFormatted, isFetching } = useTotalTreasuryPrice() + return (

Treasury Balance

- ${totalPriceFormatted ? totalPriceFormatted : 0} + {isFetching ? 'Fetching ...' : `$${formatNumber(totalPriceFormatted)}`}
) diff --git a/components/TreasuryAccount/MangoModal.tsx b/components/TreasuryAccount/MangoModal.tsx index cc02cd6ba9..fec0b5f447 100644 --- a/components/TreasuryAccount/MangoModal.tsx +++ b/components/TreasuryAccount/MangoModal.tsx @@ -1,6 +1,12 @@ -import { Group, MangoAccount } from '@blockworks-foundation/mango-v4' +import { + Group, + MangoAccount, + USDC_MINT, + toUiDecimals, + toNative, +} from '@blockworks-foundation/mango-v4' import AdditionalProposalOptions from '@components/AdditionalProposalOptions' -import Button from '@components/Button' +import Button, { LinkButton } from '@components/Button' import Input from '@components/inputs/Input' import Select from '@components/inputs/Select' import { BN } from '@coral-xyz/anchor' @@ -16,141 +22,337 @@ import { AccountMeta, PublicKey } from '@solana/web3.js' import { AssetAccount } from '@utils/uiTypes/assets' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import Tooltip from '@components/Tooltip' +import { + getMintDecimalAmount, + getMintMinAmountAsDecimal, +} from '@tools/sdk/units' +import BigNumber from 'bignumber.js' +import { precision } from '@utils/formatting' +import * as yup from 'yup' +import tokenPriceService from '@utils/services/tokenPrice' +import { validateInstruction } from '@utils/instructionTools' +import Switch from '@components/Switch' +import { InstructionDataWithHoldUpTime } from 'actions/createProposal' +import ProgramSelector from '@components/Mango/ProgramSelector' +import useProgramSelector from '@components/Mango/useProgramSelector' +import ButtonGroup from '@components/ButtonGroup' + +enum ProposalType { + DEPOSIT = 'Deposit', + WITHDRAW = 'Withdraw', +} +import { useVoteByCouncilToggle } from '@hooks/useVoteByCouncilToggle' const MangoModal = ({ account }: { account: AssetAccount }) => { - const { mangoClient, mangoGroup } = UseMangoV4() + const { canUseTransferInstruction } = useGovernanceAssets() + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup, getMaxWithdrawForBank } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) const { fmtUrlWithCluster } = useQueryContext() const { handleCreateProposal } = useCreateProposal() const router = useRouter() const { symbol } = useRealm() - const [mangoAccount, setSelectedMangoAccount] = useState( - null + const [isProposing, setIsProposing] = useState(false) + const { voteByCouncil, setVoteByCouncil } = useVoteByCouncilToggle() + const [isLoadingMangoAccount, setIsLoadingMangoAccount] = useState( + true ) const [mangoAccounts, setMangoAccounts] = useState([]) - const [mangoAccName, setMangoAccName] = useState('') - const [isProposing, setIsProposing] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) - const [proposalTitle, setProposalTitle] = useState('Create mango account') - const [proposalDescription, setProposalDescription] = useState('') + const tabs = [ProposalType.DEPOSIT, ProposalType.WITHDRAW] + const [proposalType, setProposalType] = useState(ProposalType.DEPOSIT) + const [form, setForm] = useState<{ + mangoAccount: MangoAccount | null | undefined + accountName: string + amount: number + title: string + description: string + delegate: boolean + delegateWallet: string + }>({ + accountName: '', + title: '', + description: '', + amount: 0, + mangoAccount: undefined, + delegate: false, + delegateWallet: '', + }) + + const [formErrors, setFormErrors] = useState({}) + const [maxWithdrawBalance, setMaxWithdrawBalance] = useState(0) + + const handleSetForm = ({ propertyName, value }) => { + setForm({ ...form, [propertyName]: value }) + setFormErrors({}) + } + + useEffect(() => { + setForm({ ...form, mangoAccount: undefined }) + }, [programSelectorHook.program?.val.toBase58()]) + + useEffect(() => { + setFormErrors({}) + setForm({ + ...form, + accountName: '', + amount: 0, + mangoAccount: undefined, + title: `${proposalType} ${ + tokenPriceService.getTokenInfo( + account.extensions.mint!.publicKey.toBase58() + )?.symbol || 'tokens' + } ${proposalType === 'Withdraw' ? 'from' : 'to'} Mango`, + }) + }, [proposalType]) + + const SOL_BUFFER = 0.02 + + const treasuryAmount = new BN( + account.isSol + ? account.extensions.amount!.toNumber() + : account.extensions.token!.account.amount + ) + const mintInfo = account.extensions.mint!.account! + const mintMinAmount = mintInfo ? getMintMinAmountAsDecimal(mintInfo) : 1 + let maxAmount = mintInfo + ? getMintDecimalAmount(mintInfo, treasuryAmount) + : new BigNumber(0) + if (account.isSol) { + maxAmount = maxAmount.minus(SOL_BUFFER) + } + const maxAmountFtm = maxAmount.toNumber().toFixed(4) + const currentPrecision = precision(mintMinAmount) + + const schema = yup.object().shape({ + mangoAccount: yup + .object() + .nullable(true) + .test( + 'is-not-undefined', + 'Please select an Account', + (value) => value !== undefined + ), + accountName: yup.string().when('mangoAccount', { + is: null, + then: yup.string().required('Account name is required'), + otherwise: yup.string().notRequired(), + }), + title: yup.string().required('Title is required'), + amount: yup + .number() + .required('Amount is required') + .min(mintMinAmount) + .max( + proposalType === ProposalType.DEPOSIT + ? maxAmount.toNumber() + : maxWithdrawBalance + ), + delegate: yup.boolean().required('Delegate is required'), + delegateWallet: yup + .string() + .nullable() + .when('delegate', { + is: true, + then: yup.string().required('Delegate Wallet is required'), + otherwise: yup.string().notRequired(), + }), + }) + + useEffect(() => { + setMangoAccounts([]) + }, [programSelectorHook.program?.val]) + useEffect(() => { const getMangoAccounts = async () => { const accounts = await mangoClient?.getMangoAccountsForOwner( mangoGroup!, account.extensions.token!.account.owner! ) + if (accounts) { setMangoAccounts(accounts) } } - getMangoAccounts() - }, [mangoClient !== null && mangoGroup !== null]) + if (mangoClient && mangoGroup) { + setMangoAccounts([]) + setIsLoadingMangoAccount(true) + getMangoAccounts().then(() => setIsLoadingMangoAccount(false)) + } + }, [account.extensions.token, mangoClient, mangoGroup]) + + useEffect(() => { + if (proposalType === ProposalType.DEPOSIT) return + if (!mangoGroup || !form.mangoAccount) return + const bank = mangoGroup!.getFirstBankByMint( + account.extensions.mint!.publicKey! + ) + const maxWithdrawForBank = getMaxWithdrawForBank( + mangoGroup, + bank, + form.mangoAccount + ) + setMaxWithdrawBalance(maxWithdrawForBank.toNumber()) + }, [proposalType, mangoGroup, form]) + const handleCreateAccount = async () => { + const isValid = await validateInstruction({ schema, form, setFormErrors }) + if (!isValid) return + try { setIsProposing(true) - const newAccountNum = getNextAccountNumber(mangoAccounts) + const instructions: InstructionDataWithHoldUpTime[] = [] + let mangoAccountPk = form.mangoAccount?.publicKey const bank = mangoGroup!.getFirstBankByMint( account.extensions.mint!.publicKey! ) - const createAccIx = await mangoClient!.program.methods - .accountCreate( - newAccountNum, - 8, - 4, - 4, - 32, - mangoAccName || `Account ${newAccountNum + 1}` - ) - .accounts({ - group: mangoGroup!.publicKey, - owner: account.extensions.token!.account.owner!, - payer: account.extensions.token!.account.owner!, - }) - .instruction() - - const acctNumBuffer = Buffer.alloc(4) - acctNumBuffer.writeUInt32LE(newAccountNum) - - const [mangoAccount] = PublicKey.findProgramAddressSync( - [ - Buffer.from('MangoAccount'), - mangoGroup!.publicKey.toBuffer(), - account.extensions.token!.account.owner!.toBuffer(), - acctNumBuffer, - ], - mangoClient!.programId - ) - const depositIx = await mangoClient!.program.methods - .tokenDeposit(new BN(100000000000), false) - .accounts({ - group: mangoGroup!.publicKey, - account: mangoAccount, - owner: account.extensions.token!.account.owner!, - bank: bank.publicKey, - vault: bank.vault, - oracle: bank.oracle, - tokenAccount: account.pubkey, - tokenAuthority: account.extensions.token!.account.owner!, - }) - .remainingAccounts( - [bank.publicKey, bank.oracle].map( - (pk) => - ({ - pubkey: pk, - isWritable: false, - isSigner: false, - } as AccountMeta) + if (form.mangoAccount === null) { + const newAccountNum = getNextAccountNumber(mangoAccounts) + const createAccIx = await mangoClient!.program.methods + .accountCreate( + newAccountNum, + 8, + 4, + 4, + 32, + form.accountName || `Account ${newAccountNum + 1}` ) + .accounts({ + group: mangoGroup!.publicKey, + owner: account.extensions.token!.account.owner!, + payer: account.extensions.token!.account.owner!, + }) + .instruction() + + const createAccInstData = { + data: getInstructionDataFromBase64( + serializeInstructionToBase64(createAccIx) + ), + holdUpTime: + account?.governance.account?.config.minInstructionHoldUpTime, + prerequisiteInstructions: [], + chunkBy: 1, + } + + instructions.push(createAccInstData) + + const acctNumBuffer = Buffer.alloc(4) + acctNumBuffer.writeUInt32LE(newAccountNum) + + const [mangoAccount] = PublicKey.findProgramAddressSync( + [ + Buffer.from('MangoAccount'), + mangoGroup!.publicKey.toBuffer(), + account.extensions.token!.account.owner!.toBuffer(), + acctNumBuffer, + ], + mangoClient!.programId ) - .instruction() - - const delegateIx = await mangoClient!.program.methods - .accountEdit( - null, - new PublicKey('EsWMqyaEDoAqMgiWG9McSmpetBiYjL4VkHPkfevxKu4D'), - null, - null + mangoAccountPk = mangoAccount + } + + const tokens = toNative( + form.amount, + account.extensions.mint!.account!.decimals + ) + + if (proposalType === ProposalType.DEPOSIT) { + const methodByProposal = mangoClient!.program.methods.tokenDeposit + const methodByProposalInstruction = await methodByProposal( + tokens, + false ) - .accounts({ - group: mangoGroup!.publicKey, - account: mangoAccount, - owner: account.extensions.token!.account.owner!, - }) - .instruction() - - const createAccInstData = { - data: getInstructionDataFromBase64( - serializeInstructionToBase64(createAccIx) - ), - holdUpTime: - account?.governance.account?.config.minInstructionHoldUpTime, - prerequisiteInstructions: [], + .accounts({ + group: mangoGroup!.publicKey, + account: mangoAccountPk, + owner: account.extensions.token!.account.owner!, + bank: bank.publicKey, + vault: bank.vault, + oracle: bank.oracle, + tokenAccount: account.pubkey, + tokenAuthority: account.extensions.token!.account.owner!, + }) + .remainingAccounts( + [bank.publicKey, bank.oracle].map( + (pk) => + ({ + pubkey: pk, + isWritable: false, + isSigner: false, + } as AccountMeta) + ) + ) + .instruction() + + const depositAccInstData = { + data: getInstructionDataFromBase64( + serializeInstructionToBase64(methodByProposalInstruction!) + ), + holdUpTime: + account?.governance.account?.config.minInstructionHoldUpTime, + prerequisiteInstructions: [], + chunkBy: 1, + } + + instructions.push(depositAccInstData) } - const depositAccInstData = { - data: getInstructionDataFromBase64( - serializeInstructionToBase64(depositIx!) - ), - holdUpTime: - account?.governance.account?.config.minInstructionHoldUpTime, - prerequisiteInstructions: [], + + if (proposalType === ProposalType.WITHDRAW) { + const withdrawTxs = await mangoClient!.tokenWithdrawNativeIx( + mangoGroup!, + form.mangoAccount!, + account.extensions.mint!.publicKey!, + tokens, + false + ) + + for (const withdrawTx of withdrawTxs) { + const withdrawAccInsData = { + data: getInstructionDataFromBase64( + serializeInstructionToBase64(withdrawTx) + ), + holdUpTime: + account?.governance.account?.config.minInstructionHoldUpTime, + prerequisiteInstructions: [], + chunkBy: 1, + } + + instructions.push(withdrawAccInsData) + } } - const delegateAccInstData = { - data: getInstructionDataFromBase64( - serializeInstructionToBase64(delegateIx!) - ), - holdUpTime: - account?.governance.account?.config.minInstructionHoldUpTime, - prerequisiteInstructions: [], + + if (form.delegate) { + const delegateIx = await mangoClient!.program.methods + .accountEdit(null, new PublicKey(form.delegateWallet), null, null) + .accounts({ + group: mangoGroup!.publicKey, + account: mangoAccountPk, + owner: account.extensions.token!.account.owner!, + }) + .instruction() + + const delegateAccInstData = { + data: getInstructionDataFromBase64( + serializeInstructionToBase64(delegateIx!) + ), + holdUpTime: + account?.governance.account?.config.minInstructionHoldUpTime, + prerequisiteInstructions: [], + chunkBy: 1, + } + + instructions.push(delegateAccInstData) } + const proposalAddress = await handleCreateProposal({ - title: proposalTitle, - description: proposalDescription, + title: form.title, + description: form.description, voteByCouncil, - instructionsData: [ - createAccInstData, - depositAccInstData, - delegateAccInstData, - ], + instructionsData: instructions, governance: account.governance!, }) const url = fmtUrlWithCluster( @@ -162,66 +364,371 @@ const MangoModal = ({ account }: { account: AssetAccount }) => { } setIsProposing(false) } + return ( -
-

Mango

+
+
+ +
+

Mango

+
+
- {console.log(mangoAccount)} - {mangoGroup && ( - + } + placeholder={ + form.mangoAccount === undefined + ? 'Please select...' + : form.mangoAccount?.name || 'Create new account' + } + onChange={(value) => + handleSetForm({ + propertyName: 'mangoAccount', + value, + }) + } + > + {isLoadingMangoAccount && !mangoAccounts.length ? ( +
Loading accounts...
+ ) : ( + mangoAccounts.map((x) => ( + + + + )) + )} + + +
Create new account
- ))} - -
Create new account
-
- + + {form.mangoAccount === null && ( + + handleSetForm({ + propertyName: 'accountName', + value: e.target.value, + }) + } + /> + )} +
+ Amount +
+ {maxWithdrawBalance} + { + handleSetForm({ + propertyName: 'amount', + value: maxWithdrawBalance, + }) + }} + > + Max + +
+
+ + handleSetForm({ + propertyName: 'amount', + value: e.target.value, + }) + } + onBlur={() => { + handleSetForm({ + propertyName: 'amount', + value: parseFloat( + Math.max( + Number(mintMinAmount), + Math.min( + Number(Number.MAX_SAFE_INTEGER), + Number(form.amount) + ) + ).toFixed(currentPrecision) + ), + }) + }} + /> +
+

Delegate

+ + handleSetForm({ + propertyName: 'delegate', + value: !form.delegate, + }) + } + /> +
+ {form.delegate && ( + + handleSetForm({ + propertyName: 'delegateWallet', + value: e.target.value, + }) + } + /> + )} + { + handleSetForm({ + propertyName: 'title', + value: evt.target.value, + }) + }} + setDescription={(evt) => { + handleSetForm({ + propertyName: 'description', + value: evt.target.value, + }) + }} + voteByCouncil={voteByCouncil} + setVoteByCouncil={setVoteByCouncil} + /> +
+ +
+
)} - {!mangoAccount && ( - setMangoAccName(e.target.value)} - /> + {proposalType === ProposalType.DEPOSIT && ( +
+ {account.extensions.mint?.publicKey.toBase58() === + USDC_MINT.toBase58() && ( + + )} + + + {form.mangoAccount === null && ( + + handleSetForm({ + propertyName: 'accountName', + value: e.target.value, + }) + } + /> + )} +
+ Amount +
+ {maxAmountFtm} + { + handleSetForm({ + propertyName: 'amount', + value: maxAmount.toNumber(), + }) + }} + > + Max + +
+
+ + handleSetForm({ + propertyName: 'amount', + value: e.target.value, + }) + } + onBlur={() => { + handleSetForm({ + propertyName: 'amount', + value: parseFloat( + Math.max( + Number(mintMinAmount), + Math.min( + Number(Number.MAX_SAFE_INTEGER), + Number(form.amount) + ) + ).toFixed(currentPrecision) + ), + }) + }} + /> +
+

Delegate

+ + handleSetForm({ + propertyName: 'delegate', + value: !form.delegate, + }) + } + /> +
+ {form.delegate && ( + + handleSetForm({ + propertyName: 'delegateWallet', + value: e.target.value, + }) + } + /> + )} + { + handleSetForm({ + propertyName: 'title', + value: evt.target.value, + }) + }} + setDescription={(evt) => { + handleSetForm({ + propertyName: 'description', + value: evt.target.value, + }) + }} + voteByCouncil={voteByCouncil} + setVoteByCouncil={setVoteByCouncil} + /> +
+ +
+
)} - { - setProposalTitle(evt.target.value) - }} - setDescription={(evt) => setProposalDescription(evt.target.value)} - voteByCouncil={voteByCouncil} - setVoteByCouncil={setVoteByCouncil} - /> -
- -
) @@ -232,13 +739,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/TreasuryAccount/ProposalOptions.tsx b/components/TreasuryAccount/ProposalOptions.tsx index acd48ed0cf..f5597a7559 100644 --- a/components/TreasuryAccount/ProposalOptions.tsx +++ b/components/TreasuryAccount/ProposalOptions.tsx @@ -6,13 +6,13 @@ import React from 'react' const ProposalOptions: React.FC<{ handleSetForm: (obj: { propertyName: string; value: any }) => void form: any - canChooseWhoVote?: boolean + shouldShowVoteByCouncilToggle?: boolean voteByCouncil: boolean setVoteByCouncil: React.Dispatch> }> = ({ handleSetForm, form, - canChooseWhoVote, + shouldShowVoteByCouncilToggle, voteByCouncil, setVoteByCouncil, }) => { @@ -46,14 +46,14 @@ const ProposalOptions: React.FC<{ }) } > - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - > - )} + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > + )} ) } diff --git a/components/TreasuryAccount/SendTokens.tsx b/components/TreasuryAccount/SendTokens.tsx index f5db7c538b..5955daf8bd 100644 --- a/components/TreasuryAccount/SendTokens.tsx +++ b/components/TreasuryAccount/SendTokens.tsx @@ -11,16 +11,16 @@ import { } from '@tools/sdk/units' import { tryParseKey } from '@tools/validators/pubkey' import { debounce } from '@utils/debounce' -import { abbreviateAddress, precision } from '@utils/formatting' +import { precision } from '@utils/formatting' import { TokenProgramAccount, tryGetTokenAccount } from '@utils/tokens' import { SendTokenCompactViewForm, UiInstruction, } from '@utils/uiTypes/proposalCreationTypes' -import { useEffect, useState } from 'react' +import React, { ChangeEvent, useEffect, useState } from 'react' import useTreasuryAccountStore from 'stores/useTreasuryAccountStore' -import { getTokenTransferSchema } from '@utils/validations' +import { getBatchTokenTransferSchema } from '@utils/validations' import { ArrowCircleDownIcon, ArrowCircleUpIcon, @@ -37,8 +37,8 @@ import AccountLabel from './AccountHeader' import Tooltip from '@components/Tooltip' import useGovernanceAssets from '@hooks/useGovernanceAssets' import { - getSolTransferInstruction, - getTransferInstruction, + getBatchSolTransferInstruction, + getBatchTransferInstruction, } from '@utils/instructionTools' import VoteBySwitch from 'pages/dao/[symbol]/proposal/components/VoteBySwitch' import useCreateProposal from '@hooks/useCreateProposal' @@ -46,13 +46,15 @@ import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { fetchJupiterPrice } from '@hooks/queries/jupiterPrice' -import { useAsync } from 'react-async-hook' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; +import { AddAlt } from '@carbon/icons-react' +import { StyledLabel } from '@components/inputs/styles' const SendTokens = () => { const currentAccount = useTreasuryAccountStore((s) => s.currentAccount) const connection = useLegacyConnectionContext() const realm = useRealmQuery().data?.result - const { realmInfo, symbol, canChooseWhoVote } = useRealm() + const { realmInfo, symbol} = useRealm() const { handleCreateProposal } = useCreateProposal() const { canUseTransferInstruction } = useGovernanceAssets() const tokenInfo = useTreasuryAccountStore((s) => s.tokenInfo) @@ -62,25 +64,29 @@ const SendTokens = () => { const router = useRouter() const programId: PublicKey | undefined = realmInfo?.programId const [form, setForm] = useState({ - destinationAccount: '', - amount: undefined, + destinationAccount: [''], + txDollarAmount: [undefined], + amount: [undefined], governedTokenAccount: undefined, programId: programId?.toString(), mintInfo: undefined, title: '', description: '', }) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [showOptions, setShowOptions] = useState(false) const [ destinationAccount, setDestinationAccount, - ] = useState | null>(null) + ] = useState<(TokenProgramAccount | null)[]>([null]) + const [isLoading, setIsLoading] = useState(false) const [formErrors, setFormErrors] = useState({}) - const destinationAccountName = - destinationAccount?.publicKey && - getAccountName(destinationAccount?.account.address) + const destinationAccountName = destinationAccount.map(acc => ( + acc?.publicKey && + getAccountName(acc?.account.address) + )) + const mintMinAmount = form.governedTokenAccount?.extensions?.mint ? getMintMinAmountAsDecimal( form.governedTokenAccount.extensions.mint.account @@ -92,28 +98,64 @@ const SendTokens = () => { setFormErrors({}) setForm({ ...form, [propertyName]: value }) } - const setAmount = (event) => { + + const handleSetMultipleProps = ( + {destinationAccount, amount, txDollarAmount} : + {amount: any, txDollarAmount: any, destinationAccount?: any} + ) => { + setFormErrors({}) + + setForm({ ...form, + destinationAccount : destinationAccount ? destinationAccount : form.destinationAccount, + amount, + txDollarAmount + }) + } + + const setAmount = (idx: number, event: ChangeEvent) => { const value = event.target.value + const newAmounts: any[] = [...form.amount] + newAmounts[idx] = value + handleSetForm({ - value: value, + value: newAmounts, propertyName: 'amount', }) } - const validateAmountOnBlur = () => { - const value = form.amount - handleSetForm({ - value: parseFloat( - Math.max( - Number(mintMinAmount), - Math.min(Number(Number.MAX_SAFE_INTEGER), Number(value)) - ).toFixed(currentPrecision) - ), - propertyName: 'amount', + const validateAmountOnBlur = async(idx: number) => { + const value = form.amount[idx] + const newAmounts = [...form.amount] + const newTxDollars = [...form.txDollarAmount] + + const newVal = parseFloat( + Math.max( + Number(mintMinAmount), + Math.min(Number(Number.MAX_SAFE_INTEGER), Number(value)) + ).toFixed(currentPrecision) + ) + + newAmounts[idx] = newVal + + const mint = currentAccount?.extensions.mint?.publicKey + if (mint === undefined) { + newTxDollars[idx] = undefined + } else { + const priceData = await fetchJupiterPrice(mint) + const price = priceData.result?.price ?? 0 + + const totalPrice = newVal * price + const totalPriceFormatted = newVal && price ? new BigNumber(totalPrice).toFormat(2) : '' + newTxDollars[idx] = totalPriceFormatted + } + + handleSetMultipleProps({ + amount: newAmounts, + txDollarAmount: newTxDollars }) } - async function getInstruction(): Promise { + async function getInstruction(): Promise { const defaultProps = { schema, form, @@ -124,34 +166,37 @@ const SendTokens = () => { setFormErrors, } if (isSol) { - return getSolTransferInstruction(defaultProps) + return getBatchSolTransferInstruction(defaultProps) } - return getTransferInstruction(defaultProps) + return getBatchTransferInstruction(defaultProps) } const handleProposeTransfer = async () => { setIsLoading(true) - const instruction: UiInstruction = await getInstruction() - if (instruction.isValid) { + const instruction: UiInstruction[] = await getInstruction() + + if (instruction.every(ix => ix.isValid)) { const governance = currentAccount?.governance let proposalAddress: PublicKey | null = null if (!realm) { setIsLoading(false) throw 'No realm selected' } - const instructionData = { - data: instruction.serializedInstruction - ? getInstructionDataFromBase64(instruction.serializedInstruction) + const instructionsData = instruction.map(ix => ({ + data: ix.serializedInstruction + ? getInstructionDataFromBase64(ix.serializedInstruction) : null, holdUpTime: governance?.account?.config.minInstructionHoldUpTime, - prerequisiteInstructions: instruction.prerequisiteInstructions || [], - } + prerequisiteInstructions: ix.prerequisiteInstructions || [], + chunkBy: 4 + })) + try { proposalAddress = await handleCreateProposal({ title: form.title ? form.title : proposalTitle, description: form.description ? form.description : '', voteByCouncil, - instructionsData: [instructionData], + instructionsData, governance: governance!, }) const url = fmtUrlWithCluster( @@ -165,10 +210,10 @@ const SendTokens = () => { setIsLoading(false) } - const IsAmountNotHigherThenBalance = () => { + const IsAmountNotHigherThenBalance = (idx: number) => { try { const mintValue = getMintNaturalAmountFromDecimalAsBN( - form.amount!, + form.amount[idx]!, form.governedTokenAccount!.extensions.mint!.account.decimals ) let gte: boolean | undefined = false @@ -188,50 +233,66 @@ const SendTokens = () => { } // 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 }, [currentAccount]) - useEffect(() => { - if (form.destinationAccount) { - debounce.debounceFcn(async () => { - const pubKey = tryParseKey(form.destinationAccount) - if (pubKey) { - const account = await tryGetTokenAccount(connection.current, pubKey) - setDestinationAccount(account ? account : null) - } else { - setDestinationAccount(null) - } - }) - } else { - setDestinationAccount(null) - } - // 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.destinationAccount]) - const schema = getTokenTransferSchema({ form, connection, nftMode: false }) + const schema = getBatchTokenTransferSchema({ form, connection, nftMode: false }) - const { result: transactionDolarAmount } = useAsync(async () => { - const mint = currentAccount?.extensions.mint?.publicKey - if (mint === undefined) return undefined - const amount = form.amount ?? 0 - const priceData = await fetchJupiterPrice(mint) - const price = priceData.result?.price ?? 0 - - const totalPrice = amount * price - const totalPriceFormatted = - amount && price ? new BigNumber(totalPrice).toFormat(2) : '' - return totalPriceFormatted - }, [form.amount, currentAccount?.extensions.mint?.publicKey]) - - const proposalTitle = `Pay ${form.amount}${ - tokenInfo ? ` ${tokenInfo?.symbol} ` : ' ' - }to ${ - tryParseKey(form.destinationAccount) - ? abbreviateAddress(new PublicKey(form.destinationAccount)) - : '' - }` + const proposalTitle = `Transfer tokens` + // ${ + // tokenInfo ? ` ${tokenInfo?.symbol} ` : ' ' + // }to ${ + // tryParseKey(form.destinationAccount) + // ? abbreviateAddress(new PublicKey(form.destinationAccount)) + // : '' + // }` if (!currentAccount) { return null } + const addRecipient = () => { + const newAddresses = [...form.destinationAccount] + const newAmounts = [...form.amount] + const newTxDollars = [...form.txDollarAmount] + + newAddresses.push("") + newAmounts.push(undefined) + newTxDollars.push(undefined) + + handleSetMultipleProps({ + destinationAccount: newAddresses, + amount: newAmounts, + txDollarAmount: newTxDollars + }) + + const currentAccounts = [...destinationAccount] + currentAccounts.push(null) + setDestinationAccount(currentAccounts) + } + + const setAddress = (idx: number, address: string) => { + const newAddresses = [...form.destinationAccount] + newAddresses[idx] = address + + handleSetForm({ + value: newAddresses, + propertyName: 'destinationAccount', + }) + + const currentAccounts = [...destinationAccount] + + debounce.debounceFcn(async () => { + const pubKey = tryParseKey(address) + if (pubKey) { + const account = await tryGetTokenAccount(connection.current, pubKey) + currentAccounts[idx] = account ? account : null + setDestinationAccount(currentAccounts) + } else { + currentAccounts[idx] = null + setDestinationAccount(currentAccounts) + } + }) + } + return ( <>

@@ -239,53 +300,63 @@ const SendTokens = () => {

- - handleSetForm({ - value: evt.target.value, - propertyName: 'destinationAccount', - }) - } - noMaxWidth={true} - error={formErrors['destinationAccount']} - /> - {destinationAccount && ( -
-
Account owner
-
- {destinationAccount.account.owner.toString()} -
-
- )} - {destinationAccountName && ( -
-
Account name
-
{destinationAccountName}
-
- )} + {form.destinationAccount.map((acc, idx) => ( +
+ Recipient {idx+1} + setAddress(idx, e.target.value)} + noMaxWidth={true} + error={ + formErrors['destinationAccount'] && formErrors['destinationAccount'][idx] ? + formErrors['destinationAccount'][idx] : "" + } + /> + {destinationAccount[idx] && ( +
+
Account owner
+
+ {destinationAccount[idx]!.account.owner.toString()} +
+
+ )} + {destinationAccountName[idx] && ( +
+
Account name
+
{destinationAccountName[idx]}
+
+ )} - + setAmount(idx, e)} + step={mintMinAmount} + error={formErrors['amount'] && formErrors['amount'][idx] ? formErrors['amount'][idx] : ""} + onBlur={() => validateAmountOnBlur(idx)} + noMaxWidth={true} + /> - - {transactionDolarAmount - ? IsAmountNotHigherThenBalance() - ? `~$${transactionDolarAmount}` - : 'Insufficient balance' - : null} - + + {form.txDollarAmount[idx] + ? IsAmountNotHigherThenBalance(idx) + ? `~$${form.txDollarAmount[idx]}` + : 'Insufficient balance' + : null} + +
+ ))} +
+ +
Add another recipient
+
setShowOptions(!showOptions)} @@ -345,13 +416,13 @@ const SendTokens = () => { }) } > - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - > + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )} )} diff --git a/components/TreasuryAccount/Trade.tsx b/components/TreasuryAccount/Trade.tsx index c920505a8d..0d7151dc00 100644 --- a/components/TreasuryAccount/Trade.tsx +++ b/components/TreasuryAccount/Trade.tsx @@ -51,6 +51,7 @@ import { import { deriveAllBoundedStrategyKeysV2 } from '@utils/instructions/PsyFinance/poseidon' import { TokenInfo } from '@utils/services/types' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; type TradeProps = { tokenAccount: AssetAccount } @@ -173,7 +174,7 @@ const Trade: React.FC = ({ tokenAccount }) => { const { wallet, anchorProvider } = useWalletDeprecated() const { handleCreateProposal } = useCreateProposal() const { canUseTransferInstruction } = useGovernanceAssets() - const { canChooseWhoVote, symbol } = useRealm() + const {symbol } = useRealm() const { fmtUrlWithCluster } = useQueryContext() const [form, setForm] = useState({ amount: 0, @@ -190,7 +191,7 @@ const Trade: React.FC = ({ tokenAccount }) => { }) const [formErrors, setFormErrors] = useState({}) const [showOptions, setShowOptions] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [isLoading, setIsLoading] = useState(false) const [destinationToken, setDestinationToken] = useState() @@ -438,7 +439,7 @@ const Trade: React.FC = ({ tokenAccount }) => { diff --git a/components/VoteCommentModal.tsx b/components/VoteCommentModal.tsx index e5ea1e1c9d..6f0e337782 100644 --- a/components/VoteCommentModal.tsx +++ b/components/VoteCommentModal.tsx @@ -30,7 +30,7 @@ const VoteCommentModal: FunctionComponent = ({ isMulti, }) => { const [comment, setComment] = useState('') - const { submitting, submitVote } = useSubmitVote() + const { submitting, submitVote , error } = useSubmitVote() const voteString = VOTE_STRINGS[vote] @@ -39,9 +39,8 @@ const VoteCommentModal: FunctionComponent = ({ vote, comment, voteWeights: isMulti, - }) - - onClose() + }).then(() => onClose()) + .catch(console.log) } return ( @@ -62,6 +61,7 @@ const VoteCommentModal: FunctionComponent = ({ onChange={(e) => setComment(e.target.value)} // placeholder={`Let the DAO know why you vote '${voteString}'`} /> + {error &&

{error.message}

}
diff --git a/components/VotePanel/CastVoteButtons.tsx b/components/VotePanel/CastVoteButtons.tsx index 97b45d944e..e4c8e03471 100644 --- a/components/VotePanel/CastVoteButtons.tsx +++ b/components/VotePanel/CastVoteButtons.tsx @@ -1,13 +1,22 @@ -import { VoteKind } from '@solana/spl-governance' +import { VoteKind, getVoteRecordAddress } from '@solana/spl-governance' import { useState } from 'react' import { ThumbUpIcon, ThumbDownIcon } from '@heroicons/react/solid' import Button from '../Button' import VoteCommentModal from '../VoteCommentModal' import { useIsInCoolOffTime, useIsVoting, useVotingPop } from './hooks' -import { useProposalVoteRecordQuery } from '@hooks/queries/voteRecord' +import { + fetchVoteRecordByPubkey, + useProposalVoteRecordQuery, +} from '@hooks/queries/voteRecord' import { useSubmitVote } from '@hooks/useSubmitVote' import { useSelectedRealmInfo } from '@hooks/selectedRealm/useSelectedRealmRegistryEntry' import { useCanVote } from './useCanVote' +import { useConnection } from '@solana/wallet-adapter-react' +import { useAsync } from 'react-async-hook' +import { useRouteProposalQuery } from '@hooks/queries/proposal' +import { useBatchedVoteDelegators } from './useDelegators' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' export const CastVoteButtons = () => { const [showVoteModal, setShowVoteModal] = useState(false) @@ -23,6 +32,61 @@ export const CastVoteButtons = () => { const isVoting = useIsVoting() const isInCoolOffTime = useIsInCoolOffTime() + const proposal = useRouteProposalQuery().data?.result + const connection = useConnection() + const communityDelegators = useBatchedVoteDelegators('community') + const councilDelegators = useBatchedVoteDelegators('council') + + const wallet = useWalletOnePointOh() + + const { voterWeightForWallet } = useRealmVoterWeightPlugins(votingPop) + + const ownVoterWeight = wallet?.publicKey + ? voterWeightForWallet(wallet?.publicKey) + : undefined + const hasVotingPower = !!( + ownVoterWeight?.value && ownVoterWeight.value?.gtn(0) + ) + + const isDelegatorsVoteCast = useAsync(async () => { + const relevantDelegators = + votingPop === 'community' ? communityDelegators : councilDelegators + + if ( + !hasVotingPower && + proposal && + relevantDelegators && + relevantDelegators.length > 0 + ) { + const delegatorisVoteCastList = await Promise.all( + relevantDelegators.map(async (delegator) => { + const pda = await getVoteRecordAddress( + proposal.owner, + proposal.pubkey, + delegator.pubkey + ) + const voteRecord = await fetchVoteRecordByPubkey( + connection.connection, + pda + ) + return !!voteRecord.found + }) + ) + + // check if there is any delegator without a vote. If so, return false + const voted = !delegatorisVoteCastList.includes(false) + setVote(voted ? 'yes' : 'no') + return voted + } + }, [ + communityDelegators?.length, + connection.connection, + councilDelegators?.length, + hasVotingPower, + proposal?.pubkey, + votingPop, + ]) + const handleVote = async (vote: 'yes' | 'no') => { setVote(vote) @@ -34,8 +98,11 @@ export const CastVoteButtons = () => { }) } } + const isFinalVoteCast = + isVoteCast || hasVotingPower ? isVoteCast : isDelegatorsVoteCast.result - return (isVoting && !isVoteCast) || (isInCoolOffTime && !isVoteCast) ? ( + return (isVoting && !isFinalVoteCast) || + (isInCoolOffTime && !isFinalVoteCast) ? (

Cast your {votingPop} vote

diff --git a/components/VotePanel/VetoButtons.tsx b/components/VotePanel/VetoButtons.tsx index 334feabf40..97bf924cd2 100644 --- a/components/VotePanel/VetoButtons.tsx +++ b/components/VotePanel/VetoButtons.tsx @@ -13,7 +13,7 @@ import { import { useProposalVoteRecordQuery } from '@hooks/queries/voteRecord' import { useSubmitVote } from '@hooks/useSubmitVote' import { useSelectedRealmInfo } from '@hooks/selectedRealm/useSelectedRealmRegistryEntry' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const useIsVetoable = (): undefined | boolean => { const vetoingPop = useVetoingPop() @@ -30,7 +30,9 @@ const useCanVeto = (): | { canVeto: true } | { canVeto: false; message: string } => { const vetoPop = useVetoingPop() - const { result: govPower } = useGovernancePowerAsync(vetoPop) + const { calculatedMaxVoterWeight, isReady } = useRealmVoterWeightPlugins( + vetoPop + ) const wallet = useWalletOnePointOh() const connected = !!wallet?.connected const isVetoable = useIsVetoable() @@ -53,7 +55,8 @@ const useCanVeto = (): return { canVeto: false, message: 'You already voted' } // Do you have any voting power? - const hasMinAmountToVote = voterTokenRecord && govPower?.gtn(0) + const hasMinAmountToVote = + voterTokenRecord && isReady && calculatedMaxVoterWeight?.value?.gtn(0) if (hasMinAmountToVote === undefined) return undefined if (hasMinAmountToVote === false) return { diff --git a/components/VotePanel/YouVoted.tsx b/components/VotePanel/YouVoted.tsx index 0b1e5b3886..99dc5893e8 100644 --- a/components/VotePanel/YouVoted.tsx +++ b/components/VotePanel/YouVoted.tsx @@ -1,4 +1,10 @@ -import { GovernanceAccountType, VoteKind, VoteType, withFinalizeVote } from '@solana/spl-governance' +import { + GovernanceAccountType, + VoteKind, + VoteType, + getVoteRecordAddress, + withFinalizeVote, +} from '@solana/spl-governance' import { TransactionInstruction } from '@solana/web3.js' import { useState } from 'react' import { relinquishVote } from '../../actions/relinquishVote' @@ -13,13 +19,13 @@ import { } from '@heroicons/react/solid' import Button from '../Button' import { getProgramVersionForRealm } from '@models/registry/api' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import Tooltip from '@components/Tooltip' import { useVoterTokenRecord, useIsVoting, useIsInCoolOffTime, useUserVetoTokenRecord, + useVotingPop, } from './hooks' import assertUnreachable from '@utils/typescript/assertUnreachable' import { useHasVoteTimeExpired } from '@hooks/useHasVoteTimeExpired' @@ -31,15 +37,20 @@ import { useRouteProposalQuery, } from '@hooks/queries/proposal' import { useProposalGovernanceQuery } from '@hooks/useProposal' -import { useProposalVoteRecordQuery } from '@hooks/queries/voteRecord' +import { + fetchVoteRecordByPubkey, + useProposalVoteRecordQuery, +} from '@hooks/queries/voteRecord' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import queryClient from '@hooks/queries/queryClient' import { CheckmarkFilled } from '@carbon/icons-react' +import { useVotingClientForGoverningTokenMint } from '@hooks/useVotingClients' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import { useAsync } from 'react-async-hook' +import { useBatchedVoteDelegators } from './useDelegators' +import { useSelectedDelegatorStore } from 'stores/useSelectedDelegatorStore' export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) const proposal = useRouteProposalQuery().data?.result const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() @@ -60,6 +71,9 @@ export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { const vetoVotertokenRecord = useUserVetoTokenRecord() const voterTokenRecord = quorum === 'electoral' ? electoralVoterTokenRecord : vetoVotertokenRecord + const votingClient = useVotingClientForGoverningTokenMint( + proposal?.account.governingTokenMint + ) const isWithdrawEnabled = connected && @@ -131,7 +145,7 @@ export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { voterTokenRecord.pubkey, ownVoteRecord.pubkey, instructions, - client + votingClient ) queryClient.invalidateQueries({ queryKey: proposalQueryKeys.all(connection.endpoint), @@ -142,40 +156,129 @@ export const YouVoted = ({ quorum }: { quorum: 'electoral' | 'veto' }) => { setIsLoading(false) } - const vote = ownVoteRecord?.account.vote + const selectedCommunityDelegator = useSelectedDelegatorStore( + (s) => s.communityDelegator + ) + const selectedCouncilDelegator = useSelectedDelegatorStore( + (s) => s.councilDelegator + ) + + const communityDelegators = useBatchedVoteDelegators('community') + const councilDelegators = useBatchedVoteDelegators('council') + const votingPop = useVotingPop() + const { voterWeightForWallet } = useRealmVoterWeightPlugins(votingPop) + + const relevantSelectedDelegator = + votingPop === 'community' + ? selectedCommunityDelegator + : selectedCouncilDelegator + + const ownVoterWeight = relevantSelectedDelegator + ? voterWeightForWallet(relevantSelectedDelegator) + : wallet?.publicKey + ? voterWeightForWallet(wallet?.publicKey) + : undefined + const hasVotingPower = !!( + ownVoterWeight?.value && ownVoterWeight.value?.gtn(0) + ) + + const delegatorVote = useAsync(async () => { + const relevantDelegators = + votingPop === 'community' ? communityDelegators : councilDelegators + + if ( + !hasVotingPower && + proposal && + relevantDelegators && + relevantDelegators.length > 0 + ) { + const delegatorisVoteList = await Promise.all( + relevantDelegators.map(async (delegator) => { + const pda = await getVoteRecordAddress( + proposal.owner, + proposal.pubkey, + delegator.pubkey + ) + const voteRecord = await fetchVoteRecordByPubkey( + connection.current, + pda + ) + return voteRecord + }) + ) + + const allVoted = !delegatorisVoteList + .map((vote) => !!vote.found) + .includes(false) + return allVoted ? delegatorisVoteList[0].result : null + } + }, [ + communityDelegators?.length, + connection.current, + councilDelegators?.length, + hasVotingPower, + proposal?.pubkey, + votingPop, + ]) + + const getDelegatorVoteForQuorum = () => { + if ( + // yes/no vote + (quorum === 'electoral' && !delegatorVote?.result?.account.vote?.veto) || + // veto vote + (quorum === 'veto' && delegatorVote?.result?.account.vote?.veto) + ) { + return delegatorVote?.result?.account.vote + } + return undefined + } + + const vote = hasVotingPower + ? ownVoteRecord?.account.vote + : getDelegatorVoteForQuorum() + + const isMulti = + proposal?.account.voteType !== VoteType.SINGLE_CHOICE && + proposal?.account.accountType === GovernanceAccountType.ProposalV2 + + const nota = '$$_NOTA_$$' - const isMulti = proposal?.account.voteType !== VoteType.SINGLE_CHOICE - && proposal?.account.accountType === GovernanceAccountType.ProposalV2 - return vote !== undefined ? (

{quorum === 'electoral' ? 'Your vote' : 'You voted to veto'}

- {vote.voteType === VoteKind.Approve ? - isMulti ? - vote.approveChoices?.map((choice, index) => ( - choice.weightPercentage ? -
- + {vote.voteType === VoteKind.Approve ? ( + isMulti ? ( + vote.approveChoices?.map((choice, index) => + choice.weightPercentage ? ( +
+ +
+ ) : null + ) + ) : ( + +
+
- : null - )) - : ( - -
- -
-
+
+ ) ) : vote.voteType === VoteKind.Deny ? (
diff --git a/components/VotePanel/useCanVote.ts b/components/VotePanel/useCanVote.ts index 92f28762d1..80bb661c33 100644 --- a/components/VotePanel/useCanVote.ts +++ b/components/VotePanel/useCanVote.ts @@ -1,58 +1,41 @@ -import { useVoterTokenRecord, useVotingPop } from './hooks' -import { VotingClientType } from '@utils/uiTypes/VotePlugin' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' +import {useVoterTokenRecord, useVotingPop} from './hooks' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import { useProposalVoteRecordQuery } from '@hooks/queries/voteRecord' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' - -import { useBatchedVoteDelegators } from './useDelegators' +import {useProposalVoteRecordQuery} from '@hooks/queries/voteRecord' +import {useRealmVoterWeightPlugins} from '@hooks/useRealmVoterWeightPlugins' +import {useDelegatorAwareVoterWeight} from "@hooks/useDelegatorAwareVoterWeight"; const useHasAnyVotingPower = (role: 'community' | 'council' | undefined) => { - const { result: personalAmount } = useGovernancePowerAsync(role) - const relevantDelegators = useBatchedVoteDelegators(role) - - // notably, this is ignoring whether the delegators actually have voting power, but it's not a big deal - const canBatchVote = relevantDelegators && relevantDelegators?.length !== 0 - - // technically, if you have a TOR you can vote even if there's no power. But that doesnt seem user friendly. - const canPersonallyVote = - personalAmount === undefined ? undefined : personalAmount.isZero() === false - - const canVote = canBatchVote || canPersonallyVote - - return canVote + const voterWeight = useDelegatorAwareVoterWeight(role ?? 'community'); + const {isReady } = useRealmVoterWeightPlugins(role) + return isReady && !!voterWeight?.value && voterWeight.value?.isZero() === false } export const useCanVote = () => { - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const { isReady, includesPlugin } = useRealmVoterWeightPlugins() const votingPop = useVotingPop() const wallet = useWalletOnePointOh() const connected = !!wallet?.connected const { data: ownVoteRecord } = useProposalVoteRecordQuery('electoral') const voterTokenRecord = useVoterTokenRecord() + const { plugins } = useRealmVoterWeightPlugins(votingPop); + const hasAllVoterWeightRecords = (plugins?.voterWeight ?? []).every((plugin) => plugin.weights !== undefined) const isVoteCast = !!ownVoteRecord?.found const hasMinAmountToVote = useHasAnyVotingPower(votingPop) const canVote = connected && - !( - client.clientType === VotingClientType.NftVoterClient && !voterTokenRecord - ) && - !( - client.clientType === VotingClientType.HeliumVsrClient && - !voterTokenRecord - ) && + !(isReady && includesPlugin('NFT') && !voterTokenRecord) && + !(isReady && includesPlugin('HeliumVSR') && !voterTokenRecord) && + hasAllVoterWeightRecords && !isVoteCast && hasMinAmountToVote const voteTooltipContent = !connected ? 'You need to connect your wallet to be able to vote' - : client.clientType === VotingClientType.NftVoterClient && !voterTokenRecord + : isReady && includesPlugin('NFT') && !voterTokenRecord ? 'You must join the Realm to be able to vote' : !hasMinAmountToVote ? 'You don’t have governance power to vote in this dao' 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/DiscussionForm.tsx b/components/chat/DiscussionForm.tsx index 72ec6830d3..966f385287 100644 --- a/components/chat/DiscussionForm.tsx +++ b/components/chat/DiscussionForm.tsx @@ -8,7 +8,6 @@ import { postChatMessage } from '../../actions/chat/postMessage' import Loading from '../Loading' import Tooltip from '@components/Tooltip' import { getProgramVersionForRealm } from '@models/registry/api' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useUserCommunityTokenOwnerRecord, @@ -19,6 +18,7 @@ import { useRouteProposalQuery } from '@hooks/queries/proposal' import { useVotingPop } from '@components/VotePanel/hooks' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import {useVotingClients} from "@hooks/useVotingClients"; const DiscussionForm = () => { const [comment, setComment] = useState('') @@ -27,10 +27,9 @@ const DiscussionForm = () => { const realm = useRealmQuery().data?.result const { result: ownVoterWeight } = useLegacyVoterWeight() const { realmInfo } = useRealm() - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients(); const [submitting, setSubmitting] = useState(false) + const [error, setError] = useState('') const wallet = useWalletOnePointOh() const connected = !!wallet?.connected @@ -38,10 +37,14 @@ const DiscussionForm = () => { const proposal = useRouteProposalQuery().data?.result const tokenRole = useVotingPop() const commenterVoterTokenRecord = - tokenRole === 'community' ? ownTokenRecord : ownCouncilTokenRecord + tokenRole === 'community' ? + ownTokenRecord ?? ownCouncilTokenRecord : + ownCouncilTokenRecord + const votingClient = votingClients(tokenRole ?? 'community');// default to community if no role is provided const submitComment = async () => { setSubmitting(true) + setError('') if ( !realm || !proposal || @@ -72,12 +75,13 @@ const DiscussionForm = () => { commenterVoterTokenRecord, msg, undefined, - client + ownTokenRecord ? votingClient : undefined // use votingClient only if the community TOR is used for commenting ) setComment('') } catch (ex) { console.error("Can't post chat message", ex) + setError(ex.message); //TODO: How do we present transaction errors to users? Just the notification? } finally { setSubmitting(false) @@ -117,6 +121,7 @@ const DiscussionForm = () => {
+ {error &&

{error}

} ) } 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/inputs/TokenAmountInput.tsx b/components/inputs/TokenAmountInput.tsx index bace53255a..6f1173cf2f 100644 --- a/components/inputs/TokenAmountInput.tsx +++ b/components/inputs/TokenAmountInput.tsx @@ -1,8 +1,5 @@ -import { useMintInfoByPubkeyQuery } from '@hooks/queries/mintInfo' import { PublicKey } from '@solana/web3.js' -import { precision } from '@utils/formatting' -import BigNumber from 'bignumber.js' -import { FC, useMemo } from 'react' +import { FC } from 'react' import Input, { InputProps } from './Input' type Props = Omit< @@ -26,20 +23,6 @@ const TokenAmountInput: FC = ({ value, ...props }) => { - const { data: mintInfo } = useMintInfoByPubkeyQuery(mint) - - const mintMinAmount = useMemo( - () => - mintInfo?.result - ? new BigNumber(1).shiftedBy(mintInfo.result.decimals).toNumber() - : 1, - [mintInfo?.result] - ) - - const currentPrecision = useMemo(() => precision(mintMinAmount), [ - mintMinAmount, - ]) - const validateAmount = () => { if (value === undefined || value === '') { if (props.required) { @@ -50,16 +33,16 @@ const TokenAmountInput: FC = ({ setValue( Math.max( - Number(mintMinAmount), + 1, Math.min(Number(Number.MAX_SAFE_INTEGER), Number(value)) - ).toFixed(currentPrecision) + ).toFixed(0) ) } return ( = ({ setValue(e.target.value) setError(undefined) }} - step={mintMinAmount} + step={1} error={props.error} onBlur={(e) => { props.onBlur?.(e) diff --git a/components/instructions/programs/foresight.tsx b/components/instructions/programs/foresight.tsx deleted file mode 100644 index 6537d8f123..0000000000 --- a/components/instructions/programs/foresight.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import { Connection, PublicKey } from '@solana/web3.js' - -import { - consts, - generatedTypes, - generatedAccounts, -} from '@foresight-tmp/foresight-sdk' -import { AccountMetaData } from '@solana/spl-governance' -import { IDL } from '@foresight-tmp/foresight-sdk/' -import { layout as initCategoryLayout } from '@foresight-tmp/foresight-sdk/dist/generated/instructions/initCategory' -import { layout as initMarketListLayout } from '@foresight-tmp/foresight-sdk/dist/generated/instructions/initMarketList' -import { layout as initMarketLayout } from '@foresight-tmp/foresight-sdk/dist/generated/instructions/initMarket' -import { layout as writeToFieldMarketMetadataLayout } from '@foresight-tmp/foresight-sdk/dist/generated/instructions/writeToFieldMarketMetadata' -import { layout as resolveMarketLayout } from '@foresight-tmp/foresight-sdk/dist/generated/instructions/resolveMarket' - -function displayParsedArg(argName: string, parsed: string): JSX.Element { - return ( -

- {argName}: {parsed} -

- ) -} - -function numArrayToString(data: number[]): string { - return Buffer.from(data).toString() -} - -function parseMetadata( - metadata: generatedAccounts.MarketMetadata, - includeImage = true -): string { - const base = { - title: numArrayToString(metadata.title), - description: numArrayToString(metadata.description), - rules: numArrayToString(metadata.rules), - } - const maybeImageObj = includeImage - ? { image: numArrayToString(metadata.image) } - : {} - return JSON.stringify({ ...base, ...maybeImageObj }, null, 2) -} - -function toDecodable(data: Uint8Array): Buffer { - return Buffer.from(data.slice(8)) -} - -function decodeIxData(data: Uint8Array, layout: any): any { - return layout.decode(toDecodable(data)) -} - -function findAccounts(ixName: string): { name: string }[] { - return IDL.instructions - .find((ix) => ix.name === ixName)! - .accounts.map((acc) => { - return { name: acc.name } - }) -} - -async function fetchId( - connection: Connection, - pubkey: PublicKey, - accountType: - | typeof generatedAccounts.Category - | typeof generatedAccounts.MarketList -): Promise { - const account = await accountType.fetch(connection, pubkey) - return account === null ? 'Error: not found' : numArrayToString(account.id) -} - -async function fetchCategoryId( - connection: Connection, - pubkey: PublicKey -): Promise { - return await fetchId(connection, pubkey, generatedAccounts.Category) -} - -async function fetchMarketListId( - connection: Connection, - pubkey: PublicKey -): Promise { - return await fetchId(connection, pubkey, generatedAccounts.MarketList) -} - -export const FORESIGHT_INSTRUCTIONS = { - [consts.PROGRAM_ID]: { - 65: { - name: 'Foresight: Init Category', - accounts: findAccounts('initCategory'), - getDataUI: async ( - _connection: Connection, - data: Uint8Array, - _accounts: AccountMetaData[] - ) => { - const args = decodeIxData(data, initCategoryLayout) - return ( - <> - {displayParsedArg('categoryId', numArrayToString(args.categoryId))} - - ) - }, - }, - 192: { - name: 'Foresight: Init Market List', - accounts: findAccounts('initMarketList'), - getDataUI: async ( - _connection: Connection, - data: Uint8Array, - _accounts: AccountMetaData[] - ) => { - const args = decodeIxData(data, initMarketListLayout) - return ( - <> - {displayParsedArg( - 'marketListId', - numArrayToString(args.marketListId) - )} - - ) - }, - }, - 33: { - name: 'Foresight: Init Market', - accounts: findAccounts('initMarket'), - getDataUI: async ( - connection: Connection, - data: Uint8Array, - accounts: AccountMetaData[] - ) => { - const args = decodeIxData(data, initMarketLayout) - const marketListId = await fetchMarketListId( - connection, - accounts[1].pubkey - ) - return ( - <> - {displayParsedArg('marketId', args.marketId[0].toString())} - {displayParsedArg('marketListId', marketListId)} - - ) - }, - }, - 218: { - name: 'Foresight: Add Market List to Category', - accounts: findAccounts('addMarketListToCategory'), - getDataUI: async ( - connection: Connection, - _data: Uint8Array, - accounts: AccountMetaData[] - ) => { - const categoryId = await fetchCategoryId(connection, accounts[1].pubkey) - const marketListId = await fetchMarketListId( - connection, - accounts[2].pubkey - ) - return ( - <> - {' '} - {displayParsedArg('categoryId', categoryId)} - {displayParsedArg('marketListId', marketListId)} - - ) - }, - }, - 90: { - name: 'Foresight: Set Market Metadata', - accounts: findAccounts('writeToFieldMarketMetadata'), - getDataUI: async ( - connection: Connection, - data: Uint8Array, - accounts: AccountMetaData[] - ) => { - const args = decodeIxData(data, writeToFieldMarketMetadataLayout) - const field = generatedTypes.MarketMetadataFields.fromDecoded( - args.field - ).kind - const metadataAccount = await generatedAccounts.MarketMetadata.fetch( - connection, - accounts[1].pubkey - ) - const currentMetadata = - metadataAccount === null - ? 'Error: not found.' - : parseMetadata(metadataAccount) - return ( - <> - {displayParsedArg('field', field)} - {displayParsedArg('content', numArrayToString(args.string))} -

Note: this is the current metadata:

-

{currentMetadata}

- - ) - }, - }, - 155: { - name: 'Foresight: Resolve Market', - accounts: findAccounts('resolveMarket'), - getDataUI: async ( - connection: Connection, - data: Uint8Array, - accounts: AccountMetaData[] - ) => { - const args = decodeIxData(data, resolveMarketLayout) - const winner = args.winningBracket === 0 ? 'YES' : 'NO' - const marketPubkey = accounts[2].pubkey - const marketAccount = await generatedAccounts.Market.fetch( - connection, - marketPubkey - ) - const notFoundMsg = 'Error: not found.' - let currentMetadata: string - if (marketAccount === null) { - currentMetadata = notFoundMsg - } else { - const marketId = Buffer.from(marketAccount.id) - const marketListId = Buffer.from(marketAccount.marketListId) - const [metadataPubkey] = PublicKey.findProgramAddressSync( - [Buffer.from('market_metadata'), marketId, marketListId], - consts.PROGRAM_ID_PUBKEY - ) - const metadataAccount = await generatedAccounts.MarketMetadata.fetch( - connection, - metadataPubkey - ) - currentMetadata = - metadataAccount === null - ? 'Error: not found.' - : parseMetadata(metadataAccount, false) - } - return ( - <> - {displayParsedArg('Winner', winner)} -

Note: here is the relevant market metadata:

-

{currentMetadata}

- - ) - }, - }, - }, -} 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 60d5e006cd..a5a451ee8c 100644 --- a/components/instructions/programs/mangoV4.tsx +++ b/components/instructions/programs/mangoV4.tsx @@ -1,9 +1,4 @@ -import { - Bank, - OracleProvider, - USDC_MINT, - toUiDecimals, -} from '@blockworks-foundation/mango-v4' +import { Bank, USDC_MINT, toUiDecimals } from '@blockworks-foundation/mango-v4' import AdvancedOptionsDropdown from '@components/NewRealmWizard/components/AdvancedOptionsDropdown' import { BN, BorshInstructionCoder } from '@coral-xyz/anchor' import { AccountMetaData } from '@solana/spl-governance' @@ -13,7 +8,6 @@ import { FlatListingArgs, ListingArgsFormatted, getOracle, - getBestMarket, EditTokenArgsFormatted, FlatEditArgs, getFormattedListingPresets, @@ -40,6 +34,7 @@ import { tryParseKey } from '@tools/validators/pubkey' import Loading from '@components/Loading' 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' @@ -252,18 +247,41 @@ const instructions = () => ({ ) const presetInfo = await getSuggestedCoinPresetInfo( - proposedMint.toBase58(), - proposedOracle.type === 'Pyth' + proposedMint.toBase58() ) const formattedProposedArgs = getFormattedListingValues(args) - const suggestedPreset = getFormattedListingPresets( - proposedOracle.type === 'Pyth', + const formattedSuggestedPresets = getFormattedListingPresets( 0, mintInfo?.account.decimals || 0, oracleData.uiPrice - )[presetInfo.presetKey] + ) + + 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 @@ -284,15 +302,25 @@ 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, valKey, @@ -323,13 +351,10 @@ const instructions = () => ({ <>

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

- Very low liquidity Price impact of {presetInfo.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

)} @@ -348,6 +373,13 @@ const instructions = () => ({ carefully )} + {currentListingArgsMatchedTier && ( +

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

+ )} {isMintOnCurve && (
Proposed token has open mint @@ -436,6 +468,11 @@ const instructions = () => ({ valKey={'interestRatePoint1'} suffix="%" /> + ({ ({ valKey="liquidationFee" suffix="%" /> + ({ suffix="H" /> @@ -527,24 +569,39 @@ const instructions = () => ({ - ({ label="Interest Curve Scaling" valKey="interestCurveScaling" /> - +
{info}
@@ -602,28 +664,21 @@ const instructions = () => ({ 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 } - const bestMarket = await getBestMarket({ - baseMint: baseMint!.toBase58(), - quoteMint: quoteMint!.toBase58(), - cluster: 'mainnet-beta', - connection, - }) - try { return (
- {bestMarket && openbookMarketPk.equals(bestMarket) && ( + {/* {bestMarket && openbookMarketPk.equals(bestMarket.pubKey) && (
Proposed market match the best market according to listing @@ -636,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}
) @@ -750,6 +826,7 @@ const instructions = () => ({ { name: 'Admin' }, { name: 'Mint Info' }, { name: 'Oracle' }, + { name: 'Fallback oracle' }, ], getDataUI: async ( connection: Connection, @@ -767,6 +844,7 @@ const instructions = () => ({ displayArgs(connection, data), getDataObjectFlattened(connection, data), ]) + let priceImpact: MidPriceImpact | undefined const mint = [...mangoGroup.mintInfosMapByMint.values()].find((x) => x.publicKey.equals(mintInfo) )?.mint @@ -786,11 +864,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) @@ -819,11 +901,11 @@ const instructions = () => ({ : undefined, loanFeeRate: args.loanFeeRateOpt !== undefined - ? (args.loanFeeRateOpt * 10000)?.toFixed(2) + ? (args.loanFeeRateOpt * 100)?.toFixed(2) : undefined, loanOriginationFeeRate: args.loanOriginationFeeRateOpt !== undefined - ? (args.loanOriginationFeeRateOpt * 10000)?.toFixed(2) + ? (args.loanOriginationFeeRateOpt * 100)?.toFixed(2) : undefined, maintAssetWeight: args.maintAssetWeightOpt?.toFixed(2), initAssetWeight: args.initAssetWeightOpt?.toFixed(2), @@ -833,6 +915,10 @@ const instructions = () => ({ args['liquidationFeeOpt'] !== undefined ? (args['liquidationFeeOpt'] * 100)?.toFixed(2) : undefined, + platformLiquidationFee: + args['platformLiquidationFeeOpt'] !== undefined + ? (args['platformLiquidationFeeOpt'] * 100)?.toFixed(2) + : undefined, minVaultToDepositsRatio: args['minVaultToDepositsRatioOpt'] !== undefined ? (args['minVaultToDepositsRatioOpt'] * 100)?.toFixed(2) @@ -861,7 +947,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 @@ -875,17 +964,32 @@ const instructions = () => ({ depositLimit: args.depositLimitOpt?.toString(), setFallbackOracle: args.setFallbackOracle, maintWeightShiftAbort: args.maintWeightShiftAbort, + zeroUtilRate: + args.zeroUtilRateOpt !== undefined + ? (args.zeroUtilRateOpt * 100).toFixed(2) + : undefined, + disableAssetLiquidation: args.disableAssetLiquidationOpt, + collateralFeePerDay: + args.collateralFeePerDayOpt !== undefined + ? (args.collateralFeePerDayOpt * 100)?.toFixed(4) + : undefined, + forceWithdraw: args.forceWithdrawOpt, + forceClose: args.forceCloseOpt, } if (mint) { bank = mangoGroup.getFirstBankByMint(mint) bankFormattedValues = getFormattedBankValues(mangoGroup, bank) mintData = tokenPriceService.getTokenInfo(mint.toBase58()) - const isPyth = bank?.oracleProvider === OracleProvider.Pyth - const midPriceImpacts = getMidPriceImpacts(mangoGroup.pis) + + 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 ( @@ -899,12 +1003,15 @@ const instructions = () => ({ {} ) - const priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)] + priceImpact = tokenToPriceImpact[getApiTokenName(bank.name)] - const suggestedPresetKey = getProposedKey( - priceImpact?.target_amount, - bank.oracleProvider === OracleProvider.Pyth - ) + const suggestedPresetKey = priceImpact + ? getProposedKey( + priceImpact.avg_price_impact_percent < 1 + ? priceImpact?.target_amount + : undefined + ) + : 'UNTRUSTED' liqudityTier = !mint.equals(USDC_MINT) ? { @@ -914,13 +1021,12 @@ const instructions = () => ({ : '', } : { - presetKey: 'asset_250p', + presetKey: 'asset_250', priceImpact: '0', } const suggestedPreset = getFormattedListingPresets( - !!isPyth, - bank.nativeDeposits().mul(bank.price).toNumber(), + bank.uiDeposits(), bank.mintDecimals, bank.uiPrice )[liqudityTier.presetKey!] @@ -943,6 +1049,8 @@ const instructions = () => ({ maintWeightShiftLiabTarget: args.maintWeightShiftLiabTargetOpt, maintWeightShiftAbort: args.maintWeightShiftAbort, setFallbackOracle: args.setFallbackOracle, + forceWithdraw: args.forceWithdrawOpt, + forceClose: args.forceCloseOpt, } : {} @@ -951,7 +1059,30 @@ 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 + ) + ) + } + if (x === 'collateralFeePerDay') { + return false + } + return true + }) invalidFields = invalidKeys.reduce((obj, key) => { return { @@ -964,15 +1095,20 @@ const instructions = () => ({ return (

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

+ {!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 + Very low liquidity check params carefully

)} @@ -1030,7 +1166,11 @@ const instructions = () => ({ ({ } /> + ({ `${invalidFields.liquidationFee}%` } /> + ({ `${invalidFields.netBorrowLimitWindowSizeTs}H` } /> + ({ value={args.oracleOpt?.toBase58()} currentValue={bankFormattedValues?.oracle} /> + {accounts.length && + accounts[4] && + accounts[4].pubkey.toBase58() !== + bankFormattedValues?.fallbackOracle && ( + + )} ({ /> ({ suggestedVal={invalidFields.maintWeightShiftLiabTarget} /> + + {parsedArgs?.disableAssetLiquidation && ( + + )} {parsedArgs?.maintWeightShiftAbort && ( ({ suggestedVal={null} /> )} + {parsedArgs?.forceClose && ( + + )} + {parsedArgs?.forceWithdraw && ( + + )} {parsedArgs?.setFallbackOracle && ( ({ } }, }, - 73195: { + 11366: { name: 'Withdraw all token fees', accounts: [ { name: 'Group' }, @@ -1433,6 +1703,56 @@ const instructions = () => ({ } }, }, + 63223: { + name: 'Token Withdraw', + accounts: [ + { name: 'Group' }, + { name: 'Account' }, + { name: 'Owner' }, + { name: 'Bank' }, + { name: 'Vault' }, + { name: 'Oracle' }, + { name: 'TokenAccount' }, + { name: 'TokenProgram' }, + ], + getDataUI: async ( + connection: Connection, + data: Uint8Array, + accounts: AccountMetaData[] + ) => { + 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 ( +
+
+ amount:{' '} + {mint?.account.decimals + ? formatNumber( + toUiDecimals(args.amount, mint?.account.decimals) + ) + : args.amount}{' '} + {tokenInfo?.symbol} +
+
allowBorrow: {args.allowBorrow.toString()}
+
+ ) + } catch (e) { + console.log(e) + return
{JSON.stringify(data)}
+ } + }, + }, 15219: { name: 'Withdraw all perp fees', accounts: [ @@ -1498,12 +1818,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)}
@@ -1536,6 +1879,7 @@ const instructions = () => ({ export const MANGO_V4_INSTRUCTIONS = { '4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg': instructions(), + zF2vSz6V9g1YHGmfrzsY497NJzbRr84QUrPry4bLQ25: instructions(), } async function getDataObjectFlattened( @@ -1719,13 +2063,14 @@ const getFormattedListingValues = (args: FlatListingArgs) => { adjustmentFactor: ( args['interestRateParams.adjustmentFactor'] * 100 ).toFixed(2), - loanFeeRate: (args.loanFeeRate * 10000).toFixed(2), - loanOriginationFeeRate: (args.loanOriginationFeeRate * 10000).toFixed(2), + loanFeeRate: (args.loanFeeRate * 100).toFixed(2), + loanOriginationFeeRate: (args.loanOriginationFeeRate * 100).toFixed(2), maintAssetWeight: args.maintAssetWeight.toFixed(2), initAssetWeight: args.initAssetWeight.toFixed(2), maintLiabWeight: args.maintLiabWeight.toFixed(2), initLiabWeight: args.initLiabWeight.toFixed(2), liquidationFee: (args['liquidationFee'] * 100).toFixed(2), + platformLiquidationFee: (args['platformLiquidationFee'] * 100).toFixed(2), minVaultToDepositsRatio: (args['minVaultToDepositsRatio'] * 100).toFixed(2), netBorrowLimitPerWindowQuote: toUiDecimals( args['netBorrowLimitPerWindowQuote'], @@ -1749,12 +2094,15 @@ 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, interestCurveScaling: args.interestCurveScaling, groupInsuranceFund: args.groupInsuranceFund, + collateralFeePerDay: (args.collateralFeePerDay * 100).toFixed(4), + zeroUtilRate: (args.zeroUtilRate * 100).toFixed(2), + disableAssetLiquidation: args.disableAssetLiquidation, } return formattedArgs } @@ -1772,3 +2120,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/programs/names.ts b/components/instructions/programs/names.ts index 79924845ac..1a7ef2a426 100644 --- a/components/instructions/programs/names.ts +++ b/components/instructions/programs/names.ts @@ -1,5 +1,4 @@ import { PublicKey } from '@solana/web3.js' -import { consts as foresightConsts } from '@foresight-tmp/foresight-sdk/' import { LIDO_PROGRAM_ID, LIDO_PROGRAM_ID_DEVNET, @@ -63,7 +62,6 @@ const PROGRAM_NAMES = { 'Raydium Voter Stake Registry Program', VoteMBhDCqGLRgYpp9o7DGyq81KNmwjXQRAHStjtJsS: 'Marinade Voter Stake Registry Program', - [foresightConsts.PROGRAM_ID]: 'Foresight Dex', [NAME_PROGRAM_ID.toBase58()]: 'Solana Name Service Program', AwyKDr1Z5BfdvK3jX1UWopyjsJSV5cq4cuJpoYLofyEn: 'Validator Dao', Stake11111111111111111111111111111111111111: 'Stake Program', diff --git a/components/instructions/programs/poseidon.tsx b/components/instructions/programs/poseidon.tsx index 0f2744e576..dad579b342 100644 --- a/components/instructions/programs/poseidon.tsx +++ b/components/instructions/programs/poseidon.tsx @@ -2,7 +2,8 @@ import { BN, web3 } from '@coral-xyz/anchor' import { AccountMetaData } from '@solana/spl-governance' import { getMintDecimalAmountFromNatural } from '@tools/sdk/units' import tokenPriceService from '@utils/services/tokenPrice' -import { parseMintAccountData, parseTokenAccountData } from '@utils/tokens' +import { parseMintAccountData } from '@utils/tokens' +import { parseTokenAccountData } from '@utils/parseTokenAccountData' import { InstructionDescriptorFactory } from '../tools' const common_instructions = (): Record< diff --git a/components/instructions/programs/stake.tsx b/components/instructions/programs/stake.tsx index 87618f40b9..4b97a7b492 100644 --- a/components/instructions/programs/stake.tsx +++ b/components/instructions/programs/stake.tsx @@ -1,6 +1,7 @@ -import { Connection, LAMPORTS_PER_SOL } from '@solana/web3.js' +import { Connection, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js' import { AccountMetaData } from '@solana/spl-governance' import * as BufferLayout from '@solana/buffer-layout' +import dayjs from 'dayjs' export const STAKE_INSTRUCTIONS = { Stake11111111111111111111111111111111111111: { @@ -60,5 +61,105 @@ export const STAKE_INSTRUCTIONS = { return <> }, }, + 6: { + name: 'Stake Program - Unlock', + accounts: [{ name: 'Stake Account' }, { name: 'Vote Account' }], + getDataUI: async ( + _connection: Connection, + _data: Uint8Array, + _accounts: AccountMetaData[] + ) => { + try { + const layout = BufferLayout.struct([ + BufferLayout.u32('instruction'), + BufferLayout.u8('hasUnixTimestamp'), + BufferLayout.ns64('unixTimestamp'), + BufferLayout.u8('hasEpoch'), + //add epoch field if needed + BufferLayout.u8('hasCustodian'), + //add custodian field if needed + ]) + // decode + const data = layout.decode(Buffer.from(_data)) + const accData = await _connection.getParsedAccountInfo( + _accounts[0].pubkey + ) + const stakeMeta = accData.value?.data['parsed'].info.meta + return ( + <> +
+
Staker: {stakeMeta.authorized.staker}
+
Withdraw authority: {stakeMeta.authorized.withdrawer}
+
Lockup authority: {stakeMeta.lockup.custodian}
+
+
+ Unlock date:{' '} + {dayjs.unix(data.unixTimestamp).format('DD-MM-YYYY HH:mm')} +
+ {(data.hasEpoch !== 0 || data.hasCustodian !== 0) && ( +
+ Warning! detected epoch or custodian change +
+ )} + + ) + } catch (e) { + return <> + } + }, + }, + 1: { + name: 'Stake Program - Change Authority', + accounts: [ + { name: 'Stake Account' }, + { name: '' }, + { name: 'Authorized' }, + ], + getDataUI: async ( + _connection: Connection, + _data: Uint8Array, + _accounts: AccountMetaData[] + ) => { + const layout = BufferLayout.struct([ + BufferLayout.u32('instruction'), + BufferLayout.blob(32, 'newAuthorized'), + BufferLayout.u32('voteAuthorizationType'), + ]) + const data = layout.decode(Buffer.from(_data)) + + return ( + <> +

New Authority: {new PublicKey(data.newAuthorized).toBase58()}

+

+ Change of:{' '} + {data.voteAuthorizationType === 0 ? 'Staker' : 'Withdrawer'} +

+ + ) + }, + }, + 9: { + name: 'Stake Program - Deposit Stake', + accounts: [ + { name: 'Stake Pool' }, + { name: 'Validator List' }, + { name: 'Deposit Authority' }, + { name: 'Withdraw Authority' }, + { name: 'Deposit Stake' }, + { name: 'Validator Stake' }, + { name: 'Reserve Stake' }, + { name: 'Destination PoolAccount' }, + { name: 'Manager Fee Account' }, + { name: 'Referral Pool Account' }, + { name: 'Pool Mint' }, + ], + getDataUI: async ( + _connection: Connection, + _data: Uint8Array, + _accounts: AccountMetaData[] + ) => { + return <> + }, + }, }, } diff --git a/components/instructions/programs/stakeSanctum.tsx b/components/instructions/programs/stakeSanctum.tsx new file mode 100644 index 0000000000..73d69889b5 --- /dev/null +++ b/components/instructions/programs/stakeSanctum.tsx @@ -0,0 +1,37 @@ +import { Connection } from '@solana/web3.js' +import { AccountMetaData } from '@solana/spl-governance' + +export const STAKE_SANCTUM_INSTRUCTIONS = { + SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY: { + 9: { + name: 'Stake Program - Deposit Stake', + accounts: [ + { name: 'Stake Pool' }, + { name: 'Validator List' }, + { name: 'Deposit Authority' }, + { name: 'Withdraw Authority' }, + { name: 'Deposit Stake' }, + { name: 'Validator Stake' }, + { name: 'Reserve Stake' }, + { name: 'Destination PoolAccount' }, + { name: 'Manager Fee Account' }, + { name: 'Referral Pool Account' }, + { name: 'Pool Mint' }, + ], + getDataUI: async ( + _connection: Connection, + _data: Uint8Array, + _accounts: AccountMetaData[] + ) => { + return ( + <> +
+ Check change authority instruction. New authority must match + deposit authority of pool {_accounts[2].pubkey.toBase58()} +
+ + ) + }, + }, + }, +} diff --git a/components/instructions/programs/symmetryV2.tsx b/components/instructions/programs/symmetryV2.tsx new file mode 100644 index 0000000000..b6820b2f02 --- /dev/null +++ b/components/instructions/programs/symmetryV2.tsx @@ -0,0 +1,408 @@ +import { Connection } from "@solana/web3.js" +import { BasketsSDK } from "@symmetry-hq/baskets-sdk" +import BufferLayout from 'buffer-layout' + +const targetCompositionLayout = BufferLayout.seq( + BufferLayout.u8(), + 15, + 'targetComposition' +); +const targetWeightsLayout = BufferLayout.seq( + BufferLayout.u32(), + 15, + 'targetWeights' +); +const rebalanceAndLpLayout = BufferLayout.seq( + BufferLayout.u8(), + 2, + 'rebalanceAndLp' +); + + +const SymmetryLogoLink = () => { + return + + + + + + +} + +export const SYMMETRY_V2_INSTRUCTIONS = { + "2KehYt3KsEQR53jYcxjbQp2d2kCp4AkuQW68atufRwSr": { + 78: { + name: 'Symmetry: Withdraw from Basket', + accounts: [ + { name: 'Withdrawer' }, + { name: 'Basket Address' }, + { name: 'Symmetry PDA' }, + { name: 'Withdraw Temporary State Account' }, + { name: 'Withdrawer Basket Token Account' }, + { name: 'Basket Token Mint' }, + { name: 'System Program' }, + { name: 'Token Program' }, + { name: 'Rent Program' }, + { name: 'Account' }, + ], + getDataUI: async (connection: Connection, data: Uint8Array) => { + + //@ts-ignore + const { amount, rebalance } = BufferLayout.struct([ + BufferLayout.nu64('amount'), + BufferLayout.nu64('rebalance') + ]).decode(Buffer.from(data), 8) + + return ( +
+
+ +
+

Withdraw from Basket

+

Basket Tokens will be burnt to redeem underlying assets:

+
+
+
+
+
+
+
Withdraw:
+
{(amount / 10**6).toFixed(2)} Basket Tokens
+
+
+
Rebalance to USDC:
+
+ {rebalance === 2 ? 'Yes' : 'No - Withdraw Assets Directly'} +
+
+
+
+
+
+ + ) + }, + }, + 251: { + name: 'Symmetry: Deposit into Basket', + accounts: [ + { name: 'Depositor' }, + { name: 'Basket Address' }, + { name: 'Basket Token Mint' }, + { name: 'Symmetry Token List' }, + { name: 'Symmetry PDA' }, + { name: 'USDC PDA Account' }, + { name: 'Depositor USDC Account' }, + { name: 'Manager USDC Account' }, + { name: 'Symmetry Fee Account' }, + { name: 'Host Platform USDC Account' }, + { name: 'Depositor Basket Token Account' }, + { name: 'Temporary State Account for Deposit' }, + { name: 'System Program' }, + { name: 'Token Program' }, + { name: 'Rent' }, + { name: 'Associated Token Program' }, + { name: 'Account' }, + ], + getDataUI: async (connection: Connection, data: Uint8Array) => { + + //@ts-ignore + const { amount, rebalance } = BufferLayout.struct([ + BufferLayout.nu64('amount') + ]).decode(Buffer.from(data), 8) + + return ( +
+
+ +
+

USDC Deposit Information

+

After the deposit, basket tokens will be minted to the DAO.

+
+
+
+
+
+
+
USDC Deposit Amount:
+
{(amount / 10**6).toFixed(2)} USDC
+
+
+
+
+
+ ) + }, + }, + 38: { + name: 'Symmetry: Edit Basket', + accounts: [ + { name: 'Basket Manager' }, + { name: 'Basket Address' }, + { name: 'Symmetry Token List' }, + { name: 'Manager Fee Receiver Address' }, + ], + getDataUI: async (connection: Connection, data: Uint8Array) => { + + //@ts-ignore + const { managerFee, rebalanceInterval, rebalanceThreshold, rebalanceSlippage, lpOffsetThreshold, rebalanceAndLp, numOfTokens, targetComposition, targetWeights } = BufferLayout.struct([ + BufferLayout.u16('managerFee'), + BufferLayout.nu64('rebalanceInterval'), + BufferLayout.u16('rebalanceThreshold'), + BufferLayout.u16('rebalanceSlippage'), + BufferLayout.u16('lpOffsetThreshold'), + rebalanceAndLpLayout, + BufferLayout.u8('numOfTokens'), + targetCompositionLayout, + targetWeightsLayout, + ]).decode(Buffer.from(data), 8) + + const basketsSdk = await BasketsSDK.init(connection); + const tokenData = basketsSdk.getTokenListData(); + let usdcIncluded = false; + let totalWeight = 0; targetWeights.map(w => totalWeight += w); + + let composition = targetComposition.map((tokenId, i) => { + let token = tokenData.filter(x => x.id == tokenId)[0] + if(token.id === 0) { + if(!usdcIncluded) { + usdcIncluded = true; + return { + ...token, + weight: targetWeights[i] / totalWeight * 100 + } + } + } else { + return { + ...token, + weight: targetWeights[i] / totalWeight * 100 + } + } + }).filter(x => x != null) + + return ( +
+
+ + + + + + + +
+

Editing Basket Settings

+

If the proposal passes, the basket will be edited to the following settings:

+
+
+
+
+
+
+
Manager Fee:
+
{managerFee / 100}%
+
+
+
Rebalance Check Interval:
+
{rebalanceInterval / 60} minutes
+
+
+
Rebalance Trigger Threshold:
+
{rebalanceThreshold / 100}%
+
+
+
Maximum Slippage Allowed During Rebalancing:
+
{rebalanceSlippage / 100}%
+
+
+
Liquidity Provision Threshold:
+
{lpOffsetThreshold / 100}%
+
+
+
Rebalancing Enabled:
+
{rebalanceAndLp[0] === 0 ? "Yes" : "No"}
+
+
+
Liquidity Provision Enabled:
+
{rebalanceAndLp[1] === 0 ? "Yes" : "No"}
+
+
+
Basket Composition Size:
+
{numOfTokens} Tokens
+
+
+
+
+

Basket Composition:

+ +
+
+
+ ) + }, + }, + 47: { + name: 'Symmetry: Create Basket', + accounts: [ + { name: 'Manager' }, + { name: 'Token List' }, + { name: 'Basket Address' }, + { name: 'Symmetry PDA' }, + { name: 'Basket Token Mint' }, + { name: 'Symmetry Fee Collector' }, + { name: 'Metadata Account' }, + { name: 'Metadata Program' }, + { name: 'System Program' }, + { name: 'Token Program' }, + { name: 'Rent' }, + { name: 'Host Platform' }, + { name: 'Fee Collector Address' }, + { name: 'Account' }, + ], + getDataUI: async (connection: Connection, data: Uint8Array) => { + //@ts-ignore + const { managerFee, hostFee, basketType,rebalanceInterval, rebalanceThreshold, rebalanceSlippage, lpOffsetThreshold, rebalanceAndLp, numOfTokens, targetComposition, targetWeights, } = BufferLayout.struct([ + BufferLayout.u16('managerFee'), + BufferLayout.u16('hostFee'), + BufferLayout.u8('basketType'), + BufferLayout.nu64('rebalanceInterval'), + BufferLayout.u16('rebalanceThreshold'), + BufferLayout.u16('rebalanceSlippage'), + BufferLayout.u16('lpOffsetThreshold'), + rebalanceAndLpLayout, + BufferLayout.u8('numOfTokens'), + targetCompositionLayout, + targetWeightsLayout, + ]).decode(Buffer.from(data), 8) + const getBasketType = (type) => { + switch (type) { + case 0: return "Bundle"; + case 1: return "Portfolio"; + case 2: return "Private"; + default: return "Unknown"; + } + }; + + let basketsSdk = await BasketsSDK.init(connection); + let tokenData = basketsSdk.getTokenListData(); + let usdcIncluded = false; + let totalWeight = 0; targetWeights.map(w => totalWeight += w); + + let composition = targetComposition.map((tokenId, i) => { + let token = tokenData.filter(x => x.id == tokenId)[0] + if(token.id === 0) { + if(!usdcIncluded) { + usdcIncluded = true; + return { + ...token, + weight: targetWeights[i] / totalWeight * 100 + } + } + } else + return { + ...token, + weight: targetWeights[i] / totalWeight * 100 + } + }).filter(x => x != null) + + return ( +
+
+ + + + + + + +
+

Creating a Basket

+

If the proposal passes, a basket will be created with the following settings:

+
+
+
+
+
+
+
Manager Fee:
+
{managerFee / 100}%
+
+
+
Host Platform Fee:
+
{hostFee / 100}%
+
+
+
Basket Type:
+
{getBasketType(basketType)}
+
+
+
Rebalance Check Interval:
+
{rebalanceInterval / 60} minutes
+
+
+
Rebalance Trigger Threshold:
+
{rebalanceThreshold / 100}%
+
+
+
Maximum Slippage Allowed During Rebalancing:
+
{rebalanceSlippage / 100}%
+
+
+
Liquidity Provision Threshold:
+
{lpOffsetThreshold / 100}%
+
+
+
Rebalancing Enabled:
+
{rebalanceAndLp[0] === 0 ? "Yes" : "No"}
+
+
+
Liquidity Provision Enabled:
+
{rebalanceAndLp[1] === 0 ? "Yes" : "No"}
+
+
+
Basket Composition Size:
+
{numOfTokens} Tokens
+
+
+
+
+

Basket Composition:

+ +
+
+
+ ) + }, + }, + }, +} \ No newline at end of file diff --git a/components/instructions/tools.tsx b/components/instructions/tools.tsx index 418652698d..ac37a15726 100644 --- a/components/instructions/tools.tsx +++ b/components/instructions/tools.tsx @@ -22,10 +22,8 @@ import { VOTE_STAKE_REGISTRY_INSTRUCTIONS } from './programs/voteStakeRegistry' import { MARINADE_INSTRUCTIONS } from './programs/marinade' import { SOLEND_PROGRAM_INSTRUCTIONS } from './programs/solend' import { ATA_PROGRAM_INSTRUCTIONS } from './programs/associatedTokenAccount' -import { governance as foresightGov } from '@foresight-tmp/foresight-sdk' import { ConnectionContext } from '@utils/connection' import { NFT_VOTER_INSTRUCTIONS } from './programs/nftVotingClient' -import { FORESIGHT_INSTRUCTIONS } from './programs/foresight' import { LIDO_INSTRUCTIONS } from './programs/lido' import { NAME_SERVICE_INSTRUCTIONS } from './programs/nameService' import { TOKEN_AUCTION_INSTRUCTIONS } from './programs/tokenAuction' @@ -37,6 +35,8 @@ import { SWITCHBOARD_INSTRUCTIONS } from './programs/switchboard' import { STAKE_INSTRUCTIONS } from './programs/stake' import dayjs from 'dayjs' import { JUPITER_REF } from './programs/jupiterRef' +import { STAKE_SANCTUM_INSTRUCTIONS } from './programs/stakeSanctum' +import { SYMMETRY_V2_INSTRUCTIONS } from './programs/symmetryV2' /** * Default governance program id instance @@ -61,8 +61,9 @@ export const ACCOUNT_NAMES = { 'Mango DAO BLAZE Realm Deposit', '8gjzxiqcU87cvRc7hFiUJgxqLSV7AQnSttfWC5fD9aim': 'Mango DAO Treasury Council Mint', + oW7juZxrhaGvWw5giRp3P3qTHEZpg2t8n8aXTCpBjNK: 'Mango DAO boost council', G1Yc5696GcfL28uAWG6iCaKJwZd8sQzwPJTc2UacsjHN: - 'Mango DAO Game master Council Mint', + 'Mango DAO Game Master Council Mint', A9xaHx54B9bRYBga4V6LKFrRaARpMJFYVooEXRAanru5: 'Mango DAO Treasury Council USDC Treasury', '7zGXUAeUkY9pEGfApsY26amibvqsf2dmty1cbtxHdfaQ': 'Mango DAO Wallet Governance', @@ -106,8 +107,6 @@ export const ACCOUNT_NAMES = { MangoCzJ36AjZyKwVj3VnYU4GTonjfVEnJmvvWaxLac: 'MNGO Token Mint', H7uqouPsJkeEiLpCEoC1qYVVquDrZan6ZfdPK2gS44zm: 'FORE Devnet Token Mint', '4ahVJVavHM8DZCtjX6YuKSTFx6KJwRPmVCJtjdQYdUU7': 'FORE Mainnet Token Mint', - [foresightGov.DEVNET_TREASURY.toBase58()]: 'Foresight Devnet Governance', - [foresightGov.MAINNET_TREASURY.toBase58()]: 'Foresight Mainnet Governance', EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v: 'USDC Token Mint', MyHd6a7HWKTMeJMHBkrbMq4hZwZxwn9x7dxXcopQ4Wd: 'OMH Token', @@ -137,6 +136,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)', @@ -323,6 +328,9 @@ export const ACCOUNT_NAMES = { '6gwjRFcW1Y9iuJwXPdz1zZUa3Hcu855dH6APA5LjD8qK': 'AllDomains Treasury Governance', AWVUWfRnHCTgo123mRXB9BRWaxt6JdZXXKhFMQ5mryKJ: 'AllDomains DAO Governance', + + // Parcl + "9Waj7NNTzEhyHf1j1F36xgtnXaLoAxVBFhf6VxE9fgaf": 'Parcl DAO' } // TODO: Add this to on-chain metadata to Governance account @@ -358,6 +366,8 @@ export const HIDDEN_PROPOSALS = new Map([ ['H5TnbSBNFKJJwKea8tUj7ETcmhRHXQ1N9XCXBSD6Q9P1', ''], ['GeMQWvFTasBoui11RqRzMtDPQ9b2BkMK8NzepWzvuXw3', ''], ['CRmUPr8CbfPQ4MAoo2yxSf5qL2nPsddL69kowMfp1JYP', ''], + ['8msNFq5VBectsGAv66zYx5QRve1p3m6ZEz49xaWX3tbd', ''], + ['3jU2YuKXKBw4cWx9taPDfhQZ8RFLmFUx3HLxMrh7w749', ''], ]) export const DEFAULT_NATIVE_SOL_MINT = @@ -389,6 +399,15 @@ const HIDDEN_MNGO_TREASURES = [ 'PuXf9LNrmtVDhBTxteNTWS8D2SpzbhYvidkSatjRArt', ] +//badly created realms +export const HIDDEN_REALMS = [ + 'BWnVbUDohApiiaWBNNGcLH2KXRKEoTBJ7schsKQWYAtj', + 'FsoDEiZ9BoGTAaCLzXkyQWEqNKa5PW2iokzmuD7YsRdL', + '9nUyxzVL2FUMuWUiVZG66gwK15CJiM3PoLkfrnGfkvt6', // old Drift dao + '7mjEBafqqKA2K6SHezMrDV1zBoyNw6SKFcTsBbH2Kxgb', // openBook v2 council wrong config + '6NzVDMfEBJvkFDnjPx53K7mLGW3yQdSjLhsamS8go4cn', // old bonfida dao +] + //owner and desired accounts we want to show const MNGO_AUXILIARY_TOKEN_ACCOUNTS = [ { @@ -399,10 +418,54 @@ const MNGO_AUXILIARY_TOKEN_ACCOUNTS = [ owner: '7hqfhmXK6uXQKmNjUVEJo5acDMLcnyN9p9bZ5Dmnifde', accounts: ['2gDu12CM56g18Ukc9R1EdmEbToXqGTrnBEqR3zKfVKgt'], }, + //treasury management council { owner: '9so7UTo6b6LXBSqdDfh18hjVj8Ng5BmLbYXLB7UrhaaJ', - accounts: ['A9xaHx54B9bRYBga4V6LKFrRaARpMJFYVooEXRAanru5'], + accounts: [ + 'A9xaHx54B9bRYBga4V6LKFrRaARpMJFYVooEXRAanru5', + '8Wkbx6Daq3RQY492HaXK2nbVLXKCL5SGcab3RHzBCzpV', + '7D2j3MpXMveMEkdR94QfMh5nS3HdFD7uQHKhaLenR8u6', + '5d5CU8viHKiwrwjgNUFtb6AxUjdiZ1xmLo2m3AMYa9K5', + ], + }, + //boost council + { + owner: 'BExGoGVK6k6mUL6oHmabbc2EtwNqhJUeNoJWijF6t3ZB', + accounts: [ + 'HuDbGjhoPMWxVUxJmaY4uinDF5RmSufg2SCwjxpCRvXX', + 'AnmvgZbSre3NyGn4CeSNZDTN7NMmribt4eNTFDAQSGuv', + ], + }, + //vsr + { + owner: 'DZZWE1PR8qTkH3dLTrD7kcNEs6xx3GmSuFbzW29dyHv7', + accounts: ['CJoHzb9FVJUKanFdmjjXD84Hg94qgE4egu8s2tGYTVdE'], + }, + { + owner: 'VrT8f16NLADvYR73YiDMwxZREPbJgiZqLvN6HLQj4hR', + accounts: ['BkNq5TQvPkDnQWNgn1j2Q2SAFe3r5m2PazRwC7YUSHAT'], + }, + { + owner: '3H5PPK1bhHKmCAG5zwUyxpKDijES3H9uRAUCBrW8rGPX', + accounts: ['3sC3vzVz9YoiR12QKgvxHD6Q2LBfhL1ev63tsUaUS2EJ'], + }, + { + owner: 'DdZWj3nWSzJMMv1LMTHm9gTJ37wHLNXTMzqjWCokvKEn', + accounts: ['6XfCUQuq4juhqWLCW6LeivZd1eGuCRp4Mw3D6nkwXwFG'], + }, + { + owner: '7v1dD4kTJcBC7zV9MSrz7Ddyz8Dvs24QUMnZeQQCxeyV', + accounts: ['CEGxhB84XffJBfXm8WphwSczrpaJX6cRJjZz3QqNWJSZ'], + }, + { + owner: 'A99Whcw3pNdYXQ1DikQsLLNNjbsw8rD1zdvX4LTvZ8pD', + accounts: ['CkxhXSSgqBM7HrZE6zrQPBNCb7eHN4nm1FHd3Ad1XARX'], + }, + { + owner: 'FRYXAjyVnvXja8chgdq47qL3CKoyBjUg4ro7M7QQn1aD', + accounts: ['24frxVoDzo7bAimBU6rDhB1McxWNvzX9qddPMSv9VACZ'], }, + // ] export const AUXILIARY_TOKEN_ACCOUNTS = { @@ -441,7 +504,6 @@ export const INSTRUCTION_DESCRIPTORS = { ...LIDO_INSTRUCTIONS, ...SWITCHBOARD_INSTRUCTIONS, ...SOLEND_PROGRAM_INSTRUCTIONS, - ...FORESIGHT_INSTRUCTIONS, ...ATA_PROGRAM_INSTRUCTIONS, ...SYSTEM_INSTRUCTIONS, ...VOTE_STAKE_REGISTRY_INSTRUCTIONS, @@ -453,7 +515,9 @@ export const INSTRUCTION_DESCRIPTORS = { ...MANGO_V4_INSTRUCTIONS, ...DUAL_INSTRUCTIONS, ...STAKE_INSTRUCTIONS, + ...STAKE_SANCTUM_INSTRUCTIONS, ...JUPITER_REF, + ...SYMMETRY_V2_INSTRUCTIONS, } export async function getInstructionDescriptor( 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/Details/TokenOwnerRecordDetails/Header.tsx b/components/treasuryV2/Details/TokenOwnerRecordDetails/Header.tsx index 40fb1d2a19..a00446bc63 100644 --- a/components/treasuryV2/Details/TokenOwnerRecordDetails/Header.tsx +++ b/components/treasuryV2/Details/TokenOwnerRecordDetails/Header.tsx @@ -219,7 +219,7 @@ export default function Header({ tokenOwnerRecord, governance }: Props) {

- Community Votes: {/** todo check for council */} + Community votes: {/** todo check for council */} {fmtMintAmount( mint, new BN( diff --git a/components/treasuryV2/WalletList/NewWalletButton.tsx b/components/treasuryV2/WalletList/NewWalletButton.tsx index 5981f2caf6..a2b9a4ca98 100644 --- a/components/treasuryV2/WalletList/NewWalletButton.tsx +++ b/components/treasuryV2/WalletList/NewWalletButton.tsx @@ -6,7 +6,7 @@ import { LinkButton } from '@components/Button' import useQueryContext from '@hooks/useQueryContext' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' -import { useGovernancePowerAsync } from '@hooks/queries/governancePower' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const NEW_TREASURY_ROUTE = `/treasury/new` @@ -15,8 +15,18 @@ export default function NewWalletButton() { const connected = !!wallet?.connected const realm = useRealmQuery().data?.result - const { result: councilGovPower } = useGovernancePowerAsync('council') - const { result: communityGovPower } = useGovernancePowerAsync('community') + const { + isReady: communityIsReady, + totalCalculatedVoterWeight: communityCalculatedVoterWeight, + } = useRealmVoterWeightPlugins('community') + const { + isReady: councilIsReady, + totalCalculatedVoterWeight: councilCalculatedVoterWeight, + } = useRealmVoterWeightPlugins('council') + const isReady = communityIsReady && councilIsReady + + const communityGovPower = communityCalculatedVoterWeight?.value + const councilGovPower = councilCalculatedVoterWeight?.value const { symbol, @@ -27,11 +37,12 @@ export default function NewWalletButton() { const { fmtUrlWithCluster } = useQueryContext() const canCreateGovernance = - councilGovPower?.gtn(0) || - (realm && - communityGovPower?.gt( - realm.account.config.minCommunityTokensToCreateGovernance - )) + isReady && + (councilGovPower?.gtn(0) || + (realm && + communityGovPower?.gt( + realm.account.config.minCommunityTokensToCreateGovernance + ))) const addNewAssetTooltip = !connected ? 'Connect your wallet to create new asset' diff --git a/components/treasuryV2/WalletList/WalletListItem/AssetList/MangoListItem.tsx b/components/treasuryV2/WalletList/WalletListItem/AssetList/MangoListItem.tsx new file mode 100644 index 0000000000..ebe9c5caf7 --- /dev/null +++ b/components/treasuryV2/WalletList/WalletListItem/AssetList/MangoListItem.tsx @@ -0,0 +1,35 @@ +import React from 'react' + +import ListItem from './ListItem' +import { CurrencyDollarIcon } from '@heroicons/react/solid' +import { formatNumber } from '@utils/formatNumber' +import BigNumber from 'bignumber.js' + +interface Props { + className?: string + selected?: boolean + amount: BigNumber + onSelect?(): void +} + +export default function MangoListItem(props: Props) { + return ( + +

+
$
+
+ {formatNumber(props.amount)} +
+
+
+ } + selected={props.selected} + onSelect={props.onSelect} + thumbnail={} + /> + ) +} 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/components/treasuryV2/WalletList/WalletListItem/AssetList/OtherAssetsList.tsx b/components/treasuryV2/WalletList/WalletListItem/AssetList/OtherAssetsList.tsx index cad31ef6c4..9584e723c9 100644 --- a/components/treasuryV2/WalletList/WalletListItem/AssetList/OtherAssetsList.tsx +++ b/components/treasuryV2/WalletList/WalletListItem/AssetList/OtherAssetsList.tsx @@ -9,6 +9,7 @@ import { RealmAuthority, Unknown, Stake, + Mango, } from '@models/treasury/Asset' import Collapsible from './Collapsible' @@ -19,16 +20,25 @@ import UnknownAssetListItem from './UnknownAssetListItem' import RealmAuthorityListItem from './RealmAuthorityListItem' import StakeListItem from './StakeListItem' import { abbreviateAddress } from '@utils/formatting' +import MangoListItem from './MangoListItem' interface Props { className?: string disableCollapse?: boolean expanded?: boolean - assets: (Mint | Domains | Programs | RealmAuthority | Unknown | Stake)[] + assets: ( + | Mint + | Domains + | Programs + | RealmAuthority + | Unknown + | Stake + | Mango + )[] selectedAssetId?: string | null itemsToHide: string[] onSelect?( - asset: Mint | Domains | Programs | RealmAuthority | Unknown | Stake + asset: Mint | Domains | Programs | RealmAuthority | Unknown | Stake | Mango ): void onToggleExpand?(): void } @@ -106,6 +116,14 @@ export default function OtherAssetsList(props: Props) { onSelect={() => props.onSelect?.(asset)} > ) + case AssetType.Mango: + return ( + []} + /> + ) case AssetType.Unknown: return ( (othersFromProps) const [itemsToHide, setItemsToHide] = useState([]) useEffect(() => { @@ -173,6 +183,7 @@ export default function AssetList(props: Props) { | Domains | RealmAuthority | Stake + | Mango )[] = [] for await (const token of othersFromProps) { if (isMint(token)) { diff --git a/components/treasuryV2/WalletList/WalletListItem/typeGuards.ts b/components/treasuryV2/WalletList/WalletListItem/typeGuards.ts index cc21b3b8a0..2cbcbe65b2 100644 --- a/components/treasuryV2/WalletList/WalletListItem/typeGuards.ts +++ b/components/treasuryV2/WalletList/WalletListItem/typeGuards.ts @@ -9,6 +9,7 @@ import { Domains, Unknown, Stake, + Mango, } from '@models/treasury/Asset' export function isToken(asset: Asset): asset is Token { @@ -35,6 +36,10 @@ export function isStake(asset: Asset): asset is Stake { return asset.type === AssetType.Stake } +export function isMango(asset: Asset): asset is Mango { + return asset.type === AssetType.Mango +} + export function isSol(asset: Asset): asset is Sol { return asset.type === AssetType.Sol } diff --git a/constants/endpoints.ts b/constants/endpoints.ts index 1fb8c69421..4a65f8a4e0 100644 --- a/constants/endpoints.ts +++ b/constants/endpoints.ts @@ -1,7 +1,7 @@ export const MAINNET_RPC = process.env.NEXT_PUBLIC_MAINNET_RPC || process.env.MAINNET_RPC || - 'http://realms-realms-c335.mainnet.rpcpool.com/258d3727-bb96-409d-abea-0b1b4c48af29/' + 'http://realms-realms-c335.mainnet.rpcpool.com' export const DEVNET_RPC = process.env.NEXT_PUBLIC_DEVNET_RPC || diff --git a/constants/flags.ts b/constants/flags.ts index e3768bb676..ab4dbcfff6 100644 --- a/constants/flags.ts +++ b/constants/flags.ts @@ -12,7 +12,11 @@ export const DELEGATOR_BATCH_VOTE_SUPPORT_BY_PLUGIN: Record< VSR: true, HeliumVSR: false, gateway: false, + QV: false, NFT: false, pyth: false, unknown: false, + drift: false, + token_haver: false, + parcl: false } diff --git a/constants/plugins.ts b/constants/plugins.ts index aa1ae4ab6c..4bdf3966ee 100644 --- a/constants/plugins.ts +++ b/constants/plugins.ts @@ -1,6 +1,8 @@ import { PROGRAM_ID as HELIUM_VSR_PROGRAM_ID } from '@helium/voter-stake-registry-sdk' import { PublicKey } from '@solana/web3.js' import { DEFAULT_NFT_VOTER_PLUGIN } from '@tools/constants' +import { DRIFT_STAKE_VOTER_PLUGIN } from 'DriftStakeVoterPlugin/constants' +import { TOKEN_HAVER_PLUGIN } from 'TokenHaverPlugin/constants' export const VSR_PLUGIN_PKS: string[] = [ '4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo', @@ -9,6 +11,7 @@ export const VSR_PLUGIN_PKS: string[] = [ 'VoteWPk9yyGmkX4U77nEWRJWpcc8kUfrPoghxENpstL', 'VoteMBhDCqGLRgYpp9o7DGyq81KNmwjXQRAHStjtJsS', '5sWzuuYkeWLBdAv3ULrBfqA51zF7Y4rnVzereboNDCPn', + 'HBZ5oXbFBFbr8Krt2oMU7ApHFeukdRS8Rye1f3T66vg5', ] export const HELIUM_VSR_PLUGINS_PKS: string[] = [ @@ -22,15 +25,37 @@ export const NFT_PLUGINS_PKS: string[] = [ ] export const GATEWAY_PLUGINS_PKS: string[] = [ - 'Ggatr3wgDLySEwA2qEjt1oiw4BUzp5yMLJyz21919dq6', - 'GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk', // v2, supporting composition + 'GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk', +] + +export const QV_PLUGINS_PKS: string[] = [ + 'quadCSapU8nTdLg73KHDnmdxKnJQsh7GUbu5tZfnRRr', ] export const PYTH_PLUGIN_PK: string[] = [ 'pytS9TjG1qyAZypk7n8rw8gfW9sUaqqYyMhJQ4E7JCQ', ] -export const findPluginName = (programId: PublicKey | undefined) => +export const PARCL_PLUGIN_PK: string[] = [ + '2gWf5xLAzZaKX9tQj9vuXsaxTWtzTZDFRn21J3zjNVgu', +] + +export const DRIFT_PLUGIN_PK = [DRIFT_STAKE_VOTER_PLUGIN] + +export type PluginName = + | 'gateway' + | 'QV' + | 'vanilla' + | 'VSR' + | 'HeliumVSR' + | 'NFT' + | 'pyth' + | 'drift' + | 'token_haver' + | 'parcl' + | 'unknown' + +export const findPluginName = (programId: PublicKey | undefined): PluginName => programId === undefined ? ('vanilla' as const) : VSR_PLUGIN_PKS.includes(programId.toString()) @@ -41,6 +66,38 @@ export const findPluginName = (programId: PublicKey | undefined) => ? 'NFT' : GATEWAY_PLUGINS_PKS.includes(programId.toString()) ? 'gateway' + : QV_PLUGINS_PKS.includes(programId.toString()) + ? 'QV' : PYTH_PLUGIN_PK.includes(programId.toString()) ? 'pyth' + : DRIFT_PLUGIN_PK.includes(programId.toString()) + ? 'drift' + : TOKEN_HAVER_PLUGIN.toString() === programId.toString() + ? 'token_haver' + : PARCL_PLUGIN_PK.includes(programId.toString()) + ? 'parcl' : 'unknown' + +// Used when creating a new realm to choose which voterWeightAddin to use +export const pluginNameToCanonicalProgramId = ( + pluginName: PluginName +): PublicKey | undefined => { + const lastPk = (arr: string[]) => new PublicKey(arr[arr.length - 1]) + + switch (pluginName) { + case 'VSR': + return lastPk(VSR_PLUGIN_PKS) + case 'HeliumVSR': + return lastPk(HELIUM_VSR_PLUGINS_PKS) + case 'NFT': + return lastPk(NFT_PLUGINS_PKS) + case 'gateway': + return lastPk(GATEWAY_PLUGINS_PKS) + case 'QV': + return lastPk(QV_PLUGINS_PKS) + case 'pyth': + return lastPk(PYTH_PLUGIN_PK) + default: + return undefined + } +} diff --git a/hooks/PythNetwork/useScalingFactor.ts b/hooks/PythNetwork/useScalingFactor.ts new file mode 100644 index 0000000000..b14f0ecb82 --- /dev/null +++ b/hooks/PythNetwork/useScalingFactor.ts @@ -0,0 +1,35 @@ +import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet"; +import { determineVotingPowerType } from "@hooks/queries/governancePower"; +import useSelectedRealmPubkey from "@hooks/selectedRealm/useSelectedRealmPubkey"; +import { useConnection } from "@solana/wallet-adapter-react"; +import { useAsync } from "react-async-hook"; +import { useQuery } from "@tanstack/react-query"; +import { PythStakingClient } from "@pythnetwork/staking-sdk"; + +/** + * 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 = new PythStakingClient({ + connection, + }) + return pythClient.getScalingFactor() + }, { enabled: plugin == "pyth" }) + + if (plugin == "pyth") { + return scalingFactor + } else { + return undefined + } +} + diff --git a/hooks/parcl/useScalingFactor.ts b/hooks/parcl/useScalingFactor.ts new file mode 100644 index 0000000000..58cd3d039f --- /dev/null +++ b/hooks/parcl/useScalingFactor.ts @@ -0,0 +1,38 @@ +import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' +import { determineVotingPowerType } from '@hooks/queries/governancePower' +import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' +import { useConnection } from '@solana/wallet-adapter-react' +import { useAsync } from 'react-async-hook' +import { useQuery } from '@tanstack/react-query' +import { StakeConnection } from '@parcl-oss/staking' + +/** + * Returns undefined for everything except the Parcl DAO + */ +export default function useParclScalingFactor(): number | undefined { + const realm = useSelectedRealmPubkey() + const { connection } = useConnection() + const { result: plugin } = useAsync( + async () => + realm && determineVotingPowerType(connection, realm, 'community'), + [connection, realm] + ) + + const { data: scalingFactor } = useQuery( + ['parcl-scaling-factor'], + async (): Promise => { + const parclClient = await StakeConnection.connect( + connection, + {} as NodeWallet + ) + return parclClient.getScalingFactor() + }, + { enabled: plugin == 'parcl' } + ) + + if (plugin == 'parcl') { + return scalingFactor + } else { + return undefined + } +} diff --git a/hooks/queries/bufferAuthority.ts b/hooks/queries/bufferAuthority.ts new file mode 100644 index 0000000000..180447caa7 --- /dev/null +++ b/hooks/queries/bufferAuthority.ts @@ -0,0 +1,42 @@ +import { BPF_UPGRADE_LOADER_ID } from "@solana/spl-governance"; +import { useConnection } from "@solana/wallet-adapter-react"; +import { PublicKey } from "@solana/web3.js"; +import { useQuery } from "@tanstack/react-query" +import { useRouteProposalQuery } from "./proposal"; +import { useSelectedProposalTransactions } from "./proposalTransaction"; + +export const useBufferAccountsAuthority = () => { + const {connection} = useConnection() + const proposal = useRouteProposalQuery().data?.result + const { data: transactions } = useSelectedProposalTransactions() + const enabled = transactions !== undefined && proposal !== undefined; + + const query = useQuery({ + queryKey: enabled ? + [connection.rpcEndpoint, 'BufferAccountsAuthority',proposal.pubkey] + : undefined, + + queryFn: async() => { + if (!enabled) throw new Error() + const ixs = transactions.flatMap((pix) => pix.account.getAllInstructions()) + const bufAuthorities: PublicKey[] = []; + + for (let i = 0; i 36) { + bufAuthorities.push(new PublicKey(bufferAccountData.data.subarray(5,37))) + } + } + } + + return bufAuthorities + }, + enabled + }) + + return query +} \ No newline at end of file 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/governancePower.tsx b/hooks/queries/governancePower.tsx index 3adc3da99b..8e3fdebf18 100644 --- a/hooks/queries/governancePower.tsx +++ b/hooks/queries/governancePower.tsx @@ -9,30 +9,20 @@ import BN from 'bn.js' import { fetchDigitalAssetsByOwner } from './digitalAssets' import { getNetworkFromEndpoint } from '@utils/connection' import { ON_NFT_VOTER_V2 } from '@constants/flags' -import { fetchRealmByPubkey, useRealmQuery } from './realm' +import { fetchRealmByPubkey } from './realm' import { fetchRealmConfigQuery } from './realmConfig' -import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore' -import useGatewayPluginStore from 'GatewayPlugin/store/gatewayPluginStore' -import { useAsync } from 'react-async-hook' -import { useConnection } from '@solana/wallet-adapter-react' -import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' -import { - useAddressQuery_CommunityTokenOwner, - useAddressQuery_CouncilTokenOwner, -} from './addresses/tokenOwnerRecord' + +import { StakeConnection } from "@parcl-oss/staking" import { - SimpleGatedVoterWeight, - VoteNftWeight, - VoteRegistryVoterWeight, - VoterWeight, + LegacyVoterWeightAdapter, } from '@models/voteWeights' -import useUserOrDelegator from '@hooks/useUserOrDelegator' -import { getVsrGovpower, useVsrGovpower } from './plugins/vsr' -import { PythClient } from '@pythnetwork/staking' +import { PythStakingClient } from "@pythnetwork/staking-sdk"; import NodeWallet from '@coral-xyz/anchor/dist/cjs/nodewallet' import { findPluginName } from '@constants/plugins' -import { nftRegistrarQuery } from './plugins/nftVoter' -import queryClient from './queryClient' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' +import {IdlAccounts} from "@coral-xyz/anchor"; +import {NftVoter} from "../../idls/nft_voter"; +import {getPluginRegistrarClientCached} from "@hooks/queries/pluginRegistrar"; export const getVanillaGovpower = async ( connection: Connection, @@ -47,7 +37,7 @@ export const getVanillaGovpower = async ( : new BN(0) } -export const useVanillaGovpower = (tokenOwnerRecordPk: PublicKey) => { +export const useVanillaGovpower = (tokenOwnerRecordPk: PublicKey | undefined) => { const { data: torAccount } = useTokenOwnerRecordByPubkeyQuery( tokenOwnerRecordPk ) @@ -56,82 +46,99 @@ export const useVanillaGovpower = (tokenOwnerRecordPk: PublicKey) => { : new BN(0) } -export const getNftGovpower = async ( - connection: Connection, - realmPk: PublicKey, - tokenOwnerRecordPk: PublicKey -) => { - // figure out what collections are used - const { result: registrar } = await queryClient.fetchQuery( - nftRegistrarQuery(connection, realmPk) - ) +export const getNftGovpowerForOwnerAndRegistrar = async(connection: Connection, owner: PublicKey, registrar: IdlAccounts['registrar'] | undefined) => { if (registrar === undefined) throw new Error() - const { collectionConfigs } = registrar - - // grab the owner of the TOR - const { result: TOR } = await fetchTokenOwnerRecordByPubkey( - connection, - tokenOwnerRecordPk - ) - if (TOR === undefined) throw new Error() - const owner = TOR.account.governingTokenOwner + const {collectionConfigs} = registrar // grab the user nfts const network = getNetworkFromEndpoint(connection.rpcEndpoint) if (network === 'localnet') throw new Error() const nfts = (await fetchDigitalAssetsByOwner(network, owner)) - // filter cnfts if not supported yet - .filter((nft) => ON_NFT_VOTER_V2 || !nft.compression.compressed) + // filter cnfts if not supported yet + .filter((nft) => ON_NFT_VOTER_V2 || !nft.compression.compressed) // map nfts to power and sum them const power = nfts - .map( - (nft) => - // find collectionConfig such that the nft's `collection` grouping matches the collection id - collectionConfigs.find( - (x) => - x.collection.toString() === - (nft.grouping.find((y) => y.group_key === 'collection') - ?.group_value ?? false) - // take the weight for that collection, or 0 if the nft matches none of the dao's collections - )?.weight ?? new BN(0) - ) - // sum - .reduce((partialSum, a) => partialSum.add(a), new BN(0)) + .map( + (nft) => + // find collectionConfig such that the nft's `collection` grouping matches the collection id + collectionConfigs.find( + (x) => + x.collection.toString() === + (nft.grouping.find((y) => y.group_key === 'collection') + ?.group_value ?? false) + // take the weight for that collection, or 0 if the nft matches none of the dao's collections + )?.weight ?? new BN(0) + ) + // sum + .reduce((partialSum, a) => partialSum.add(a), new BN(0)) return power } +export const getNftGovpowerForOwner = async (connection: Connection, realmPk: PublicKey, owner: PublicKey) => { + const registrar = await getPluginRegistrarClientCached(realmPk, connection, owner, 'NFT'); + return getNftGovpowerForOwnerAndRegistrar(connection, owner, registrar); +} + +export const getNftGovpower = async ( + connection: Connection, + realmPk: PublicKey, + tokenOwnerRecordPk: PublicKey +) => { + // grab the owner of the TOR + const { result: TOR } = await fetchTokenOwnerRecordByPubkey( + connection, + tokenOwnerRecordPk + ) + if (TOR === undefined) throw new Error() + const owner = TOR.account.governingTokenOwner + return getNftGovpowerForOwner(connection, realmPk, owner); +} + export const getPythGovPower = async ( connection: Connection, user: PublicKey | undefined ): Promise => { if (!user) return new BN(0) - const pythClient = await PythClient.connect( + const pythClient = new PythStakingClient({ + connection, + }) + const voterWeight = await pythClient.getVoterWeight(user) + + return new BN(voterWeight.toString()) +} + +export const getParclGovPower = async ( + connection: Connection, + user: PublicKey | undefined +): Promise => { + if (!user) return new BN(0) + const client = await StakeConnection.connect( connection, new NodeWallet(new Keypair()) ) - const stakeAccount = await pythClient.getMainAccount(user) - + const stakeAccount = await client.getMainAccount(user) if (stakeAccount) { - return stakeAccount.getVoterWeight(await pythClient.getTime()).toBN() + return stakeAccount.getVoterWeight(await client.getTime()).toBN() } else { return new BN(0) } } + export const determineVotingPowerType = async ( connection: Connection, realmPk: PublicKey, - kind: 'council' | 'community' + role: 'council' | 'community' ) => { const realm = (await fetchRealmByPubkey(connection, realmPk)).result if (!realm) throw new Error() const config = await fetchRealmConfigQuery(connection, realmPk) const programId = - kind === 'community' + role === 'community' ? config.result?.account.communityTokenConfig.voterWeightAddin : config.result?.account.councilTokenConfig.voterWeightAddin @@ -178,146 +185,41 @@ export const WithVsrGovernancePower = < ) } */ -/** where possible avoid using this and use a plugin-specific hook instead */ +// TODO QV-2 Check if there is no plugin and get the vanilla value (or should the usePlugins hook have the vanilla value?) +export const useGovernancePower = ( + kind: 'community' | 'council' | undefined +) => { + const { calculatedMaxVoterWeight } = useRealmVoterWeightPlugins(kind) + return calculatedMaxVoterWeight?.value +} +/** deprecated: this should not be used any more. Use useRealmVoterWeightPlugins hook */ export const useGovernancePowerAsync = ( kind: 'community' | 'council' | undefined ) => { - const { connection } = useConnection() - const realmPk = useSelectedRealmPubkey() - - const heliumVotingPower = useHeliumVsrStore((s) => s.state.votingPower) - const gatewayVotingPower = useGatewayPluginStore((s) => s.state.votingPower) - const vsrVotingPower = useVsrGovpower().data?.result - - const communityTOR = useAddressQuery_CommunityTokenOwner() - const councilTOR = useAddressQuery_CouncilTokenOwner() - const { data: TOR } = kind && kind === 'community' ? communityTOR : councilTOR - - const { result: plugin } = useAsync( - async () => - kind && realmPk && determineVotingPowerType(connection, realmPk, kind), - [connection, realmPk, kind] - ) - const actingAsWalletPk = useUserOrDelegator() - - return useAsync( - async () => - plugin === undefined - ? undefined - : realmPk && - TOR && - (plugin === 'vanilla' - ? getVanillaGovpower(connection, TOR) - : plugin === 'NFT' - ? getNftGovpower(connection, realmPk, TOR) - : plugin === 'VSR' - ? vsrVotingPower ?? new BN(0) - : plugin === 'HeliumVSR' - ? heliumVotingPower - : plugin === 'gateway' - ? gatewayVotingPower - : plugin === 'pyth' - ? getPythGovPower(connection, actingAsWalletPk) - : new BN(0)), - [ - plugin, - realmPk, - TOR, - connection, - vsrVotingPower, - heliumVotingPower, - gatewayVotingPower, - actingAsWalletPk, - ] - ) + const { totalCalculatedVoterWeight } = useRealmVoterWeightPlugins(kind) + return totalCalculatedVoterWeight?.value; } /** * @deprecated - * use useGovernancePowerAsync + * use useRealmVoterWeightPlugins instead */ export const useLegacyVoterWeight = () => { - const { connection } = useConnection() - const realmPk = useSelectedRealmPubkey() - const realm = useRealmQuery().data?.result - - const heliumVotingPower = useHeliumVsrStore((s) => s.state.votingPower) - const gatewayVotingPower = useGatewayPluginStore((s) => s.state.votingPower) - + const communityPluginDetails = useRealmVoterWeightPlugins('community'); + const councilPluginDetails = useRealmVoterWeightPlugins('council'); + const ownVoterWeights = { + community: communityPluginDetails.totalCalculatedVoterWeight?.value ?? undefined, + council: councilPluginDetails.totalCalculatedVoterWeight?.value ?? undefined, + } const { data: communityTOR } = useUserCommunityTokenOwnerRecord() const { data: councilTOR } = useUserCouncilTokenOwnerRecord() - const { result: plugin } = useAsync( - async () => - realmPk && determineVotingPowerType(connection, realmPk, 'community'), - [connection, realmPk] - ) - const actingAsWalletPk = useUserOrDelegator() - - const shouldCareAboutCouncil = - realm && realm.account.config.councilMint !== undefined + const voterWeight = new LegacyVoterWeightAdapter(ownVoterWeights, { + community: communityTOR?.result, + council: councilTOR?.result, + }); + const ready = communityPluginDetails.isReady && councilPluginDetails.isReady; - return useAsync( - async () => - realmPk && - communityTOR && - (shouldCareAboutCouncil === undefined - ? undefined - : shouldCareAboutCouncil === true && councilTOR === undefined - ? undefined - : plugin === 'vanilla' - ? new VoterWeight(communityTOR.result, councilTOR?.result) - : plugin === 'pyth' - ? new VoteRegistryVoterWeight( - communityTOR.result, - councilTOR?.result, - await getPythGovPower(connection, actingAsWalletPk) - ) - : plugin === 'NFT' - ? communityTOR.result?.pubkey - ? new VoteNftWeight( - communityTOR.result, - councilTOR?.result, - await getNftGovpower( - connection, - realmPk, - communityTOR.result.pubkey - ) - ) - : undefined - : plugin === 'VSR' - ? actingAsWalletPk - ? new VoteRegistryVoterWeight( - communityTOR.result, - councilTOR?.result, - (await getVsrGovpower(connection, realmPk, actingAsWalletPk)) - .result ?? new BN(0) - ) - : undefined - : plugin === 'HeliumVSR' - ? new VoteRegistryVoterWeight( - communityTOR.result, - councilTOR?.result, - heliumVotingPower - ) - : plugin === 'gateway' - ? new SimpleGatedVoterWeight( - communityTOR.result, - councilTOR?.result, - gatewayVotingPower - ) - : undefined), - - [ - actingAsWalletPk, - communityTOR, - connection, - councilTOR, - gatewayVotingPower, - heliumVotingPower, - plugin, - realmPk, - shouldCareAboutCouncil, - ] - ) + // only expose the vote weight once everything is loaded + return { result: ready ? voterWeight : undefined, ready }; } 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/mango.ts b/hooks/queries/mango.ts index 4c0771686f..e52267b86b 100644 --- a/hooks/queries/mango.ts +++ b/hooks/queries/mango.ts @@ -20,7 +20,10 @@ export const useMangoClient = (connection: Connection) => { const client = await MangoClient.connect( adminProvider, cluster, - MANGO_V4_ID[cluster] + MANGO_V4_ID[cluster], + { + idsSource: 'api', + } ) return client diff --git a/hooks/queries/pluginRegistrar.ts b/hooks/queries/pluginRegistrar.ts new file mode 100644 index 0000000000..0f1cf1e9dc --- /dev/null +++ b/hooks/queries/pluginRegistrar.ts @@ -0,0 +1,34 @@ +import queryClient from "@hooks/queries/queryClient"; +import {getPlugins} from "../../VoterWeightPlugins/lib/getPlugins"; +import {AnchorProvider, Idl, IdlAccounts} from "@coral-xyz/anchor"; +import EmptyWallet from "@utils/Mango/listingTools"; +import {Connection, Keypair, PublicKey} from "@solana/web3.js"; +import {fetchRealmByPubkey} from "@hooks/queries/realm"; +import {PluginName} from "@constants/plugins"; +import {PluginType, VoterWeightPluginInfo} from "../../VoterWeightPlugins/lib/types"; + +export const getPluginClientCachedWithEmptySigner = async (realmPk: PublicKey, connection: Connection, owner: PublicKey, pluginName: PluginName, type: PluginType): Promise => { + const realm = fetchRealmByPubkey(connection, realmPk) + const plugins = await queryClient.fetchQuery({ + queryKey: ['getCommunityPluginsWithoutWallet', realmPk.toString()], + queryFn: async () => { + const {result} = await realm; + if (!result) return []; + return getPlugins({ + realmPublicKey: realmPk, + governanceMintPublicKey: result.account.communityMint, + provider: new AnchorProvider(connection, new EmptyWallet(Keypair.generate()), AnchorProvider.defaultOptions()), + type, + wallets: [owner], + signer: new EmptyWallet(Keypair.generate()), + }) + } + }); + + return plugins.find((x) => x.name === pluginName); +} + +export const getPluginRegistrarClientCached = async (realmPk: PublicKey, connection: Connection, owner: PublicKey, pluginName: PluginName, type: PluginType = 'voterWeight'): Promise['registrar'] | undefined> => { + const plugin = await getPluginClientCachedWithEmptySigner(realmPk, connection, owner, pluginName, type); + return plugin?.params as IdlAccounts['registrar'] | undefined; +} \ No newline at end of file diff --git a/hooks/queries/plugins/nftVoter.ts b/hooks/queries/plugins/nftVoter.ts index edc45a7d7b..7f200a1f42 100644 --- a/hooks/queries/plugins/nftVoter.ts +++ b/hooks/queries/plugins/nftVoter.ts @@ -1,7 +1,7 @@ -import { Connection, PublicKey } from '@solana/web3.js' -import { fetchRealmByPubkey } from '../realm' +import {Connection, PublicKey} from '@solana/web3.js' +import {fetchRealmByPubkey} from '../realm' import { getRegistrarPDA } from '@utils/plugin/accounts' -import { Program } from '@coral-xyz/anchor' +import { Program} from '@coral-xyz/anchor' import { IDL, NftVoter } from 'idls/nft_voter' import asFindable from '@utils/queries/asFindable' import { fetchRealmConfigQuery } from '../realmConfig' @@ -9,24 +9,22 @@ import { useBatchedVoteDelegators } from '@components/VotePanel/useDelegators' import { useConnection } from '@solana/wallet-adapter-react' import useSelectedRealmPubkey from '@hooks/selectedRealm/useSelectedRealmPubkey' import { getNftGovpower } from '../governancePower' -import { useQueries, useQuery } from '@tanstack/react-query' +import { useQueries } from '@tanstack/react-query' import { fetchDigitalAssetsByOwner, useDigitalAssetsByOwner, } from '../digitalAssets' import { useMemo } from 'react' import { ON_NFT_VOTER_V2 } from '@constants/flags' -import queryClient from '../queryClient' import { NFT_PLUGINS_PKS } from '@constants/plugins' import { getNetworkFromEndpoint } from '@utils/connection' +import {useNftRegistrar} from "@hooks/useNftRegistrar"; +import {getPluginRegistrarClientCached} from "@hooks/queries/pluginRegistrar"; export const useVotingNfts = (ownerPk: PublicKey | undefined) => { - const { connection } = useConnection() - const realmPk = useSelectedRealmPubkey() + const registrar = useNftRegistrar(); const { data: nfts } = useDigitalAssetsByOwner(ownerPk) - - const registrar = useQuery(nftRegistrarQuery(connection, realmPk)).data - ?.result + console.log('nfts', nfts) const usedCollectionsPks = useMemo( () => registrar?.collectionConfigs.map((x) => x.collection.toBase58()), @@ -55,12 +53,7 @@ export const getVotingNfts = async ( if (realm === undefined) throw new Error() const config = await fetchRealmConfigQuery(connection, realmPk) if (config.result === undefined) throw new Error() - const currentPluginPk = - config.result.account.communityTokenConfig.voterWeightAddin - if (currentPluginPk === undefined) throw new Error() - const { result: registrar } = await queryClient.fetchQuery( - nftRegistrarQuery(connection, realmPk) - ) + const registrar = await getPluginRegistrarClientCached(realmPk, connection, ownerPk, 'NFT'); if (registrar === undefined) throw new Error() const usedCollectionsPks = registrar.collectionConfigs.map((x) => x.collection.toBase58() @@ -108,6 +101,8 @@ export const useNftBatchedVotePower = async ( return total } +// @deprecated - Use useNftClient().plugin.registrar instead to support chaining. +// Outside of react, use getPluginRegistrarClientCached instead. export const nftRegistrarQuery = ( connection: Connection, realmPk: PublicKey | undefined @@ -132,10 +127,10 @@ export const nftRegistrarQuery = ( ) return { found: false, result: undefined } as const - const { registrar: registrarPk } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - programId + const { registrar: registrarPk } = getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + programId ) // use anchor to fetch registrar :-) diff --git a/hooks/queries/plugins/vsr.ts b/hooks/queries/plugins/vsr.ts index f72805ef6d..14bacac087 100644 --- a/hooks/queries/plugins/vsr.ts +++ b/hooks/queries/plugins/vsr.ts @@ -11,10 +11,11 @@ import { fetchRealmConfigQuery, useRealmConfigQuery } from '../realmConfig' import queryClient from '../queryClient' import { useConnection } from '@solana/wallet-adapter-react' import useUserOrDelegator from '@hooks/useUserOrDelegator' -import { useAsync } from 'react-async-hook' import { getLockTokensVotingPowerPerWallet } from 'VoteStakeRegistry/tools/deposits' import { useQuery } from '@tanstack/react-query' import { findPluginName } from '@constants/plugins' +import {useVsrClient} from "../../../VoterWeightPlugins/useVsrClient"; +import {getPluginClientCachedWithEmptySigner} from "@hooks/queries/pluginRegistrar"; const VOTER_INFO_EVENT_NAME = 'VoterInfo' @@ -37,6 +38,8 @@ export const vsrQueryKeys = { ], } +// @deprecated - use the vsr voting client instead (useVsrClient), or preferably just obtain the weight generically for all plugins using +// useRealmVoterWeightPlugins().totalCalculatedVoterWeight export const getVsrGovpower = async ( connection: Connection, realmPk: PublicKey, @@ -44,25 +47,19 @@ export const getVsrGovpower = async ( ) => { const { result: realm } = await fetchRealmByPubkey(connection, realmPk) if (realm === undefined) throw new Error() - const communityMintPk = realm.account.communityMint - const config = await fetchRealmConfigQuery(connection, realmPk) - const programId = config.result?.account.communityTokenConfig.voterWeightAddin - if (programId === undefined) - return { found: false, result: undefined } as const - - const { registrar: registrarPk } = await getRegistrarPDA( + const plugin = await getPluginClientCachedWithEmptySigner(realmPk, connection, walletPk, 'VSR', 'voterWeight'); + const votingPower =await plugin?.client?.calculateVoterWeight( + walletPk, realmPk, - communityMintPk, - programId - ) - const { voter: voterPk } = await getVoterPDA(registrarPk, walletPk, programId) - const votingPower = await fetchVotingPower( - connection, - programId, - registrarPk, - voterPk - ) - return votingPower + realm.account.communityMint, + new BN(0) // technically incorrect. Should obtain the voter weight from the input TOR + ); + + if (!votingPower) { + return {found: false, result: undefined} as const + } + + return { found: true, result: votingPower } } const extractVotingPowerFromSimulation = ( @@ -149,28 +146,21 @@ export const useRegistrarPk = () => { const communityMintPk = realm?.account.communityMint const config = useRealmConfigQuery().data?.result const programId = config?.account.communityTokenConfig.voterWeightAddin - return useAsync( - async () => - realm && + return realm && communityMintPk && programId && - getRegistrarPDA(realm.pubkey, communityMintPk, programId), - [communityMintPk, programId, realm] - ) + getRegistrarPDA(realm.pubkey, communityMintPk, programId) } export const useVoterPk = (walletPk: PublicKey | undefined) => { - const registrar = useRegistrarPk().result + const registrar = useRegistrarPk() const config = useRealmConfigQuery().data?.result const programId = config?.account.communityTokenConfig.voterWeightAddin - return useAsync( - async () => - registrar && + + return registrar && walletPk && programId && - getVoterPDA(registrar.registrar, walletPk, programId), - [programId, registrar, walletPk] - ) + getVoterPDA(registrar.registrar, walletPk, programId); } export const useVsrGovpower = () => { @@ -178,8 +168,8 @@ export const useVsrGovpower = () => { const actingAsWallet = useUserOrDelegator() const config = useRealmConfigQuery().data?.result const pluginId = config?.account.communityTokenConfig.voterWeightAddin - const voterPk = useVoterPk(actingAsWallet).result?.voter - const registrarPk = useRegistrarPk().result?.registrar + const voterPk = useVoterPk(actingAsWallet)?.voter + const registrarPk = useRegistrarPk()?.registrar const pluginName = findPluginName(pluginId) const enabled = @@ -232,6 +222,7 @@ const voterPowerLogQueryFn = async ( export const useVsrGovpowerMulti = (wallets: PublicKey[] | undefined) => { const { connection } = useConnection() const realm = useRealmQuery().data?.result + const { vsrClient } = useVsrClient(); return useQuery({ enabled: wallets !== undefined && wallets.length > 0, @@ -251,29 +242,23 @@ export const useVsrGovpowerMulti = (wallets: PublicKey[] | undefined) => { const config = await fetchRealmConfigQuery(connection, realm.pubkey) const programId = config.result?.account.communityTokenConfig.voterWeightAddin - if (programId === undefined) return undefined - - const client = { - program: new Program(IDL, programId, { - connection, - }), - } + if (!vsrClient || programId === undefined) return undefined const x = await getLockTokensVotingPowerPerWallet( wallets, realm, - client, + vsrClient, connection ) - const { registrar: registrarPk } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - programId + const { registrar: registrarPk } = getRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + programId ) for (const [key, power] of Object.entries(x)) { - const { voter: voterPk } = await getVoterPDA( + const { voter: voterPk } = getVoterPDA( registrarPk, new PublicKey(key), programId 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/tokenAccount.ts b/hooks/queries/tokenAccount.ts index 126ae1539f..f2952c19e5 100644 --- a/hooks/queries/tokenAccount.ts +++ b/hooks/queries/tokenAccount.ts @@ -1,10 +1,57 @@ import { Connection, PublicKey } from '@solana/web3.js' import { useQuery } from '@tanstack/react-query' -import { getOwnedTokenAccounts, tryGetTokenAccount } from '@utils/tokens' import queryClient from './queryClient' import asFindable from '@utils/queries/asFindable' import { useConnection } from '@solana/wallet-adapter-react' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { AccountInfo, TOKEN_PROGRAM_ID } from '@solana/spl-token' +import { parseTokenAccountData } from '@utils/parseTokenAccountData' + +type TokenAccount = AccountInfo + +type TokenProgramAccount = { + publicKey: PublicKey + account: T +} + +async function getOwnedTokenAccounts( + connection: Connection, + publicKey: PublicKey +): Promise[]> { + const result = await connection.getTokenAccountsByOwner(publicKey, { + programId: TOKEN_PROGRAM_ID, + }) + + return result.value.map((r) => { + const publicKey = r.pubkey + const data = Buffer.from(r.account.data) + const account = parseTokenAccountData(publicKey, data) + return { publicKey, account } + }) +} + +async function tryGetTokenAccount( + connection: Connection, + publicKey: PublicKey +): Promise | undefined> { + try { + const result = await connection.getAccountInfo(publicKey) + + if (!result?.owner.equals(TOKEN_PROGRAM_ID)) { + return undefined + } + + const data = Buffer.from(result!.data) + const account = parseTokenAccountData(publicKey, data) + return { + publicKey, + account, + } + } catch (ex) { + // This is Try method and is expected to fail and hence logging is uneccesery + // console.error(`Can't fetch token account ${publicKey?.toBase58()}`, ex) + } +} export const tokenAccountQueryKeys = { all: (endpoint: string) => [endpoint, 'TokenAccount'], diff --git a/hooks/queries/tokenOwnerRecord.ts b/hooks/queries/tokenOwnerRecord.ts index 092a438153..8a1a9c11f7 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,11 +13,11 @@ 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' import mainnetBetaRealms from 'public/realms/mainnet-beta.json' +import { determineVotingPowerType } from './governancePower' export const tokenOwnerRecordQueryKeys = { all: (endpoint: string) => [endpoint, 'TokenOwnerRecord'], @@ -24,17 +25,28 @@ export const tokenOwnerRecordQueryKeys = { ...tokenOwnerRecordQueryKeys.all(endpoint), k.toString(), ], - byRealm: (endpoint: string, realm: PublicKey) => [ + byRealm: (endpoint: string, realm: PublicKey, type: string) => [ ...tokenOwnerRecordQueryKeys.all(endpoint), 'by Realm', - realm, + realm.toString(), + type ], + byRealmXDelegate: ( + endpoint: string, + realm: PublicKey, + delegate: PublicKey + ) => [ + ...tokenOwnerRecordQueryKeys.byRealm(endpoint, realm, 'all'), + 'by Delegate', + delegate.toString(), + ], + byProgramXOwner: (endpoint: string, program: PublicKey, owner: PublicKey) => [ ...tokenOwnerRecordQueryKeys.all(endpoint), 'by Program', - program, + program.toString(), 'by Owner', - owner, + owner.toString(), ], } @@ -88,7 +100,8 @@ export const useTokenOwnerRecordsForRealmQuery = () => { queryKey: enabled ? tokenOwnerRecordQueryKeys.byRealm( connection.current.rpcEndpoint, - realm.pubkey + realm.pubkey, + 'all' ) : undefined, queryFn: async () => { @@ -121,23 +134,109 @@ export const useTokenOwnerRecordsForRealmQuery = () => { return query } +export const useCouncilTokenOwnerRecordsForRealmQuery = () => { + const connection = useLegacyConnectionContext() + const realm = useRealmQuery().data?.result + + const enabled = realm !== undefined + const query = useQuery({ + queryKey: enabled + ? tokenOwnerRecordQueryKeys.byRealm( + connection.current.rpcEndpoint, + realm.pubkey, + 'council' + ) + : undefined, + queryFn: async () => { + if (!enabled) throw new Error() + + const filter = pubkeyFilter(1, realm.pubkey) + if (!filter) throw new Error() // unclear why this would ever happen, probably it just cannot + + const votingType = await determineVotingPowerType(connection.current, realm.pubkey, "community") + const councilOnly = !(votingType === 'vanilla' || votingType === 'NFT') + const councilMint = realm.account.config.councilMint + + const mintFilter = councilOnly && councilMint ? + pubkeyFilter(33, councilMint) : + null + + const results = await getGovernanceAccounts( + connection.current, + realm.owner, + TokenOwnerRecord, + mintFilter ? [filter, mintFilter] : [filter] + ) + + // 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 +} + +// 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() + + 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] + ) - return delagatingTors + // 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/queries/useProgramVersionQuery.ts b/hooks/queries/useProgramVersionQuery.ts index bea6e40779..c8ad64441b 100644 --- a/hooks/queries/useProgramVersionQuery.ts +++ b/hooks/queries/useProgramVersionQuery.ts @@ -1,4 +1,4 @@ -import { getGovernanceProgramVersion } from '@solana/spl-governance' +import { getGovernanceProgramVersion } from '@realms-today/spl-governance' import { useConnection } from '@solana/wallet-adapter-react' import { Connection, PublicKey } from '@solana/web3.js' import { useQuery } from '@tanstack/react-query' 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/useCreatePostMessageIx.ts b/hooks/useCreatePostMessageIx.ts index 6de921fc71..0771a41046 100644 --- a/hooks/useCreatePostMessageIx.ts +++ b/hooks/useCreatePostMessageIx.ts @@ -6,12 +6,13 @@ import { GOVERNANCE_CHAT_PROGRAM_ID, withPostChatMessage, } from '@solana/spl-governance' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import { useRouteProposalQuery } from '@hooks/queries/proposal' import { Keypair, TransactionInstruction } from '@solana/web3.js' import useUserOrDelegator from './useUserOrDelegator' +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {convertTypeToVoterWeightAction} from "../VoterWeightPlugins"; /** This is WIP and shouldn't be used * @deprecated @@ -21,9 +22,8 @@ const useCreatePostMessageIx = () => { const realm = useRealmQuery().data?.result const walletPk = useWalletOnePointOh()?.publicKey ?? undefined const actingWalletPk = useUserOrDelegator() - const votingPluginClient = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const { updateVoterWeightRecords, voterWeightPks, voterWeightPkForWallet } = useRealmVoterWeightPlugins(); + const voterWeightPk = actingWalletPk ? voterWeightPkForWallet(actingWalletPk) : undefined; const proposal = useRouteProposalQuery().data?.result return useCallback( @@ -47,13 +47,10 @@ const useCreatePostMessageIx = () => { proposal.account.governingTokenMint, actingWalletPk ) + const updateVWRInstructions = await updateVoterWeightRecords(actingWalletPk, convertTypeToVoterWeightAction('commentProposal')); - const plugin = await votingPluginClient?.withUpdateVoterWeightRecord( - instructions, - userTorPk, - 'commentProposal', - createNftTicketsIxs - ) + instructions.push(...updateVWRInstructions.pre); + createNftTicketsIxs.push(...updateVWRInstructions.post); const body = new ChatMessageBody({ type: ChatMessageBodyType.Text, @@ -73,10 +70,10 @@ const useCreatePostMessageIx = () => { walletPk, undefined, body, - plugin?.voterWeightPk + voterWeightPk ) }, - [actingWalletPk, proposal, realm, votingPluginClient, walletPk] + [actingWalletPk, proposal, realm, voterWeightPks, walletPk] ) } diff --git a/hooks/useCreateProposal.ts b/hooks/useCreateProposal.ts index 45337a8e6d..434bdfbbe2 100644 --- a/hooks/useCreateProposal.ts +++ b/hooks/useCreateProposal.ts @@ -2,8 +2,6 @@ import { InstructionDataWithHoldUpTime, createProposal, } from 'actions/createProposal' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import useRealm from './useRealm' import useRpcContext from './useRpcContext' import { fetchGovernanceByPubkey } from './queries/governance' import { PublicKey } from '@solana/web3.js' @@ -18,12 +16,9 @@ import queryClient from './queries/queryClient' import { proposalQueryKeys } from './queries/proposal' import { createLUTProposal } from 'actions/createLUTproposal' import { useLegacyVoterWeight } from './queries/governancePower' +import {useVotingClients} from "@hooks/useVotingClients"; export default function useCreateProposal() { - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) - const connection = useLegacyConnectionContext() const realm = useRealmQuery().data?.result const config = useRealmConfigQuery().data?.result @@ -31,8 +26,8 @@ export default function useCreateProposal() { const councilMint = useRealmCouncilMintInfoQuery().data?.result const { result: ownVoterWeight } = useLegacyVoterWeight() - const { canChooseWhoVote } = useRealm() const { getRpcContext } = useRpcContext() + const votingClients = useVotingClients(); /** @deprecated because the api is goofy, use `propose` */ const handleCreateProposal = async ({ @@ -56,13 +51,24 @@ export default function useCreateProposal() { connection.current, governance.pubkey ) + const minCouncilTokensToCreateProposal = selectedGovernance?.account.config.minCouncilTokensToCreateProposal + const councilPower = ownVoterWeight?.councilTokenRecord?.account.governingTokenDepositAmount + + const ownTokenRecord = + minCouncilTokensToCreateProposal && councilPower && councilPower >= minCouncilTokensToCreateProposal ? + ownVoterWeight?.councilTokenRecord : + ownVoterWeight?.communityTokenRecord + + if (!ownTokenRecord) throw new Error('token owner record does not exist') if (!selectedGovernance) throw new Error('governance not found') if (!realm) throw new Error() - const ownTokenRecord = ownVoterWeight?.getTokenRecordToCreateProposal( - selectedGovernance.account.config, - voteByCouncil - ) // TODO just get the token record the normal way + // this is somewhat confusing - the basic idea is: + // although a vote may be by community vote, the proposer may create it with their council token + // The choice of which token to use is made when the token record is selected + const proposeByCouncil = ownVoterWeight?.councilTokenRecord?.pubkey.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); + // now we can we identify whether we are using the community or council voting client (to decide which (if any) plugins to use) + const votingClient = votingClients(proposeByCouncil ? 'council' : 'community'); const defaultProposalMint = !mint?.supply.isZero() || @@ -73,7 +79,7 @@ export default function useCreateProposal() { : undefined const proposalMint = - canChooseWhoVote && voteByCouncil + voteByCouncil ? realm?.account.config.councilMint : defaultProposalMint @@ -83,12 +89,13 @@ export default function useCreateProposal() { const rpcContext = getRpcContext() if (!rpcContext) throw new Error() + const create = utilizeLookupTable ? createLUTProposal : createProposal const proposalAddress = await create( rpcContext, realm, governance.pubkey, - ownTokenRecord!, + ownTokenRecord, title, description, proposalMint, @@ -96,7 +103,7 @@ export default function useCreateProposal() { instructionsData, isDraft, ['Approve'], - client + votingClient ) queryClient.invalidateQueries({ queryKey: proposalQueryKeys.all(connection.endpoint), @@ -134,13 +141,25 @@ export default function useCreateProposal() { connection.current, governance ) + + const minCouncilTokensToCreateProposal = selectedGovernance?.account.config.minCouncilTokensToCreateProposal + const councilPower = ownVoterWeight?.councilTokenRecord?.account.governingTokenDepositAmount + + const ownTokenRecord = + minCouncilTokensToCreateProposal && councilPower && councilPower >= minCouncilTokensToCreateProposal ? + ownVoterWeight?.councilTokenRecord : + ownVoterWeight?.communityTokenRecord + + if (!ownTokenRecord) throw new Error('token owner record does not exist') if (!selectedGovernance) throw new Error('governance not found') if (!realm) throw new Error() - const ownTokenRecord = ownVoterWeight?.getTokenRecordToCreateProposal( - selectedGovernance.account.config, - voteByCouncil - ) + // this is somewhat confusing - the basic idea is: + // although a vote may be by community vote, the proposer may create it with their council token + // The choice of which token to use is made when the token record is selected + const proposeByCouncil = ownVoterWeight?.councilTokenRecord?.pubkey.toBase58() === (ownTokenRecord?.pubkey.toBase58() ?? ""); + // now we can we identify whether we are using the community or council voting client (to decide which (if any) plugins to use) + const votingClient = votingClients(proposeByCouncil ? 'council' : 'community'); const defaultProposalMint = !mint?.supply.isZero() || @@ -151,7 +170,7 @@ export default function useCreateProposal() { : undefined const proposalMint = - canChooseWhoVote && voteByCouncil + voteByCouncil ? realm?.account.config.councilMint : defaultProposalMint @@ -165,7 +184,7 @@ export default function useCreateProposal() { rpcContext, realm, governance, - ownTokenRecord!, + ownTokenRecord, title, description, proposalMint, @@ -173,7 +192,7 @@ export default function useCreateProposal() { instructionsData, isDraft, options, - client + votingClient ) queryClient.invalidateQueries({ queryKey: proposalQueryKeys.all(connection.endpoint), diff --git a/hooks/useDelegatorAwareVoterWeight.ts b/hooks/useDelegatorAwareVoterWeight.ts new file mode 100644 index 0000000000..86ea749215 --- /dev/null +++ b/hooks/useDelegatorAwareVoterWeight.ts @@ -0,0 +1,37 @@ +import {GovernanceRole} from "../@types/types"; +import {CalculatedWeight} from "../VoterWeightPlugins/lib/types"; +import useWalletOnePointOh from "@hooks/useWalletOnePointOh"; +import {useSelectedDelegatorStore} from "../stores/useSelectedDelegatorStore"; +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {DELEGATOR_BATCH_VOTE_SUPPORT_BY_PLUGIN} from "@constants/flags"; + +export const useDelegatorAwareVoterWeight = (role: GovernanceRole): CalculatedWeight | undefined => { + const wallet = useWalletOnePointOh(); + // these hooks return different results depending on whether batch delegator voting is supported + // if batch is on, and these are undefined, it means "yourself + all delegators" + // if batch is off, and these are undefined, it means "yourself only" + // if batch is on, and yourself only is picked, the selectedDelegator will be the current logged-in wallet + const selectedCommunityDelegator = useSelectedDelegatorStore((s) => s.communityDelegator) + const selectedCouncilDelegator = useSelectedDelegatorStore((s) => s.councilDelegator) + const selectedDelegatorForRole = role === 'community' ? selectedCommunityDelegator : selectedCouncilDelegator; + const votingWallet = (role === 'community' ? selectedCommunityDelegator : selectedCouncilDelegator) ?? wallet?.publicKey + + const {plugins, totalCalculatedVoterWeight, voterWeightForWallet} = useRealmVoterWeightPlugins(role) + + // if the plugin supports delegator batch voting (or no plugins exist on the dao), + // and no delegator is selected, we can use totalCalculatedVoterWeight + // otherwise, use the voterWeightForWallet for the correct delegator or the wallet itself + const lastPlugin = plugins?.voterWeight[plugins.voterWeight.length - 1]; + const supportsBatchVoting = !lastPlugin || DELEGATOR_BATCH_VOTE_SUPPORT_BY_PLUGIN[lastPlugin?.name] + + // the user has selected "yourself + all delegators" and the plugin supports batch voting + if (supportsBatchVoting && !selectedDelegatorForRole) { + return totalCalculatedVoterWeight; + } + + // there is no wallet to calculate voter weight for + if (!votingWallet) return undefined; + + // the user has selected a specific delegator or "yourself only" + return voterWeightForWallet(votingWallet); +} \ No newline at end of file diff --git a/hooks/useGovernanceAssets.ts b/hooks/useGovernanceAssets.ts index 08a8052c97..f0f320b684 100644 --- a/hooks/useGovernanceAssets.ts +++ b/hooks/useGovernanceAssets.ts @@ -4,10 +4,10 @@ import useGovernanceAssetsStore from 'stores/useGovernanceAssetsStore' import { HELIUM_VSR_PLUGINS_PKS, VSR_PLUGIN_PKS } from '../constants/plugins' import { useRealmQuery } from './queries/realm' import { useRealmConfigQuery } from './queries/realmConfig' -import { useRouter } from 'next/router' import { useRealmGovernancesQuery } from './queries/governance' import { useMemo } from 'react' -import { useLegacyVoterWeight } from './queries/governancePower' +import { useRealmVoterWeights } from '@hooks/useRealmVoterWeightPlugins' +import { GovernanceConfig } from '@solana/spl-governance' type Package = { name: string @@ -43,8 +43,19 @@ export type InstructionType = { export default function useGovernanceAssets() { const realm = useRealmQuery().data?.result const config = useRealmConfigQuery().data?.result - const { symbol } = useRouter().query - const { result: ownVoterWeight } = useLegacyVoterWeight() + const { communityWeight, councilWeight } = useRealmVoterWeights() + const ownVoterWeights = { + community: communityWeight?.value, + council: councilWeight?.value, + } + + const canCreateProposal = (config: GovernanceConfig) => { + return ( + ownVoterWeights.community?.gte( + config.minCommunityTokensToCreateProposal + ) || ownVoterWeights.council?.gte(config.minCouncilTokensToCreateProposal) + ) + } const governedTokenAccounts: AssetAccount[] = useGovernanceAssetsStore( (s) => s.governedTokenAccounts @@ -67,12 +78,9 @@ export default function useGovernanceAssets() { realm && assetAccounts .filter((x) => types.find((t) => t === x.type)) - .some((govAcc) => - ownVoterWeight?.canCreateProposal(govAcc.governance.account.config) - ) + .some((govAcc) => canCreateProposal(govAcc.governance.account.config)) ) } - const canMintRealmCouncilToken = () => { return !!assetAccounts.find( (x) => @@ -83,10 +91,7 @@ export default function useGovernanceAssets() { const governance = governancesArray.find( (x) => acc.governance.pubkey.toBase58() === x.pubkey.toBase58() ) - return ( - governance && - ownVoterWeight?.canCreateProposal(governance?.account?.config) - ) + return governance && canCreateProposal(governance?.account?.config) }) const canUseProgramUpgradeInstruction = canUseGovernanceForInstruction([ @@ -99,9 +104,7 @@ export default function useGovernanceAssets() { const canUseAnyInstruction = realm && - governancesArray.some((gov) => - ownVoterWeight?.canCreateProposal(gov.account.config) - ) + governancesArray.some((gov) => canCreateProposal(gov.account.config)) const realmAuth = realm && @@ -109,7 +112,7 @@ export default function useGovernanceAssets() { (x) => x.pubkey.toBase58() === realm.account.authority?.toBase58() ) const canUseAuthorityInstruction = - realmAuth && ownVoterWeight?.canCreateProposal(realmAuth?.account.config) + realmAuth && canCreateProposal(realmAuth?.account.config) const governedSPLTokenAccounts = governedTokenAccounts.filter( (x) => x.type === AccountType.TOKEN @@ -125,10 +128,7 @@ export default function useGovernanceAssets() { const governance = governancesArray.find( (x) => acc.governance.pubkey.toBase58() === x.pubkey.toBase58() ) - return ( - governance && - ownVoterWeight?.canCreateProposal(governance?.account?.config) - ) + return governance && canCreateProposal(governance?.account?.config) } ) @@ -150,14 +150,8 @@ export default function useGovernanceAssets() { [PackageEnum.Distribution]: { name: 'Distribution Program', }, - [PackageEnum.Foresight]: { - name: 'Foresight', - isVisible: symbol === 'FORE', - image: '/img/foresight.png', - }, - [PackageEnum.GatewayPlugin]: { - name: 'Gateway Plugin', + name: 'Civic Plugin', image: '/img/civic.svg', }, [PackageEnum.Identity]: { @@ -179,6 +173,10 @@ export default function useGovernanceAssets() { name: 'PsyFinance', image: '/img/psyfinance.png', }, + [PackageEnum.Pyth]: { + name: 'Pyth', + image: '/img/pyth.svg', + }, [PackageEnum.Serum]: { name: 'Serum', image: '/img/serum.png', @@ -190,6 +188,14 @@ export default function useGovernanceAssets() { name: 'Solend', image: '/img/solend.png', }, + [PackageEnum.Symmetry]: { + name: 'Symmetry', + image: '/img/symmetry.png', + }, + [PackageEnum.Squads]: { + name: 'Squads', + image: '/img/squads.png', + }, [PackageEnum.Switchboard]: { name: 'Switchboard', image: '/img/switchboard.png', @@ -265,6 +271,10 @@ export default function useGovernanceAssets() { name: 'Delegate Stake Account', packageId: PackageEnum.Common, }, + [Instructions.RemoveStakeLock]: { + name: 'Stake Account Remove Lock', + packageId: PackageEnum.Common, + }, [Instructions.DifferValidatorStake]: { name: 'Differ validator stake', // Not to be used for now @@ -292,9 +302,7 @@ export default function useGovernanceAssets() { name: 'None', isVisible: realm && - governancesArray.some((g) => - ownVoterWeight?.canCreateProposal(g.account.config) - ), + governancesArray.some((g) => canCreateProposal(g.account.config)), packageId: PackageEnum.Common, }, [Instructions.ProgramUpgrade]: { @@ -311,11 +319,24 @@ export default function useGovernanceAssets() { name: 'Stake A Validator', packageId: PackageEnum.Common, }, + [Instructions.SanctumDepositStake]: { + name: 'Sanctum Deposit Stake', + packageId: PackageEnum.Common, + }, + [Instructions.SanctumWithdrawStake]: { + name: 'Sanctum Withdraw Stake', + packageId: PackageEnum.Common, + }, [Instructions.Transfer]: { name: 'Transfer Tokens', isVisible: canUseTokenTransferInstruction, packageId: PackageEnum.Common, }, + [Instructions.Burn]: { + name: 'Burn Tokens', + isVisible: canUseTokenTransferInstruction, + packageId: PackageEnum.Common, + }, [Instructions.TransferDomainName]: { name: 'SNS Transfer Out Domain Name', packageId: PackageEnum.Common, @@ -337,6 +358,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,54 +426,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, - }, - - /* - ███████ ██████ ██████ ███████ ███████ ██ ██████ ██ ██ ████████ - ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - █████ ██ ██ ██████ █████ ███████ ██ ██ ███ ███████ ██ - ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ - ██ ██████ ██ ██ ███████ ███████ ██ ██████ ██ ██ ██ - */ - - [Instructions.ForesightAddMarketListToCategory]: { - name: 'Add Market List To Category', - packageId: PackageEnum.Foresight, - }, - [Instructions.ForesightInitCategory]: { - name: 'Init Category', - packageId: PackageEnum.Foresight, - }, - [Instructions.ForesightInitMarket]: { - name: 'Init Market', - packageId: PackageEnum.Foresight, - }, - [Instructions.ForesightInitMarketList]: { - name: 'Init Market List', - packageId: PackageEnum.Foresight, - }, - [Instructions.ForesightResolveMarket]: { - name: 'Resolve Market', - packageId: PackageEnum.Foresight, - }, - [Instructions.ForesightSetMarketMetadata]: { - name: 'Set Market Metadata', - packageId: PackageEnum.Foresight, - }, /* ██ ██████ ███████ ███ ██ ████████ ██ ████████ ██ ██ @@ -649,6 +637,21 @@ export default function useGovernanceAssets() { packageId: PackageEnum.PsyFinance, }, + /* + ██████ ██ ██ ████████ ██ ██ + ██ ██ ██ ██ ██ ██ ██ + ██████ ████ ██ ███████ + ██ ██ ██ ██ ██ + ██ ██ ██ ██ ██ + */ + [Instructions.PythRecoverAccount]: { + name: 'Recover Account', + packageId: PackageEnum.Pyth, + }, + [Instructions.PythUpdatePoolAuthority]: { + name: 'Update Pool Authority', + packageId: PackageEnum.Pyth, + }, /* ███████ ███████ ██████ ██ ██ ███ ███ ██ ██ ██ ██ ██ ██ ████ ████ @@ -719,6 +722,48 @@ export default function useGovernanceAssets() { packageId: PackageEnum.Solend, }, + /* + ███████ ██ ██ ███ ███ ███ ███ ███████ ████████ ██████ ██ ██ + ██ ██ ██ ████ ████ ████ ████ ██ ██ ██ ██ ██ ██ + ███████ ████ ██ ████ ██ ██ ████ ██ █████ ██ ██████ ████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ███████ ██ ██ ██ ██ ██ ███████ ██ ██ ██ ██ + */ + [Instructions.SymmetryCreateBasket]: { + name: 'Create Basket', + packageId: PackageEnum.Symmetry, + }, + [Instructions.SymmetryEditBasket]: { + name: 'Edit Basket', + packageId: PackageEnum.Symmetry, + }, + [Instructions.SymmetryDeposit]: { + name: 'Deposit into Basket', + packageId: PackageEnum.Symmetry, + }, + [Instructions.SymmetryWithdraw]: { + name: 'Withdraw from Basket', + packageId: PackageEnum.Symmetry, + }, + /* + ███████ ██████ ██ ██ █████ ██████ ███████ + ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ + ███████ ██ ██ ██ ██ ███████ ██ ██ ███████ + ██ ██ ▄▄ ██ ██ ██ ██ ██ ██ ██ ██ + ███████ ██████ ██████ ██ ██ ██████ ███████ + */ + [Instructions.SquadsMeshAddMember]: { + name: 'Mesh Add Member', + packageId: PackageEnum.Squads, + }, + [Instructions.SquadsMeshChangeThresholdMember]: { + name: 'Mesh Change Threshold', + packageId: PackageEnum.Squads, + }, + [Instructions.SquadsMeshRemoveMember]: { + name: 'Mesh Remove Member', + packageId: PackageEnum.Squads, + }, /* ███████ ██ ██ ██ ████████ ██████ ██ ██ ██████ ██████ █████ ██████ ██████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ diff --git a/hooks/useJoinRealm.ts b/hooks/useJoinRealm.ts new file mode 100644 index 0000000000..8effc5c9c5 --- /dev/null +++ b/hooks/useJoinRealm.ts @@ -0,0 +1,63 @@ +import {useUserCommunityTokenOwnerRecord} from "@hooks/queries/tokenOwnerRecord"; +import { withCreateTokenOwnerRecord } from '@solana/spl-governance' +import {useRealmQuery} from "@hooks/queries/realm"; +import useWalletOnePointOh from "@hooks/useWalletOnePointOh"; +import useProgramVersion from "@hooks/useProgramVersion"; +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {useCallback, useEffect, useState} from "react"; +import {TransactionInstruction} from "@solana/web3.js"; + +type UseJoinRealmReturnType = { + // use this to decide whether the join button should be displayed + userNeedsTokenOwnerRecord: boolean, + userNeedsVoterWeightRecords: boolean, + // returns an array of instructions that should be added to a transaction when the join button is clicked. + // will create the Token Owner Record if needed unless includeTokenOwnerRecord is false + // (this allows it to be chained with deposit instructions) + handleRegister: (includeTokenOwnerRecord?: boolean) => Promise +} + +export const useJoinRealm = (): UseJoinRealmReturnType => { + const tokenOwnerRecord = useUserCommunityTokenOwnerRecord().data?.result + const { createVoterWeightRecords } = useRealmVoterWeightPlugins(); + const realm = useRealmQuery().data?.result + const wallet = useWalletOnePointOh() + const programVersion = useProgramVersion() + const [userNeedsVoterWeightRecords, setUserNeedsVoterWeightRecords] = useState(false) + + // A user needs a token owner record if they don't have one already and either + // there are no plugins (vanilla realm) or + // the first plugin in the chain requires an input voter weight + const userNeedsTokenOwnerRecord = !tokenOwnerRecord; + useEffect(() => { + if (!wallet?.publicKey) return; + createVoterWeightRecords(wallet.publicKey) + .then((ixes) => setUserNeedsVoterWeightRecords(ixes.length > 0)); + }, [createVoterWeightRecords]) + + const handleRegister = useCallback(async (includeTokenOwnerRecord = true) => { + if (!wallet?.publicKey) return []; + + const onboardUserIxes = [] + if (includeTokenOwnerRecord && userNeedsTokenOwnerRecord && realm && programVersion) { + await withCreateTokenOwnerRecord(onboardUserIxes, + realm.owner, + programVersion, + realm.pubkey, + wallet.publicKey, + realm.account.communityMint, + wallet.publicKey) + } + + const createVoterWeightRecordIxes = await createVoterWeightRecords(wallet.publicKey); + return [...createVoterWeightRecordIxes, ...onboardUserIxes] + }, [realm?.pubkey.toBase58(), wallet?.publicKey?.toBase58(), programVersion, userNeedsTokenOwnerRecord]) + + return { + // use these to decide whether the join button should be displayed + userNeedsTokenOwnerRecord, + userNeedsVoterWeightRecords, + // returns an array of instructions that should be added to a transaction when the join button is clicked. + handleRegister + } +} \ No newline at end of file diff --git a/hooks/useMangoAccountsTreasury.ts b/hooks/useMangoAccountsTreasury.ts new file mode 100644 index 0000000000..73eb098a16 --- /dev/null +++ b/hooks/useMangoAccountsTreasury.ts @@ -0,0 +1,78 @@ +import useProgramSelector from '@components/Mango/useProgramSelector' +import BigNumber from 'bignumber.js' +import { useState, useEffect } from 'react' +import UseMangoV4 from './useMangoV4' +import { fetchMangoAccounts } from './useTreasuryInfo/assembleWallets' +import { convertAccountToAsset } from './useTreasuryInfo/convertAccountToAsset' +import { AccountType, AssetAccount } from '@utils/uiTypes/assets' +import { Asset } from '@models/treasury/Asset' +import { useRealmQuery } from './queries/realm' + +export function useMangoAccountsTreasury(assetAccounts: AssetAccount[]) { + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const [mangoAccountsValue, setMangoAccountsValue] = useState(new BigNumber(0)) + const [isFetching, setIsFetching] = useState(true) + const [isFetchingMangoAcc, setIsFetchingMangoAcc] = useState(false) + const [mangoAccWasFetched, setMangoAccWasFetched] = useState(false) + const realm = useRealmQuery().data?.result + + useEffect(() => { + async function fetchMangoValue() { + setMangoAccWasFetched(false) + setIsFetchingMangoAcc(true) + setMangoAccountsValue(new BigNumber(0)) + const filteredAssetAccounts = assetAccounts.filter( + (a) => a.type !== AccountType.PROGRAM && a.type !== AccountType.NFT + ) + const assets = ( + await Promise.all( + filteredAssetAccounts.map((a) => convertAccountToAsset(a)) + ) + ).filter((asset): asset is Asset => asset !== null) + const { mangoAccountsValue: newMangoValue } = await fetchMangoAccounts( + assets!, + mangoClient!, + mangoGroup + ) + + setIsFetchingMangoAcc(false) + setMangoAccWasFetched(true) + setMangoAccountsValue(newMangoValue) + } + + if ( + assetAccounts.length > 0 && + isFetching && + mangoClient && + mangoGroup && + realm && + !isFetchingMangoAcc && + !mangoAccWasFetched + ) { + fetchMangoValue().finally(() => { + setIsFetchingMangoAcc(false) + setIsFetching(false) + setMangoAccWasFetched(true) + }) + } + }, [ + assetAccounts, + isFetching, + mangoClient, + mangoGroup, + realm, + isFetchingMangoAcc, + mangoAccWasFetched, + ]) + + return { + isFetching, + mangoAccountsValue, + setMangoAccountsValue, + setIsFetching, + } +} diff --git a/hooks/useMangoV4.tsx b/hooks/useMangoV4.tsx index 9f2cbf3c91..db5277f83a 100644 --- a/hooks/useMangoV4.tsx +++ b/hooks/useMangoV4.tsx @@ -2,16 +2,19 @@ import { AnchorProvider } from '@coral-xyz/anchor' import { PublicKey } from '@solana/web3.js' import { ConnectionContext } from '@utils/connection' import { WalletSigner } from '@solana/spl-governance' +import Decimal from 'decimal.js' import { Group, MangoClient, MANGO_V4_ID, + Bank, + MangoAccount, } from '@blockworks-foundation/mango-v4' 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 +27,14 @@ 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 isMainMangoProgram = program.equals(MANGO_V4_ID[clientCluster]) const [mangoClient, setMangoClient] = useState(null) const [mangoGroup, setMangoGroup] = useState(null) const getClient = async ( @@ -41,7 +51,10 @@ export default function UseMangoV4() { const client = await MangoClient.connect( adminProvider, clientCluster, - MANGO_V4_ID[clientCluster] + program, + { + idsSource: isMainMangoProgram ? 'api' : undefined, + } ) return client @@ -54,11 +67,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) @@ -76,6 +94,40 @@ export default function UseMangoV4() { } } + const getMaxBorrowForBank = ( + group: Group, + bank: Bank, + mangoAccount: MangoAccount + ) => { + try { + const maxBorrow = new Decimal( + mangoAccount.getMaxWithdrawWithBorrowForTokenUi(group, bank.mint) + ) + return maxBorrow + } catch (e) { + console.log(`failed to get max borrow for ${bank.name}`, e) + return new Decimal(0) + } + } + + const getMaxWithdrawForBank = ( + group: Group, + bank: Bank, + mangoAccount: MangoAccount, + allowBorrow = false + ): Decimal => { + const accountBalance = new Decimal(mangoAccount.getTokenBalanceUi(bank)) + const vaultBalance = group.getTokenVaultBalanceByMintUi(bank.mint) + const maxBorrow = getMaxBorrowForBank(group, bank, mangoAccount) + const maxWithdraw = allowBorrow + ? Decimal.min(vaultBalance, maxBorrow) + : bank.initAssetWeight.toNumber() === 0 + ? Decimal.min(accountBalance, vaultBalance) + : Decimal.min(accountBalance, vaultBalance, maxBorrow) + + return Decimal.max(0, maxWithdraw) + } + return { ADMIN_PK, GROUP_NUM, @@ -84,5 +136,17 @@ export default function UseMangoV4() { mangoClient, mangoGroup, getAdditionalLabelInfo, + getMaxWithdrawForBank, } } + +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/useMaxVoteRecord.ts b/hooks/useMaxVoteRecord.ts index dddf667526..f701fc4657 100644 --- a/hooks/useMaxVoteRecord.ts +++ b/hooks/useMaxVoteRecord.ts @@ -1,15 +1,17 @@ -import { useMemo } from 'react' -import { MaxVoterWeightRecord, ProgramAccount } from '@solana/spl-governance' -import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' -import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore' +import {getMaxVoterWeightRecord} from '@solana/spl-governance' +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {useConnection} from "@solana/wallet-adapter-react"; +import {useAsync} from "react-async-hook"; export const useMaxVoteRecord = () => { - const nftMaxVoteRecord = useNftPluginStore((s) => s.state.maxVoteRecord) - const heliumMaxVoteRecord = useHeliumVsrStore((s) => s.state.maxVoteRecord) - const maxVoteWeightRecord: ProgramAccount | null = useMemo( - () => nftMaxVoteRecord || heliumMaxVoteRecord || null, - [nftMaxVoteRecord, heliumMaxVoteRecord] - ) + const { connection } = useConnection() + const { maxVoterWeightPk } = useRealmVoterWeightPlugins(); - return maxVoteWeightRecord + const maxVoteWeightRecord = useAsync(async () => + maxVoterWeightPk && + getMaxVoterWeightRecord(connection, maxVoterWeightPk), + [maxVoterWeightPk?.toBase58()] + ); + + return maxVoteWeightRecord.result } diff --git a/hooks/useNftRegistrar.ts b/hooks/useNftRegistrar.ts new file mode 100644 index 0000000000..f0e25bc7d6 --- /dev/null +++ b/hooks/useNftRegistrar.ts @@ -0,0 +1,8 @@ +import {useNftClient} from "../VoterWeightPlugins/useNftClient"; +import {NftVoter} from "../idls/nft_voter"; +import { IdlAccounts } from '@coral-xyz/anchor'; + +export const useNftRegistrar = () => { + const { plugin } = useNftClient(); + return plugin?.params as IdlAccounts['registrar'] | null; +} diff --git a/hooks/useNftRegistrarCollection.ts b/hooks/useNftRegistrarCollection.ts index b86475c243..4a860dc63e 100644 --- a/hooks/useNftRegistrarCollection.ts +++ b/hooks/useNftRegistrarCollection.ts @@ -1,14 +1,12 @@ -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { useRealmConfigQuery } from './queries/realmConfig' import { useMemo } from 'react' import { NFT_PLUGINS_PKS } from '@constants/plugins' +import {useNftRegistrar} from "@hooks/useNftRegistrar"; export const useNftRegistrarCollection = () => { const config = useRealmConfigQuery().data?.result + const nftMintRegistrar = useNftRegistrar(); const currentPluginPk = config?.account.communityTokenConfig.voterWeightAddin - const [nftMintRegistrar] = useVotePluginsClientStore((s) => [ - s.state.nftMintRegistrar, - ]) return useMemo( () => diff --git a/hooks/useProposalVotes.tsx b/hooks/useProposalVotes.tsx index 5113b42bd9..d83283b679 100644 --- a/hooks/useProposalVotes.tsx +++ b/hooks/useProposalVotes.tsx @@ -10,21 +10,28 @@ import { useRealmCouncilMintInfoQuery, } from './queries/mintInfo' import { useGovernanceByPubkeyQuery } from './queries/governance' +import usePythScalingFactor from './PythNetwork/useScalingFactor' +import useParclScalingFactor from './parcl/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(); + // This is always undefined except for parcl + const parclScalingFactor: number | undefined = useParclScalingFactor(); const programVersion = useProgramVersion() const proposalMint = proposal?.governingTokenMint.toBase58() === - realm?.account.communityMint.toBase58() + realm?.account.communityMint.toBase58() ? mint : councilMint // TODO: optimize using memo @@ -52,8 +59,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 +107,12 @@ export default function useProposalVotes(proposal?: Proposal) { voteThresholdPct, yesVotePct, yesVoteProgress, - yesVoteCount, - noVoteCount, + yesVoteCount: Math.floor(yesVoteCount * (pythScalingFactor || parclScalingFactor || 1)), + noVoteCount: Math.floor(noVoteCount * (pythScalingFactor || parclScalingFactor || 1)), relativeYesVotes, relativeNoVotes, minimumYesVotes, - yesVotesRequired, + yesVotesRequired: yesVotesRequired * (pythScalingFactor || parclScalingFactor || 1), } // @asktree: you may be asking yourself, "is this different from the more succinct way to write this?" @@ -166,11 +173,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/useRealm.tsx b/hooks/useRealm.tsx index 14b4153f42..8840ee1183 100644 --- a/hooks/useRealm.tsx +++ b/hooks/useRealm.tsx @@ -8,10 +8,6 @@ import { useUserCouncilTokenOwnerRecord, } from './queries/tokenOwnerRecord' import { useRealmConfigQuery } from './queries/realmConfig' -import { - useRealmCommunityMintInfoQuery, - useRealmCouncilMintInfoQuery, -} from './queries/mintInfo' import { useSelectedRealmInfo } from './selectedRealm/useSelectedRealmRegistryEntry' import { useUserTokenAccountsQuery } from './queries/tokenAccount' @@ -27,9 +23,6 @@ export default function useRealm() { const realmInfo = useSelectedRealmInfo() const config = useRealmConfigQuery().data?.result - const mint = useRealmCommunityMintInfoQuery().data?.result - const councilMint = useRealmCouncilMintInfoQuery().data?.result - const currentPluginPk = config?.account?.communityTokenConfig.voterWeightAddin const ownTokenRecord = useUserCommunityTokenOwnerRecord().data?.result @@ -55,13 +48,6 @@ export default function useRealm() { [realm, tokenAccounts] ) - const canChooseWhoVote = - realm?.account.communityMint && - (!mint?.supply.isZero() || - config?.account.communityTokenConfig.voterWeightAddin) && - realm.account.config.councilMint && - !councilMint?.supply.isZero() - //TODO take from realm config when available const realmCfgMaxOutstandingProposalCount = 10 const toManyCommunityOutstandingProposalsForUser = @@ -100,7 +86,6 @@ export default function useRealm() { /** @deprecated just use the token owner record directly, ok? */ //ownVoterWeight, //realmDisplayName: realmInfo?.displayName ?? realm?.account?.name, - canChooseWhoVote, //councilTokenOwnerRecords, toManyCouncilOutstandingProposalsForUse, toManyCommunityOutstandingProposalsForUser, @@ -111,7 +96,6 @@ export default function useRealm() { isNftMode, }), [ - canChooseWhoVote, councilTokenAccount, currentPluginPk, isNftMode, diff --git a/hooks/useRealmVoterWeightPlugins.ts b/hooks/useRealmVoterWeightPlugins.ts new file mode 100644 index 0000000000..46b593b8e1 --- /dev/null +++ b/hooks/useRealmVoterWeightPlugins.ts @@ -0,0 +1,149 @@ +// Exposes a 'realms-friendly' version of the generic useVoterWeightPlugins hook, +// which knows how to get the current realm, governance mint, and wallet public keys +// this simplifies usage across the realms codebase +import { useVoterWeightPlugins } from '../VoterWeightPlugins' +import { useRealmQuery } from '@hooks/queries/realm' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { GovernanceRole } from '../@types/types' +import { useSelectedDelegatorStore } from '../stores/useSelectedDelegatorStore' +import { UseVoterWeightPluginsReturnType } from '../VoterWeightPlugins/useVoterWeightPlugins' +import { PublicKey } from '@solana/web3.js' +import { CalculatedWeight } from '../VoterWeightPlugins/lib/types' +import useDelegators from '@components/VotePanel/useDelegators' +import {BN_ZERO} from "@solana/spl-governance"; +import {TokenOwnerRecord} from "@solana/spl-governance/lib/governance/accounts"; +import {SignerWalletAdapter} from "@solana/wallet-adapter-base"; + +export type UseRealmVoterWeightPluginsReturnType = UseVoterWeightPluginsReturnType & { + totalCalculatedVoterWeight: CalculatedWeight | undefined, + ownVoterWeight: CalculatedWeight | undefined + voterWeightForWallet: (walletPublicKey: PublicKey) => CalculatedWeight | undefined + voterWeightPkForWallet: (walletPublicKey: PublicKey) => PublicKey | undefined +} + +/** + * Select the wallets to determine the voter weights for as follows: + * - If a delegator is selected, use it only + * - If delegators are available, use them and the connected wallet (in first position) + * - If no delegators are available, use the connected wallet only + * @param selectedDelegator + * @param delegators + * @param wallet + */ +const getWalletList = ( + selectedDelegator: PublicKey | undefined, + delegators: TokenOwnerRecord[] | undefined, + wallet: SignerWalletAdapter | undefined +): PublicKey[] => { + if (!wallet?.publicKey) return []; + + // if selectedDelegator is not set, this means "yourself + all delegators" + if (selectedDelegator) { + return [selectedDelegator] + } + + if (delegators) { + const delegatorOwners = delegators.map((d) => d.governingTokenOwner) + + return [ + wallet.publicKey, + ...delegatorOwners + ] + } + + return [wallet.publicKey]; +} + +export const useRealmVoterWeightPlugins = ( + role: GovernanceRole = 'community' +): UseRealmVoterWeightPluginsReturnType => { + const realm = useRealmQuery().data?.result + const wallet = useWalletOnePointOh() + const governanceMintPublicKey = + role === 'community' + ? realm?.account.communityMint + : realm?.account.config.councilMint + const selectedDelegator = useSelectedDelegatorStore((s) => + role === 'community' ? s.communityDelegator : s.councilDelegator + ) + + const mainWalletPk = selectedDelegator || wallet?.publicKey + + const delegators = useDelegators(role) + const walletPublicKeys = getWalletList( + selectedDelegator, + delegators?.map(programAccount => programAccount.account), + wallet + ); + + // if a delegator is selected, use it, otherwise use the currently connected wallet + const nonAggregatedResult = useVoterWeightPlugins({ + realmPublicKey: realm?.pubkey, + governanceMintPublicKey, + walletPublicKeys, + realmConfig: realm?.account.config, + }) + + const totalCalculatedVoterWeight = nonAggregatedResult.calculatedVoterWeights?.length ? nonAggregatedResult.calculatedVoterWeights?.reduce( + (acc, weight) => { + if (!acc) return weight; + + const initialValue = weight.initialValue === null ? (acc.initialValue === null ? null : acc.initialValue) : weight.initialValue.add(acc.initialValue ?? BN_ZERO); + const value = weight.value === null ? (acc.value === null ? null : acc.value) : weight.value.add(acc.value ?? BN_ZERO); + // Note - voter-specific details (e.g. plugin weights) are not aggregated and just use the first one + const details = acc.details + + return { + details, + initialValue, + value, + } + } + ) : undefined; + + + // This requires that the index of the wallet in the list of wallets remains consistent with the output voter weights, + // while not ideal, this is simpler than the alternative, which would be to return a map of wallet public keys to voter weights + // or something similar. + const voterWeightForWallet = (walletPublicKey: PublicKey): CalculatedWeight | undefined => { + const walletIndex = walletPublicKeys.findIndex((pk) => pk.equals(walletPublicKey)) + if (walletIndex === -1) return undefined; // the wallet is not one of the ones passed in + return nonAggregatedResult.calculatedVoterWeights?.[walletIndex] + } + + const voterWeightPkForWallet = (walletPublicKey: PublicKey): PublicKey | undefined => { + const walletIndex = walletPublicKeys.findIndex((pk) => pk.equals(walletPublicKey)) + if (walletIndex === -1) return undefined; // the wallet is not one of the ones passed in + return nonAggregatedResult.voterWeightPks?.[walletIndex] + } + + const ownVoterWeight = mainWalletPk ? voterWeightForWallet(mainWalletPk) : undefined + + return { + ...nonAggregatedResult, + totalCalculatedVoterWeight, + ownVoterWeight, + voterWeightForWallet, + voterWeightPkForWallet, + } +} + +// Get the current weights for the community and council governances - should be used in cases where the realm is known but the choice of governance is not, +// e.g. when creating a proposal +export const useRealmVoterWeights = () => { + const { + calculatedMaxVoterWeight: communityMaxWeight, + totalCalculatedVoterWeight: communityWeight, + } = useRealmVoterWeightPlugins('community') + const { + calculatedMaxVoterWeight: councilMaxWeight, + totalCalculatedVoterWeight: councilWeight, + } = useRealmVoterWeightPlugins('council') + + return { + communityMaxWeight, + communityWeight, + councilMaxWeight, + councilWeight, + } +} diff --git a/hooks/useSubmitVote.ts b/hooks/useSubmitVote.ts index 447087dd3b..2571fe2a50 100644 --- a/hooks/useSubmitVote.ts +++ b/hooks/useSubmitVote.ts @@ -1,6 +1,5 @@ import useWalletOnePointOh from './useWalletOnePointOh' import useRealm from './useRealm' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useNftProposalStore from 'NftVotePlugin/NftProposalStore' import { useAsyncCallback } from 'react-async-hook' import { @@ -22,34 +21,29 @@ import { castVote } from 'actions/castVote' import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' import { notify } from '@utils/notifications' import { useRealmQuery } from './queries/realm' -import { useRealmConfigQuery } from './queries/realmConfig' import { proposalQueryKeys, useRouteProposalQuery } from './queries/proposal' import useLegacyConnectionContext from './useLegacyConnectionContext' -import { NFT_PLUGINS_PKS } from '@constants/plugins' import { TransactionInstruction } from '@solana/web3.js' import useProgramVersion from './useProgramVersion' import useVotingTokenOwnerRecords from './useVotingTokenOwnerRecords' import { useMemo } from 'react' import { useSelectedDelegatorStore } from 'stores/useSelectedDelegatorStore' import { useBatchedVoteDelegators } from '@components/VotePanel/useDelegators' +import { useVotingClients } from '@hooks/useVotingClients' +import { useNftClient } from '../VoterWeightPlugins/useNftClient' +import { useRealmVoterWeightPlugins } from './useRealmVoterWeightPlugins' export const useSubmitVote = () => { const wallet = useWalletOnePointOh() const connection = useLegacyConnectionContext() const realm = useRealmQuery().data?.result - const config = useRealmConfigQuery().data?.result const proposal = useRouteProposalQuery().data?.result const { realmInfo } = useRealm() const { closeNftVotingCountingModal } = useNftProposalStore.getState() - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients() // TODO this should be passed the role + const { nftClient } = useNftClient() - const isNftPlugin = - config?.account.communityTokenConfig.voterWeightAddin && - NFT_PLUGINS_PKS.includes( - config?.account.communityTokenConfig.voterWeightAddin?.toBase58() - ) + const isNftPlugin = !!nftClient const selectedCommunityDelegator = useSelectedDelegatorStore( (s) => s.communityDelegator @@ -60,6 +54,13 @@ export const useSubmitVote = () => { const communityDelegators = useBatchedVoteDelegators('community') const councilDelegators = useBatchedVoteDelegators('council') + const { + voterWeightForWallet: voterWeightForWalletCommunity, + } = useRealmVoterWeightPlugins('community') + const { + voterWeightForWallet: voterWeightForWalletCouncil, + } = useRealmVoterWeightPlugins('council') + const { error, loading, execute } = useAsyncCallback( async ({ vote, @@ -131,6 +132,17 @@ export const useSubmitVote = () => { : councilDelegators )?.map((x) => x.pubkey) + const voterWeightForWallet = + role === 'community' + ? voterWeightForWalletCommunity + : voterWeightForWalletCouncil + const ownVoterWeight = relevantSelectedDelegator + ? voterWeightForWallet(relevantSelectedDelegator) + : wallet?.publicKey + ? voterWeightForWallet(wallet?.publicKey) + : undefined + + const votingClient = votingClients(role) try { await castVote( rpcContext, @@ -139,10 +151,11 @@ export const useSubmitVote = () => { tokenOwnerRecordPk, vote, msg, - role === 'community' ? client : undefined, // NOTE: currently FE doesn't support council plugins fully + votingClient, confirmationCallback, voteWeights, - relevantDelegators + relevantDelegators, + ownVoterWeight?.value ) queryClient.invalidateQueries({ queryKey: proposalQueryKeys.all(connection.current.rpcEndpoint), @@ -154,10 +167,13 @@ export const useSubmitVote = () => { } catch (e) { console.error(e) notify({ type: 'error', message: e.message }) + if (msg) { + throw e + } } finally { if (isNftPlugin) { closeNftVotingCountingModal( - client.client as NftVoterClient, + votingClient.client as NftVoterClient, proposal!, wallet!.publicKey! ) @@ -188,10 +204,8 @@ export const useCreateVoteIxs = () => { const programVersion = useProgramVersion() const realm = useRealmQuery().data?.result const wallet = useWalletOnePointOh() - const votingPluginClient = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) const getVotingTokenOwnerRecords = useVotingTokenOwnerRecords() + const votingClients = useVotingClients() // get delegates @@ -204,7 +218,6 @@ export const useCreateVoteIxs = () => { walletPk !== undefined ? // eslint-disable-next-line @typescript-eslint/no-unused-vars async ({ voteKind, governingBody, proposal, comment }: VoteArgs) => { - //const signers: Keypair[] = [] const instructions: TransactionInstruction[] = [] const governingTokenMint = @@ -214,12 +227,13 @@ export const useCreateVoteIxs = () => { if (governingTokenMint === undefined) throw new Error(`no mint for ${governingBody} governing body`) + const votingClient = votingClients(governingBody) const vote = formatVote(voteKind) const votingTors = await getVotingTokenOwnerRecords(governingBody) for (const torPk of votingTors) { //will run only if any plugin is connected with realm - const votingPluginHelpers = await votingPluginClient?.withCastPluginVote( + const votingPluginHelpers = await votingClient.withCastPluginVote( instructions, proposal, torPk @@ -246,13 +260,7 @@ export const useCreateVoteIxs = () => { } } : undefined, - [ - getVotingTokenOwnerRecords, - programVersion, - realm, - votingPluginClient, - walletPk, - ] + [getVotingTokenOwnerRecords, programVersion, realm, votingClients, walletPk] ) } diff --git a/hooks/useTotalTreasuryPrice.ts b/hooks/useTotalTreasuryPrice.ts index 9615116dcb..e56ba44bb7 100644 --- a/hooks/useTotalTreasuryPrice.ts +++ b/hooks/useTotalTreasuryPrice.ts @@ -6,6 +6,7 @@ import { useJupiterPricesByMintsQuery } from './queries/jupiterPrice' import { PublicKey } from '@metaplex-foundation/js' import { WSOL_MINT } from '@components/instructions/tools' import { AccountType } from '@utils/uiTypes/assets' +import { useMangoAccountsTreasury } from './useMangoAccountsTreasury' export function useTotalTreasuryPrice() { const { @@ -26,6 +27,10 @@ export function useTotalTreasuryPrice() { new PublicKey(WSOL_MINT), ]) + const { mangoAccountsValue, isFetching } = useMangoAccountsTreasury( + assetAccounts + ) + const totalTokensPrice = [ ...governedTokenAccountsWithoutNfts, ...auxiliaryTokenAccounts, @@ -57,11 +62,13 @@ export function useTotalTreasuryPrice() { const totalPrice = totalTokensPrice + stakeAccountsTotalPrice - const totalPriceFormatted = governedTokenAccountsWithoutNfts.length - ? new BigNumber(totalPrice).toFormat(0) - : '' + const totalPriceFormatted = (governedTokenAccountsWithoutNfts.length + ? new BigNumber(totalPrice) + : new BigNumber(0) + ).plus(mangoAccountsValue) return { + isFetching, totalPriceFormatted, } } diff --git a/hooks/useTreasuryInfo/assembleWallets.tsx b/hooks/useTreasuryInfo/assembleWallets.tsx index 95ec2a22aa..bf6c72f61b 100644 --- a/hooks/useTreasuryInfo/assembleWallets.tsx +++ b/hooks/useTreasuryInfo/assembleWallets.tsx @@ -9,7 +9,14 @@ import { import { SparklesIcon } from '@heroicons/react/outline' import { AssetAccount, AccountType } from '@utils/uiTypes/assets' -import { AssetType, Token, RealmAuthority } from '@models/treasury/Asset' +import { + AssetType, + Token, + RealmAuthority, + Asset, + Mango, + Sol, +} from '@models/treasury/Asset' import { AuxiliaryWallet, Wallet } from '@models/treasury/Wallet' import { getAccountName } from '@components/instructions/tools' import { RealmInfo } from '@models/registry/api' @@ -26,16 +33,79 @@ import { Domain } from '@models/treasury/Domain' import { groupDomainsByWallet } from './groupDomainsByWallet' import { ConnectionContext } from '@utils/connection' import { PublicKey } from '@solana/web3.js' +import { + MangoClient, + Group, + MangoAccount, + I80F48, + toUiDecimals, +} from '@blockworks-foundation/mango-v4' +import { BN } from '@coral-xyz/anchor' function isNotNull(x: T | null): x is T { return x !== null } +export async function fetchMangoAccounts( + assets: Asset[], + mangoClient: MangoClient | null, + mangoGroup: Group | null +) { + if (!mangoClient || !mangoGroup) { + return { + mangoAccountsValue: new BigNumber(0), + mangoAccounts: [], + } + } + + const tokenAccountOwners = Array.from( + new Set( + assets + .filter((a) => a.type === AssetType.Token) + .filter((a: Token) => a.raw.extensions.token) + .filter((a: Token) => a.raw.extensions.token!.account.owner) + .map((a: Token) => a.raw.extensions.token!.account.owner.toString()) + ) + ).map((o) => new PublicKey(o)) + + const mangoAccounts: MangoAccount[] = [] + if (tokenAccountOwners.length <= 2) { + for (const tokenAccountOwner of tokenAccountOwners) { + const accounts = await mangoClient.getMangoAccountsForOwner( + mangoGroup, + tokenAccountOwner + ) + + if (accounts) { + mangoAccounts.push(...accounts) + } + } + } + + const mangoAccountsValue = mangoAccounts.reduce((acc: I80F48, account) => { + try { + const value = account.getAssetsValue(mangoGroup!) + acc = acc.add(value) + return acc + } catch (e) { + console.log(e) + return acc + } + }, new I80F48(new BN(0))) + + return { + mangoAccountsValue: new BigNumber(toUiDecimals(mangoAccountsValue, 6)), + mangoAccounts, + } +} + export const assembleWallets = async ( connection: ConnectionContext, accounts: AssetAccount[], domains: Domain[], programId: PublicKey, + mangoGroup: Group | null, + mangoClient: MangoClient | null, councilMintAddress?: string, communityMintAddress?: string, councilMint?: MintInfo, @@ -172,7 +242,7 @@ export const assembleWallets = async ( } } - walletMap[walletAddress].assets.push({ + walletMap[walletAddress].assets.unshift({ type: AssetType.Domain, id: 'domain-list', count: new BigNumber(domainList.length), @@ -180,8 +250,23 @@ export const assembleWallets = async ( }) } - const allWallets = Object.values(walletMap) - .map((wallet) => ({ + const allWallets: any[] = [] + for (const wallet of Object.values(walletMap)) { + const { mangoAccountsValue } = await fetchMangoAccounts( + wallet.assets, + mangoClient, + mangoGroup + ) + + if (mangoAccountsValue.gt(0)) { + wallet.assets.push({ + id: 'mango', + type: AssetType.Mango, + value: mangoAccountsValue, + }) + } + + allWallets.push({ ...wallet, name: wallet.governanceAddress ? getAccountName(wallet.governanceAddress) @@ -191,27 +276,29 @@ export const assembleWallets = async ( 'value' in asset ? asset.value : new BigNumber(0) ) ), - })) - .sort((a, b) => { - if (a.totalValue.isZero() && b.totalValue.isZero()) { - const aContainsSortable = a.assets.some( - (asset) => asset.type === AssetType.Programs - ) - const bContainsSortable = b.assets.some( - (asset) => asset.type === AssetType.Programs - ) + }) + } - if (aContainsSortable && !bContainsSortable) { - return -1 - } else if (!aContainsSortable && bContainsSortable) { - return 1 - } else { - return b.assets.length - a.assets.length - } + allWallets.sort((a, b) => { + if (a.totalValue.isZero() && b.totalValue.isZero()) { + const aContainsSortable = a.assets.some( + (asset) => asset.type === AssetType.Programs + ) + const bContainsSortable = b.assets.some( + (asset) => asset.type === AssetType.Programs + ) + + if (aContainsSortable && !bContainsSortable) { + return -1 + } else if (!aContainsSortable && bContainsSortable) { + return 1 + } else { + return b.assets.length - a.assets.length } + } - return b.totalValue.comparedTo(a.totalValue) - }) + return b.totalValue.comparedTo(a.totalValue) + }) const auxiliaryAssets = ( await Promise.all( @@ -220,11 +307,23 @@ export const assembleWallets = async ( convertAccountToAsset({ ...account, type: AccountType.TOKEN, - }) as Promise + }) as Promise ) ) ).filter(isNotNull) + const { + mangoAccountsValue: auxMangoAccountsValue, + } = await fetchMangoAccounts(auxiliaryAssets, mangoClient!, mangoGroup!) + + if (auxMangoAccountsValue.gt(0)) { + auxiliaryAssets.unshift({ + id: 'mango', + type: AssetType.Mango, + value: auxMangoAccountsValue, + }) + } + const auxiliaryWallets: AuxiliaryWallet[] = auxiliaryAssets.length ? [ { 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/useTreasuryInfo/index.tsx b/hooks/useTreasuryInfo/index.tsx index e0d00b604f..b9f3d8b8a0 100644 --- a/hooks/useTreasuryInfo/index.tsx +++ b/hooks/useTreasuryInfo/index.tsx @@ -17,6 +17,8 @@ import { useRealmCouncilMintInfoQuery, } from '@hooks/queries/mintInfo' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import UseMangoV4 from '@hooks/useMangoV4' +import useProgramSelector from '@components/Mango/useProgramSelector' interface Data { auxiliaryWallets: AuxiliaryWallet[] @@ -41,6 +43,12 @@ export default function useTreasuryInfo( const connection = useLegacyConnectionContext() const accounts = useGovernanceAssetsStore((s) => s.assetAccounts) + const programSelectorHook = useProgramSelector() + const { mangoClient, mangoGroup } = UseMangoV4( + programSelectorHook.program?.val, + programSelectorHook.program?.group + ) + const loadingGovernedAccounts = useGovernanceAssetsStore( (s) => s.loadGovernedAccounts ) @@ -84,6 +92,8 @@ export default function useTreasuryInfo( accounts, domains, realmInfo.programId, + mangoGroup, + mangoClient, realm?.account.config.councilMint?.toBase58(), realm?.account.communityMint?.toBase58(), councilMint, diff --git a/hooks/useVoteByCouncilToggle.ts b/hooks/useVoteByCouncilToggle.ts new file mode 100644 index 0000000000..7c17104d0b --- /dev/null +++ b/hooks/useVoteByCouncilToggle.ts @@ -0,0 +1,65 @@ +// The voteByCouncil toggle UI is avaiable on a number of views in Realms. +// Whether it is available, or enabled, is determined by the realm's config and the user's tokens. +// This hook encapsulates this logic +import { useEffect, useState } from 'react' +import { useRealmVoterWeights } from '@hooks/useRealmVoterWeightPlugins' +import BN from 'bn.js' +import { GovernanceRole } from '../@types/types' + +const onlyGovernanceAvailable = ( + availableVoteGovernanceOptions: GovernanceRole[], + role: GovernanceRole +) => + availableVoteGovernanceOptions.length === 1 && + availableVoteGovernanceOptions[0] === role + +type UseVoteByCouncilToggleValue = { + // Allow the UI to decide whether the toggle should be shown + // False if there is only one option + // NOTE: ignore this if you always want to show the toggle if the user has council tokens (even if they don't have community tokens) + shouldShowVoteByCouncilToggle: boolean + // The value of the UI toggle + // True if this proposal should be voted by council + voteByCouncil: boolean + // Set the value of the UI toggle + setVoteByCouncil: (value: boolean) => void +} + +export const useVoteByCouncilToggle = (): UseVoteByCouncilToggleValue => { + const { communityMaxWeight, councilMaxWeight } = useRealmVoterWeights() + const availableVoteGovernanceOptions = [ + communityMaxWeight?.value?.gt(new BN(0)) ? 'community' : undefined, + councilMaxWeight?.value?.gt(new BN(0)) ? 'council' : undefined, + ].filter(Boolean) as GovernanceRole[] // filter out undefined + const [voteByCouncil, setVoteByCouncil] = useState(false) + + // once availableVoteGovernanceOptions is available, we set the default vote level (if there is only one option) + useEffect(() => { + if (onlyGovernanceAvailable(availableVoteGovernanceOptions, 'council')) { + setVoteByCouncil(true) + } else if ( + onlyGovernanceAvailable(availableVoteGovernanceOptions, 'community') + ) { + setVoteByCouncil(false) + } + }, [availableVoteGovernanceOptions]) + + // the proposal will use the council if: + // - that is the only option + // - the proposer chooses it + const updateVoteByCouncilToggle = (value: boolean) => { + // only set it to false if there is another option + if ( + value || + !onlyGovernanceAvailable(availableVoteGovernanceOptions, 'council') + ) { + setVoteByCouncil(value) + } + } + + return { + shouldShowVoteByCouncilToggle: availableVoteGovernanceOptions.length > 1, + voteByCouncil, + setVoteByCouncil: updateVoteByCouncilToggle, + } +} diff --git a/hooks/useVoteRecords.ts b/hooks/useVoteRecords.ts index dcb1599442..6eeb2c1500 100644 --- a/hooks/useVoteRecords.ts +++ b/hooks/useVoteRecords.ts @@ -14,7 +14,6 @@ import useRpcContext from '@hooks/useRpcContext' import { getVoteRecords, getTokenOwnerRecords } from '@models/proposal' import useRealm from '@hooks/useRealm' import { buildTopVoters } from '@models/proposal' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { getLockTokensVotingPowerPerWallet } from 'VoteStakeRegistry/tools/deposits' import { BN } from '@coral-xyz/anchor' import useGovernanceAssetsStore from 'stores/useGovernanceAssetsStore' @@ -27,6 +26,8 @@ import { getNetworkFromEndpoint } from '@utils/connection' import { fetchDigitalAssetsByOwner } from './queries/digitalAssets' import { useNftRegistrarCollection } from './useNftRegistrarCollection' import { useAsync } from 'react-async-hook' +import {useVsrClient} from "../VoterWeightPlugins/useVsrClient"; +import {useNftRegistrar} from "@hooks/useNftRegistrar"; export default function useVoteRecords(proposal?: ProgramAccount) { const { getRpcContext } = useRpcContext() @@ -52,7 +53,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { /// const [context, setContext] = useState(null) - const client = useVotePluginsClientStore((s) => s.state.vsrClient) + const { vsrClient } = useVsrClient(); const connection = useLegacyConnectionContext() const governingTokenMintPk = proposal?.account.governingTokenMint @@ -61,9 +62,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { // In buildTopVoters.ts, it checks whether the token_owner_record is in the vote_record. // If not, the function use record.account.governingTokenDepositAmount as the undecided vote weight, where nft-voter should be 0. // Thus, pre-calculating the undecided weight for each nft voter is necessary. - const [nftMintRegistrar] = useVotePluginsClientStore((s) => [ - s.state.nftMintRegistrar, - ]) + const nftMintRegistrar = useNftRegistrar(); const usedCollectionsPks: string[] = useNftRegistrarCollection() const { result: undecidedNftsByVoteRecord } = useAsync(async () => { @@ -165,7 +164,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { const nftVoterPluginTotalWeight = nftMintRegistrar?.collectionConfigs.reduce( (prev, curr) => { const size = curr.size - const weight = curr.weight + const weight = curr.weight.toNumber() if (typeof size === 'undefined' || typeof weight === 'undefined') return prev return prev + size * weight @@ -177,7 +176,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { tokenOwnerRecords, mint, undecidedNftsByVoteRecord ?? {}, - new BN(nftVoterPluginTotalWeight) + new BN(nftVoterPluginTotalWeight ?? 0) ) } return [] @@ -196,12 +195,12 @@ export default function useVoteRecords(proposal?: ProgramAccount) { useEffect(() => { //VSR only const handleGetVsrVotingPowers = async (walletsPks: PublicKey[]) => { - if (!realm || !client) throw new Error() + if (!realm || !vsrClient) throw new Error() const votingPerWallet = await getLockTokensVotingPowerPerWallet( walletsPks, realm, - client, + vsrClient, connection.current ) setUndecidedDepositByVoteRecord(votingPerWallet) @@ -221,7 +220,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { tokenOwnerRecord.account.governingTokenOwner.toBase58() ) ) - if (undecidedData.length && mintsUsedInRealm.length && realm && client) { + if (undecidedData.length && mintsUsedInRealm.length && realm && vsrClient) { handleGetVsrVotingPowers( undecidedData.map((x) => x.account.governingTokenOwner) ) @@ -235,7 +234,7 @@ export default function useVoteRecords(proposal?: ProgramAccount) { tokenOwnerRecords, voteRecords, realm, - client, + vsrClient, connection, mintsUsedInRealm, ]) diff --git a/hooks/useVotingClients.ts b/hooks/useVotingClients.ts new file mode 100644 index 0000000000..e870a45058 --- /dev/null +++ b/hooks/useVotingClients.ts @@ -0,0 +1,60 @@ +import {useRealmVoterWeightPlugins} from "@hooks/useRealmVoterWeightPlugins"; +import {useRealmQuery} from "@hooks/queries/realm"; +import useWalletOnePointOh from "@hooks/useWalletOnePointOh"; +import {VotingClient} from "@utils/uiTypes/VotePlugin"; +import {GovernanceRole} from "../@types/types"; +import {PublicKey} from "@solana/web3.js"; +import {useSelectedDelegatorStore} from "../stores/useSelectedDelegatorStore"; + +/** + * The Voting Client encapsulates plugin-specific voting logic not currently encapsulated in the individual plugins, and exposed by the + * useVoterWeightPlugins hook. + * As such, it should be used only if the useVoterWeightPlugins hook is insufficient, or in places where access to hooks is not available. + * Since in the latter cases, it is not always clear which governance role to use, it exposes a callback to get the correct client for a given role. + */ +export const useVotingClients = () => { + const voterWeightPluginDetailsForCommunity = useRealmVoterWeightPlugins('community'); + const voterWeightPluginDetailsForCouncil = useRealmVoterWeightPlugins('council'); + const realm = useRealmQuery().data?.result + const wallet = useWalletOnePointOh() + + const selectedCouncilDelegator = useSelectedDelegatorStore( + (s) => s.councilDelegator + ) + const selectedCommunityDelegator = useSelectedDelegatorStore( + (s) => s.communityDelegator + ) + const councilWallet = selectedCouncilDelegator ?? wallet?.publicKey; + const communityWallet = selectedCommunityDelegator ?? wallet?.publicKey; + + + // This is not cached at present, but should be efficient, as the contents (plugins) are cached. + // If this becomes a performance issue, we should add react-query here. + return (kind: GovernanceRole) => { + // messy logic to get the "legacy" client out of the plugins. + // if there's more than one, use the first one. + // this only works if the legacy plugins don't support chaining anyway. + // if they did, then we would have to call relinquish on whichever plugin supported it + const voterWeightPluginDetails = kind === 'community' ? voterWeightPluginDetailsForCommunity : voterWeightPluginDetailsForCouncil; + const client = voterWeightPluginDetails.plugins?.voterWeight.length ? voterWeightPluginDetails.plugins.voterWeight[0].client : undefined; + const wallet = kind === 'community' ? communityWallet : councilWallet; + + return new VotingClient({ + client: client, + realm: realm, + walletPk: wallet, + voterWeightPluginDetails + }); + }; +} + +// If we know the governingTokenMint, we can deduce the role. +// This is a little convoluted, but necessary in places, until we decommission the voting client. +export const useVotingClientForGoverningTokenMint = (governingTokenMint: PublicKey | undefined) => { + const clients = useVotingClients(); + const realm = useRealmQuery().data?.result + // default to community if there is no council or the realm or governingTokenMint are not yet loaded + const kind = governingTokenMint && realm?.account.config.councilMint?.equals(governingTokenMint) ? 'council' : 'community'; + + return clients(kind); +} \ No newline at end of file diff --git a/hooks/useVotingPlugins.ts b/hooks/useVotingPlugins.ts deleted file mode 100644 index 5bbbe030d0..0000000000 --- a/hooks/useVotingPlugins.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { useCallback, useEffect, useMemo } from 'react' -import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { getMaxVoterWeightRecord } from '@solana/spl-governance' -import { getMaxVoterWeightRecord as getPluginMaxVoterWeightRecord } from '@utils/plugin/accounts' -import { notify } from '@utils/notifications' - -import useGatewayPluginStore from '../GatewayPlugin/store/gatewayPluginStore' -import { getGatekeeperNetwork } from '../GatewayPlugin/sdk/accounts' -import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore' -import * as heliumVsrSdk from '@helium/voter-stake-registry-sdk' -import useWalletOnePointOh from './useWalletOnePointOh' -import { useRealmQuery } from './queries/realm' -import { useRealmConfigQuery } from './queries/realmConfig' -import useLegacyConnectionContext from './useLegacyConnectionContext' -import { - NFT_PLUGINS_PKS, - HELIUM_VSR_PLUGINS_PKS, - VSR_PLUGIN_PKS, - GATEWAY_PLUGINS_PKS, - PYTH_PLUGIN_PK, -} from '../constants/plugins' -import useUserOrDelegator from './useUserOrDelegator' - -export function useVotingPlugins() { - const realm = useRealmQuery().data?.result - const config = useRealmConfigQuery().data?.result - const currentPluginPk = config?.account.communityTokenConfig.voterWeightAddin - const voterPk = useUserOrDelegator() - - const { - handleSetVsrRegistrar, - handleSetVsrClient, - handleSetHeliumVsrRegistrar, - handleSetHeliumVsrClient, - handleSetNftClient, - handleSetGatewayClient, - handleSetNftRegistrar, - handleSetGatewayRegistrar, - handleSetCurrentRealmVotingClient, - handleSetPythClient, - } = useVotePluginsClientStore() - - const [setNftMaxVoterWeight] = useNftPluginStore((s) => [s.setMaxVoterWeight]) - - // @asktree: you should select what you need from stores, not use entire thing - const heliumStore = useHeliumVsrStore() - const gatewayStore = useGatewayPluginStore() - const wallet = useWalletOnePointOh() - const connection = useLegacyConnectionContext() - const connected = !!wallet?.connected - - const [ - currentClient, - vsrClient, - gatewayClient, - nftClient, - nftMintRegistrar, - heliumVsrClient, - pythClient, - ] = useVotePluginsClientStore((s) => [ - s.state.currentRealmVotingClient, - s.state.vsrClient, - s.state.gatewayClient, - s.state.nftClient, - s.state.nftMintRegistrar, - s.state.heliumVsrClient, - s.state.pythClient, - s.state.heliumVsrRegistrar, - ]) - - const usedCollectionsPks: string[] = useMemo( - () => - (currentPluginPk && - NFT_PLUGINS_PKS.includes(currentPluginPk?.toBase58()) && - nftMintRegistrar?.collectionConfigs.map((x) => - x.collection.toBase58() - )) || - [], - [currentPluginPk, nftMintRegistrar?.collectionConfigs] - ) - - const handleRegisterGatekeeperNetwork = useCallback(async () => { - if (realm && gatewayClient) { - gatewayStore.setIsLoadingGatewayToken(true) - - try { - const gatekeeperNetwork = await getGatekeeperNetwork( - gatewayClient, - realm - ) - - gatewayStore.setGatekeeperNetwork(gatekeeperNetwork) - } catch (e) { - console.log(e) - notify({ - message: 'Error fetching gateway token', - type: 'error', - }) - } - gatewayStore.setIsLoadingGatewayToken(false) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - gatewayClient, - //gatewayStore, - realm, - ]) - - // initialise pyth plugin - useEffect(() => { - if ( - wallet && - connection && - currentPluginPk && - PYTH_PLUGIN_PK.includes(currentPluginPk.toBase58()) - ) { - handleSetPythClient(wallet, connection) - } - }, [connection, currentPluginPk, handleSetPythClient, wallet]) - - useEffect(() => { - if (wallet && connection) { - if (currentPluginPk) { - if (VSR_PLUGIN_PKS.includes(currentPluginPk.toBase58())) { - handleSetVsrClient(wallet, connection, currentPluginPk) - } - if (HELIUM_VSR_PLUGINS_PKS.includes(currentPluginPk.toBase58())) { - handleSetHeliumVsrClient(wallet, connection, currentPluginPk) - } - } - handleSetNftClient(wallet, connection) - handleSetGatewayClient(wallet, connection) - } - }, [ - connection, - currentPluginPk, - handleSetGatewayClient, - handleSetHeliumVsrClient, - handleSetNftClient, - handleSetVsrClient, - wallet, - ]) - - useEffect(() => { - const handleVsrPlugin = () => { - if ( - vsrClient && - currentPluginPk && - VSR_PLUGIN_PKS.includes(currentPluginPk.toBase58()) - ) { - handleSetVsrRegistrar(vsrClient, realm) - if (voterPk) { - handleSetCurrentRealmVotingClient({ - client: vsrClient, - realm, - walletPk: voterPk, - }) - } - } - } - - const handleHeliumVsrPlugin = () => { - if ( - heliumVsrClient && - currentPluginPk && - HELIUM_VSR_PLUGINS_PKS.includes(currentPluginPk.toBase58()) - ) { - handleSetHeliumVsrRegistrar(heliumVsrClient, realm) - if (voterPk) { - handleSetCurrentRealmVotingClient({ - client: heliumVsrClient, - realm, - walletPk: voterPk, - }) - } - } - } - - const handleNftplugin = () => { - if ( - nftClient && - currentPluginPk && - NFT_PLUGINS_PKS.includes(currentPluginPk.toBase58()) - ) { - handleSetNftRegistrar(nftClient, realm) - if (voterPk) { - handleSetCurrentRealmVotingClient({ - client: nftClient, - realm, - walletPk: voterPk, - }) - } - } - } - - const handlePythPlugin = () => { - if ( - pythClient && - currentPluginPk && - PYTH_PLUGIN_PK.includes(currentPluginPk.toBase58()) - ) { - if (voterPk) { - handleSetCurrentRealmVotingClient({ - client: pythClient, - realm, - walletPk: voterPk, - }) - } - } - } - - // If the current realm uses Civic Pass - // register the gatekeeper network (the "type" of Civic) - // in the Civic GatewayProvider. - // This updates the UI to show if the user has a gateway token - const handleGatewayPlugin = () => { - if ( - gatewayClient && - currentPluginPk && - GATEWAY_PLUGINS_PKS.includes(currentPluginPk.toBase58()) - ) { - handleSetGatewayRegistrar(gatewayClient, realm) - if (voterPk) { - handleSetCurrentRealmVotingClient({ - client: gatewayClient, - realm, - walletPk: voterPk, - }) - } - - handleRegisterGatekeeperNetwork() - } - } - - if ( - realm && - (!currentClient || - currentClient.realm?.pubkey.toBase58() !== realm.pubkey.toBase58() || - (voterPk && currentClient.walletPk?.toBase58() !== voterPk.toBase58())) - ) { - console.log( - 'setting plugin; if this is getting spammed, this store just needs to be refactored away' - ) - handleNftplugin() - handleGatewayPlugin() - handleVsrPlugin() - handleHeliumVsrPlugin() - handlePythPlugin() - } - }, [ - currentClient, - currentPluginPk, - gatewayClient, - handleRegisterGatekeeperNetwork, - handleSetCurrentRealmVotingClient, - handleSetGatewayRegistrar, - handleSetHeliumVsrRegistrar, - handleSetNftRegistrar, - handleSetVsrRegistrar, - heliumVsrClient, - nftClient, - voterPk, - realm, - vsrClient, - pythClient, - ]) - - const handleMaxVoterWeight = useCallback(async () => { - if (!realm || !nftClient) return - - const { maxVoterWeightRecord } = await getPluginMaxVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - nftClient.program.programId - ) - try { - const existingMaxVoterRecord = await getMaxVoterWeightRecord( - connection.current, - maxVoterWeightRecord - ) - setNftMaxVoterWeight(existingMaxVoterRecord) - } catch (e) { - console.log(e) - setNftMaxVoterWeight(null) - } - }, [connection, nftClient, setNftMaxVoterWeight, realm]) - - const handleGetHeliumVsrVoting = useCallback(async () => { - if ( - realm && - currentPluginPk && - HELIUM_VSR_PLUGINS_PKS.includes(currentPluginPk.toBase58()) - ) { - const [maxVoterRecord] = heliumVsrSdk.maxVoterWeightRecordKey( - realm.pubkey, - realm.account.communityMint, - currentPluginPk - ) - try { - const mvwr = await getMaxVoterWeightRecord( - connection.current, - maxVoterRecord - ) - heliumStore.setMaxVoterWeight(mvwr) - } catch (_e) { - console.log("Couldn't get max voter weight record. Setting to null.") - heliumStore.setMaxVoterWeight(null) - } - - if (currentClient.walletPk && heliumVsrClient) { - try { - await heliumStore.getPositions({ - realmPk: realm.pubkey, - communityMintPk: realm.account.communityMint, - walletPk: currentClient.walletPk, - connection: connection.current, - client: heliumVsrClient, - votingClient: currentClient, - }) - } catch (e) { - console.log(e) - } - } - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - connection, - currentClient, - currentPluginPk, - //heliumStore, - heliumVsrClient, - realm, - ]) - - useEffect(() => { - if (usedCollectionsPks.length && realm) { - handleMaxVoterWeight() - } else if (realm) { - handleGetHeliumVsrVoting() - } else { - setNftMaxVoterWeight(null) - } - }, [ - connected, - currentClient, - currentPluginPk, - handleGetHeliumVsrVoting, - handleMaxVoterWeight, - nftMintRegistrar, - realm, - setNftMaxVoterWeight, - usedCollectionsPks.length, - ]) -} 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 b110bed608..5c34732493 100644 --- a/hub/components/EditRealmConfig/CommunityStructure/index.tsx +++ b/hub/components/EditRealmConfig/CommunityStructure/index.tsx @@ -1,5 +1,6 @@ import EventsIcon from '@carbon/icons-react/lib/Events'; import WarningFilledIcon from '@carbon/icons-react/lib/WarningFilled'; +import { Coefficients } from '@solana/governance-program-library'; import { GoverningTokenType } from '@solana/spl-governance'; import type { PublicKey } from '@solana/web3.js'; import BigNumber from 'bignumber.js'; @@ -9,6 +10,7 @@ import { produce } from 'immer'; import { Config } from '../fetchConfig'; import { TokenTypeSelector } from '../TokenTypeSelector'; import { VotingStructureSelector } from '../VotingStructureSelector'; +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins'; import { ButtonToggle } from '@hub/components/controls/ButtonToggle'; import { Input } from '@hub/components/controls/Input'; import { MAX_NUM } from '@hub/components/EditWalletRules/constants'; @@ -26,6 +28,8 @@ interface Props nftCollectionSize: number; nftCollectionWeight: BN; civicPassType: Config['civicPassType']; + qvCoefficients?: Coefficients; + chainingEnabled: boolean; }> { currentConfigAccount: Config['configAccount']; currentNftCollection?: PublicKey; @@ -37,6 +41,9 @@ interface Props } export function CommunityStructure(props: Props) { + const { plugins } = useRealmVoterWeightPlugins(); + const inOrderPlugins = plugins?.voterWeight.reverse(); + const currentVotingStructure = { votingProgramId: props.currentConfigAccount.communityTokenConfig.voterWeightAddin, @@ -46,6 +53,7 @@ export function CommunityStructure(props: Props) { nftCollectionSize: props.currentNftCollectionSize, nftCollectionWeight: props.currentNftCollectionWeight, civicPassType: props.currentCivicPassType, + qvCoefficients: props.qvCoefficients, }; const votingStructure = { @@ -56,6 +64,8 @@ export function CommunityStructure(props: Props) { nftCollectionSize: props.nftCollectionSize, nftCollectionWeight: props.nftCollectionWeight, civicPassType: props.civicPassType, + qvCoefficients: props.qvCoefficients, + chainingEnabled: props.chainingEnabled, }; const minTokensToManage = new BigNumber( @@ -187,6 +197,7 @@ export function CommunityStructure(props: Props) { )} )} + {props.configAccount.communityTokenConfig.tokenType !== GoverningTokenType.Dormant && ( + {inOrderPlugins && + inOrderPlugins?.length > 1 && + inOrderPlugins.slice(0, -1).map((plugin) => { + return ( + <> + +
+ + ); + })}
{ const newConfig = produce( { ...props.configAccount }, @@ -258,6 +290,22 @@ export function CommunityStructure(props: Props) { ) { props.onCivicPassTypeChange?.(civicPassType); } + + if ( + typeof qvCoefficients !== 'undefined' && + !props?.qvCoefficients?.every((value) => + qvCoefficients.includes(value), + ) + ) { + props.onQvCoefficientsChange?.(qvCoefficients); + } + + if ( + typeof chainingEnabled !== 'undefined' && + props.chainingEnabled !== chainingEnabled + ) { + props.onChainingEnabledChange?.(chainingEnabled); + } }, 0); }} /> diff --git a/hub/components/EditRealmConfig/Form/index.tsx b/hub/components/EditRealmConfig/Form/index.tsx index 5f13d3df2a..d3fe929082 100644 --- a/hub/components/EditRealmConfig/Form/index.tsx +++ b/hub/components/EditRealmConfig/Form/index.tsx @@ -72,6 +72,8 @@ export function Form(props: Props) { nftCollectionSize={props.config.nftCollectionSize} nftCollectionWeight={props.config.nftCollectionWeight} civicPassType={props.config.civicPassType} + qvCoefficients={props.config.qvCoefficients} + chainingEnabled={props.config.chainingEnabled} onConfigChange={(config) => { const newConfig = produce(props.config, (data) => { data.config = config; @@ -112,6 +114,20 @@ export function Form(props: Props) { data.civicPassType = civicPassType; }); + props.onConfigChange?.(newConfig); + }} + onQvCoefficientsChange={(coeffcients) => { + const newConfig = produce(props.config, (data) => { + data.qvCoefficients = coeffcients; + }); + + props.onConfigChange?.(newConfig); + }} + onChainingEnabledChange={(chainingEnabled) => { + const newConfig = produce(props.config, (data) => { + data.chainingEnabled = chainingEnabled; + }); + props.onConfigChange?.(newConfig); }} /> diff --git a/hub/components/EditRealmConfig/UpdatesList/index.tsx b/hub/components/EditRealmConfig/UpdatesList/index.tsx index f6e7d3e723..1f8b48c2c0 100644 --- a/hub/components/EditRealmConfig/UpdatesList/index.tsx +++ b/hub/components/EditRealmConfig/UpdatesList/index.tsx @@ -2,6 +2,7 @@ import EditIcon from '@carbon/icons-react/lib/Edit'; import EventsIcon from '@carbon/icons-react/lib/Events'; import RuleIcon from '@carbon/icons-react/lib/Rule'; import ScaleIcon from '@carbon/icons-react/lib/Scale'; +import { Coefficients } from '@solana/governance-program-library'; import { MintMaxVoteWeightSourceType, MintMaxVoteWeightSource, @@ -10,6 +11,8 @@ import { PublicKey } from '@solana/web3.js'; import { BigNumber } from 'bignumber.js'; import BN from 'bn.js'; +import { FC } from 'react'; + import { availablePasses } from '../../../../GatewayPlugin/config'; import { Config } from '../fetchConfig'; import { getLabel } from '../TokenTypeSelector'; @@ -17,6 +20,7 @@ import { DEFAULT_NFT_CONFIG, DEFAULT_VSR_CONFIG, DEFAULT_CIVIC_CONFIG, + DEFAULT_QV_CONFIG, } from '../VotingStructureSelector'; import { SectionBlock } from '@hub/components/EditWalletRules/SectionBlock'; import { SectionHeader } from '@hub/components/EditWalletRules/SectionHeader'; @@ -47,6 +51,8 @@ export function buildUpdates(config: Config) { nftCollectionSize: config.nftCollectionSize, nftCollectionWeight: config.nftCollectionWeight, civicPassType: config.civicPassType, + qvCoefficients: config.qvCoefficients, + chainingEnabled: config.chainingEnabled, }; } @@ -93,6 +99,27 @@ const civicPassTypeLabel = (civicPassType: PublicKey | undefined): string => { return foundPass.name; }; +// display QV coefficients inline with A, B, C as labels +const QvCoefficientsDisplay: FC<{ + qvCoefficients: Coefficients | undefined; +}> = ({ qvCoefficients }) => { + if (!qvCoefficients) return null; + const coefficient = (label: string, value: number) => ( +
+
{label}
+
{value}
+
+ ); + + return ( + <> + {coefficient('A', qvCoefficients[0])} + {coefficient('B', qvCoefficients[1])} + {coefficient('C', qvCoefficients[2])} + + ); +}; + function votingStructureText( votingPluginDiff: [PublicKey | undefined, PublicKey | undefined], maxVotingPluginDiff: [PublicKey | undefined, PublicKey | undefined], @@ -115,6 +142,11 @@ function votingStructureText( typeof maxVotingPluginDiff[0] === 'undefined' ) { existingText = 'Civic'; + } else if ( + votingPluginDiff[0]?.equals(DEFAULT_QV_CONFIG.votingProgramId) && + typeof maxVotingPluginDiff[0] === 'undefined' + ) { + existingText = 'QV'; } else if (votingPluginDiff[0] || maxVotingPluginDiff[0]) { existingText = 'Custom'; } @@ -134,6 +166,11 @@ function votingStructureText( typeof maxVotingPluginDiff[1] === 'undefined' ) { newText = 'Civic'; + } else if ( + votingPluginDiff[1]?.equals(DEFAULT_QV_CONFIG.votingProgramId) && + typeof maxVotingPluginDiff[1] === 'undefined' + ) { + newText = 'QV'; } else if (votingPluginDiff[1] || maxVotingPluginDiff[1]) { newText = 'Custom'; } @@ -315,14 +352,25 @@ export function UpdatesList(props: Props) { )[1] }
-
- { - votingStructureText( - updates.communityVotingPlugin || [], - updates.communityMaxVotingPlugin || [], - )[0] - } -
+ {updates.chainingEnabled ? ( +
+ {'⬅ ' + + votingStructureText( + updates.communityVotingPlugin || [], + updates.communityMaxVotingPlugin || [], + )[0] + + ' (Chaining)'} +
+ ) : ( +
+ { + votingStructureText( + updates.communityVotingPlugin || [], + updates.communityMaxVotingPlugin || [], + )[0] + } +
+ )}
} /> @@ -647,6 +695,25 @@ export function UpdatesList(props: Props) {
)} + {'qvCoefficients' in updates && ( + +
+ +
+
+ +
+
+ } + /> + )} ); } diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/ChainToggle.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/ChainToggle.tsx new file mode 100644 index 0000000000..f07c774a68 --- /dev/null +++ b/hub/components/EditRealmConfig/VotingStructureSelector/ChainToggle.tsx @@ -0,0 +1,70 @@ +import React, { FC } from 'react'; + +import { ButtonToggle } from '@hub/components/controls/ButtonToggle'; +import { PLUGIN_DISPLAY_NAMES } from '@hub/components/EditRealmConfig/VotingStructureSelector/index'; +import { ValueBlock } from '@hub/components/EditWalletRules/ValueBlock'; +import cx from '@hub/lib/cx'; + +interface Props { + className?: string; + previousPlugin: string; + chainingEnabled: boolean; + onChange(value: boolean): void; +} + +const pluginProgramIdToName = (plugin: string) => + PLUGIN_DISPLAY_NAMES[plugin] ?? plugin; + +// A dropdown of all the available Civic Passes +const ChainToggle: FC<{ + className?: string; + previousPlugin: string; + chainingEnabled: boolean; + onChange(value: boolean): void; +}> = (props) => { + return ( + + { + props.onChange(value); + }} + /> + + ); +}; + +export function ChainToggleConfigurator(props: Props) { + return ( +
+
+
+
+
+
+ +
+
+
+
+ ); +} diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx index 83a6fdaef3..7c8ec56f18 100644 --- a/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx +++ b/hub/components/EditRealmConfig/VotingStructureSelector/CivicConfigurator.tsx @@ -4,7 +4,11 @@ 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 { + availablePasses, + CivicPass, + defaultPass, +} from '../../../../GatewayPlugin/config'; import Input from '@components/inputs/Input'; import cx from '@hub/lib/cx'; @@ -30,21 +34,10 @@ 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; diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/QVConfigurator.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/QVConfigurator.tsx new file mode 100644 index 0000000000..2d20030500 --- /dev/null +++ b/hub/components/EditRealmConfig/VotingStructureSelector/QVConfigurator.tsx @@ -0,0 +1,129 @@ +import { Coefficients } from '@solana/governance-program-library'; +import { useConnection } from '@solana/wallet-adapter-react'; +import React, { useState, useEffect } from 'react'; + +import { getCoefficients } from '../../../../actions/addPlugins/addQVPlugin'; +import { useRealmQuery } from '@hooks/queries/realm'; + +import { Input } from '@hub/components/controls/Input'; +import cx from '@hub/lib/cx'; +import { preventNegativeNumberInput } from '@utils/helpers'; + +interface Props { + className?: string; + onCoefficientsChange(value: Coefficients | undefined): void; +} + +export function QVConfigurator({ className, onCoefficientsChange }: Props) { + const [coefficients, setCoefficients] = useState([1000, 0, 0]); + const { connection } = useConnection(); + const realm = useRealmQuery().data?.result; + + useEffect(() => { + const fetchCoefficients = async () => { + const coefficients = await getCoefficients( + undefined, + realm?.account.communityMint, + connection, + ); + + const coefficientA = Number(coefficients[0].toFixed(2)); + + setCoefficients([coefficientA, coefficients[1], coefficients[2]]); + onCoefficientsChange([coefficientA, coefficients[1], coefficients[2]]); + }; + + // If the user wants to use a pre-existing token, we need to adjust the coefficients ot match the decimals of that token + if (realm?.account.communityMint) { + fetchCoefficients(); + } + }, [connection, realm?.account.communityMint]); + + return ( +
+
+
+
+
+ Quadratic Coefficients +
+
+
+
+
+ { + preventNegativeNumberInput(ev); + const newCoefficients = [...coefficients]; + newCoefficients[0] = Number(ev.target.value); + setCoefficients(newCoefficients as Coefficients); + onCoefficientsChange(newCoefficients as Coefficients); + }} + /> +
+ A +
+
+
+ { + preventNegativeNumberInput(ev); + const newCoefficients = [...coefficients]; + newCoefficients[1] = Number(ev.target.value); + setCoefficients(newCoefficients as Coefficients); + onCoefficientsChange(newCoefficients as Coefficients); + }} + /> +
+ B +
+
+
+ { + preventNegativeNumberInput(ev); + const newCoefficients = [...coefficients]; + newCoefficients[2] = Number(ev.target.value); + setCoefficients(newCoefficients as Coefficients); + onCoefficientsChange(newCoefficients as Coefficients); + }} + /> +
+ C +
+
+
+
+
+ Advanced Option: Defaults have been set to an appropriate curve + based on the community token. Please take a look at the Realms + documentation to understand how changing the quadratic formula will + affect voting. +
+
+
+
+ ); +} diff --git a/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx b/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx index 3b1ecd2a84..ead8388aef 100644 --- a/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx +++ b/hub/components/EditRealmConfig/VotingStructureSelector/index.tsx @@ -1,11 +1,16 @@ import ChevronDownIcon from '@carbon/icons-react/lib/ChevronDown'; +import { GATEWAY_PLUGINS_PKS, QV_PLUGINS_PKS } from '@constants/plugins'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; +import { Coefficients } from '@solana/governance-program-library'; import { PublicKey } from '@solana/web3.js'; import BN from 'bn.js'; import { produce } from 'immer'; + import { useEffect, useRef, useState } from 'react'; +import { defaultPass } from '../../../../GatewayPlugin/config'; import { Config } from '../fetchConfig'; +import { ChainToggleConfigurator } from '@hub/components/EditRealmConfig/VotingStructureSelector/ChainToggle'; import cx from '@hub/lib/cx'; import { DEFAULT_NFT_VOTER_PLUGIN } from '@tools/constants'; @@ -13,6 +18,7 @@ import { DEFAULT_NFT_VOTER_PLUGIN } from '@tools/constants'; import { CivicConfigurator } from './CivicConfigurator'; import { Custom } from './Custom'; import { NFT } from './NFT'; +import { QVConfigurator } from './QVConfigurator'; export const DEFAULT_NFT_CONFIG = { votingProgramId: new PublicKey(DEFAULT_NFT_VOTER_PLUGIN), @@ -25,12 +31,22 @@ export const DEFAULT_VSR_CONFIG = { }; export const DEFAULT_CIVIC_CONFIG = { - votingProgramId: new PublicKey( - 'GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk', - ), + votingProgramId: new PublicKey(GATEWAY_PLUGINS_PKS[0]), maxVotingProgramId: undefined, }; +export const DEFAULT_QV_CONFIG = { + votingProgramId: new PublicKey(QV_PLUGINS_PKS[0]), + maxVotingProgramId: undefined, // the QV plugin does not use a max voting weight record. +}; + +export const PLUGIN_DISPLAY_NAMES = { + [DEFAULT_NFT_VOTER_PLUGIN]: 'NFT Plugin', + [DEFAULT_VSR_CONFIG.votingProgramId.toBase58() || '']: 'VSR Plugin', + [DEFAULT_CIVIC_CONFIG.votingProgramId.toBase58() || '']: 'Civic Plugin', + [DEFAULT_QV_CONFIG.votingProgramId.toBase58() || '']: 'QV Plugin', +}; + const itemStyles = cx( 'border', 'cursor-pointer', @@ -59,12 +75,15 @@ type VotingStructure = { nftCollectionSize?: number; nftCollectionWeight?: BN; civicPassType?: PublicKey; + chainingEnabled?: boolean; + qvCoefficients?: Coefficients; }; interface Props { allowNFT?: boolean; allowCivic?: boolean; allowVSR?: boolean; + allowQV?: boolean; className?: string; communityMint: Config['communityMint']; currentStructure: VotingStructure; @@ -73,6 +92,15 @@ interface Props { } function areConfigsEqual(a: Props['structure'], b: Props['structure']) { + if ( + Object.hasOwnProperty.call(a, 'maxVotingProgramId') !== + Object.hasOwnProperty.call(b, 'maxVotingProgramId') || + Object.hasOwnProperty.call(a, 'votingProgramId') !== + Object.hasOwnProperty.call(b, 'votingProgramId') + ) { + return false; + } + if ( (a.maxVotingProgramId && !b.maxVotingProgramId) || (!a.maxVotingProgramId && b.maxVotingProgramId) @@ -118,8 +146,22 @@ function isCivicConfig(config: Props['structure']) { return areConfigsEqual(config, DEFAULT_CIVIC_CONFIG); } +function isQVConfig(config: Props['structure']) { + return areConfigsEqual(config, DEFAULT_QV_CONFIG); +} + +// true if this plugin supports chaining with other plugins +function isChainablePlugin(config: Props['structure']) { + return isCivicConfig(config) || isQVConfig(config); +} + function isCustomConfig(config: Props['structure']) { - return !isNFTConfig(config) && !isVSRConfig(config) && !isCivicConfig(config); + return ( + !isNFTConfig(config) && + !isVSRConfig(config) && + !isCivicConfig(config) && + !isQVConfig(config) + ); } export function getLabel(value: Props['structure']): string { @@ -135,9 +177,26 @@ export function getLabel(value: Props['structure']): string { return 'Civic'; } + if (isQVConfig(value)) { + return 'QV'; + } + return 'Custom'; } +const getDefaults = (value: Props['structure']): Partial => { + let result: Partial = {}; + + if (isCivicConfig(value)) { + result = { + ...result, + civicPassType: new PublicKey(defaultPass.value), + }; + } + + return result; +}; + function getDescription(value: Props['structure']): string { if (isNFTConfig(value)) { return 'Voting enabled and weighted based on NFTs owned'; @@ -151,6 +210,10 @@ function getDescription(value: Props['structure']): string { return 'Governance based on Civic verification'; } + if (isQVConfig(value)) { + return 'Quadratic voting'; + } + return 'Add a custom program ID for governance structure'; } @@ -163,6 +226,15 @@ export function VotingStructureSelector(props: Props) { ); const trigger = useRef(null); + // only show the chain toggle if the plugin supports chaining + // and there is a previous plugin to chain with + // and the current plugin is not the same as the previous plugin + const shouldShowChainToggle = + isChainablePlugin(props.structure) && + !!props.currentStructure.votingProgramId && + props.structure.votingProgramId?.toBase58() !== + props.currentStructure.votingProgramId?.toBase58(); + useEffect(() => { if (trigger.current) { setWidth(trigger.current.clientWidth); @@ -183,12 +255,10 @@ export function VotingStructureSelector(props: Props) { ref={trigger} >
- {areConfigsEqual({}, props.structure) && isDefault - ? 'Default' - : getLabel(props.structure)} + {isDefault ? 'Default' : getLabel(props.structure)}
- {areConfigsEqual({}, props.structure) && isDefault + {isDefault ? 'Governance is based on token ownership' : getDescription(props.structure)}
@@ -203,6 +273,7 @@ export function VotingStructureSelector(props: Props) { const newConfig = produce({ ...props.structure }, (data) => { data.votingProgramId = value || undefined; data.nftCollection = undefined; + data.chainingEnabled = isChainablePlugin(data); }); props.onChange?.(newConfig); @@ -250,6 +321,17 @@ export function VotingStructureSelector(props: Props) { }} /> )} + {isQVConfig(props.structure) && ( + { + const newConfig = produce({ ...props.structure }, (data) => { + data.qvCoefficients = value ?? undefined; + }); + props.onChange?.(newConfig); + }} + /> + )} {isCivicConfig(props.structure) && ( )} + {shouldShowChainToggle && ( + { + const newConfig = produce({ ...props.structure }, (data) => { + data.chainingEnabled = value; + }); + props.onChange?.(newConfig); + }} + /> + )} { if (typeof config === 'string') { - return !areConfigsEqual({}, props.structure); + return !isDefault; } - return !areConfigsEqual(config, props.structure); }) .map((config, i) => ( @@ -299,7 +395,11 @@ export function VotingStructureSelector(props: Props) { props.onChange?.({}); setIsDefault(true); } else { - props.onChange?.(config); + const changes = { + ...getDefaults(config), // add any default values (e.g. chainingEnabled) + ...config, + }; + props.onChange?.(changes); setIsDefault(false); } }} diff --git a/hub/components/EditRealmConfig/createTransaction.ts b/hub/components/EditRealmConfig/createTransaction.ts index 43cf931c3e..e0458af446 100644 --- a/hub/components/EditRealmConfig/createTransaction.ts +++ b/hub/components/EditRealmConfig/createTransaction.ts @@ -1,29 +1,41 @@ -import { AnchorProvider, Wallet } from '@project-serum/anchor'; +import { AnchorProvider, Wallet } from '@coral-xyz/anchor'; -import { GatewayClient } from '@solana/governance-program-library'; +import { + GatewayClient, + QuadraticClient, +} from '@solana/governance-program-library'; import { createSetRealmConfig, GoverningTokenType, GoverningTokenConfigAccountArgs, tryGetRealmConfig, getRealm, - getGovernanceProgramVersion, SYSTEM_PROGRAM_ID, } from '@solana/spl-governance'; +import { + getGovernanceProgramVersion +} from "@realms-today/spl-governance" import type { Connection, PublicKey, TransactionInstruction, } from '@solana/web3.js'; +import { + configureCivicRegistrarIx, + createCivicRegistrarIx, +} from '../../../GatewayPlugin/sdk/api'; +import { + coefficientsEqual, + configureQuadraticRegistrarIx, + createQuadraticRegistrarIx, + DEFAULT_COEFFICIENTS, +} from '../../../QuadraticPlugin/sdk/api'; +import { DEFAULT_QV_CONFIG } from '@hub/components/EditRealmConfig/VotingStructureSelector'; import { getMaxVoterWeightRecord, getRegistrarPDA, } from '@utils/plugin/accounts'; -import { - configureCivicRegistrarIx, - createCivicRegistrarIx, -} from '@utils/plugin/gateway'; import { NftVoterClient } from '@utils/uiTypes/NftVoterClient'; import { Config } from './fetchConfig'; @@ -49,6 +61,9 @@ function shouldAddConfigInstruction(config: Config, currentConfig: Config) { return false; } +const configUsesVoterWeightPlugin = (config: Config, plugin: PublicKey) => + config.configAccount.communityTokenConfig.voterWeightAddin?.equals(plugin); + export async function createTransaction( realmPublicKey: PublicKey, governance: PublicKey, @@ -87,8 +102,12 @@ export async function createTransaction( currentConfig.nftCollectionSize !== config.nftCollectionSize || !currentConfig.nftCollectionWeight.eq(config.nftCollectionWeight)) ) { - const nftClient = await NftVoterClient.connect(anchorProvider, isDevnet); - const { registrar } = await getRegistrarPDA( + const nftClient = await NftVoterClient.connect( + anchorProvider, + undefined, + isDevnet, + ); + const { registrar } = getRegistrarPDA( realmPublicKey, config.communityMint.publicKey, nftClient.program.programId, @@ -154,7 +173,16 @@ export async function createTransaction( isDevnet, ); - const instruction = currentConfig.civicPassType + const predecessorPlugin = config.chainingEnabled + ? currentConfig.configAccount.communityTokenConfig.voterWeightAddin + : undefined; + + const existingRegistrarAccount = await gatewayClient.getRegistrarAccount( + realmPublicKey, + config.communityMint.publicKey, + ); + + const instruction = existingRegistrarAccount ? await configureCivicRegistrarIx( realmAccount, gatewayClient, @@ -165,6 +193,66 @@ export async function createTransaction( wallet.publicKey, gatewayClient, config.civicPassType, + predecessorPlugin, + ); + + instructions.push(instruction); + } else if ( + (config.qvCoefficients && + !coefficientsEqual( + config.qvCoefficients, + currentConfig.qvCoefficients, + )) || + (configUsesVoterWeightPlugin(config, DEFAULT_QV_CONFIG.votingProgramId) && + !configUsesVoterWeightPlugin( + currentConfig, + DEFAULT_QV_CONFIG.votingProgramId, + )) + ) { + // Configure the registrar for the quadratic voting plugin for the DAO + // Since QV needs to be paired up with some other plugin that protects against sybil attacks, + // it will typically have a predecessor plugin (e.g. the Civic Gateway plugin) + const predecessorPlugin = config.chainingEnabled + ? currentConfig.configAccount.communityTokenConfig.voterWeightAddin + : undefined; + + const quadraticClient = await QuadraticClient.connect( + anchorProvider, + isDevnet, + ); + + const existingRegistrarAccount = await quadraticClient.getRegistrarAccount( + realmPublicKey, + config.communityMint.publicKey, + ); + + // if the update is a simple coefficient update, do not change the predecessor unless also set specifically + // Note - the UI is somewhat overloaded here and it would be nicer differentiate + // between updates and new plugins being added to the chain + const isCoefficientUpdate = + existingRegistrarAccount && + config.qvCoefficients && + !coefficientsEqual(config.qvCoefficients, currentConfig.qvCoefficients); + const previousVoterWeightPluginProgramId = + predecessorPlugin ?? + (isCoefficientUpdate + ? existingRegistrarAccount.previousVoterWeightPluginProgramId + : undefined); + + const instruction = existingRegistrarAccount + ? await configureQuadraticRegistrarIx( + realmAccount, + quadraticClient, + config.qvCoefficients || DEFAULT_COEFFICIENTS, + // keep the existing predecessor when updating the coefficients + previousVoterWeightPluginProgramId, + ) + : await createQuadraticRegistrarIx( + realmAccount, + wallet.publicKey, + quadraticClient, + config.qvCoefficients || DEFAULT_COEFFICIENTS, + predecessorPlugin, ); instructions.push(instruction); diff --git a/hub/components/EditRealmConfig/fetchConfig.ts b/hub/components/EditRealmConfig/fetchConfig.ts index e640a134d7..f108922fbe 100644 --- a/hub/components/EditRealmConfig/fetchConfig.ts +++ b/hub/components/EditRealmConfig/fetchConfig.ts @@ -1,26 +1,28 @@ -import { GATEWAY_PLUGINS_PKS, NFT_PLUGINS_PKS } from '@constants/plugins'; -import { AnchorProvider, Wallet } from '@project-serum/anchor'; - -import { GatewayClient } from '@solana/governance-program-library'; import { - RealmConfig, - RealmConfigAccount, + Coefficients, + GatewayClient, +} from '@solana/governance-program-library'; +import { QuadraticClient } from '@solana/governance-program-library/dist/quadraticVoter/client'; +import { getRealm, getRealmConfigAddress, - ProgramAccount, GovernanceAccountParser, - GoverningTokenType, GoverningTokenConfig, + GoverningTokenType, + ProgramAccount, + RealmConfig, + RealmConfigAccount, } from '@solana/spl-governance'; import { Connection, PublicKey } from '@solana/web3.js'; import BN from 'bn.js'; +import { QuadraticPluginParams } from 'VoterWeightPlugins/useQuadraticVoterWeightPlugin'; import { tryGetNftRegistrar } from 'VoteStakeRegistry/sdk/api'; -import { getNetworkFromEndpoint } from '@utils/connection'; +import { AnchorParams } from '../../../QuadraticPlugin/sdk/api'; +import { VoterWeightPluginInfo } from '../../../VoterWeightPlugins/lib/types'; import { getRegistrarPDA as getPluginRegistrarPDA } from '@utils/plugin/accounts'; -import { tryGetRegistar as tryGetGatewayRegistrar } from '@utils/plugin/gateway'; -import { parseMintAccountData, MintAccount } from '@utils/tokens'; +import { MintAccount, parseMintAccountData } from '@utils/tokens'; import { NftVoterClient } from '@utils/uiTypes/NftVoterClient'; export interface Config { @@ -35,12 +37,14 @@ export interface Config { nftCollectionWeight: BN; realmAuthority?: PublicKey; civicPassType?: PublicKey; + chainingEnabled: boolean; + qvCoefficients?: Coefficients; } export async function fetchConfig( connection: Connection, realmPublicKey: PublicKey, - wallet: Pick, + currentPlugins: VoterWeightPluginInfo[], ): Promise { const realm = await getRealm(connection, realmPublicKey); @@ -86,46 +90,51 @@ export async function fetchConfig( let nftCollectionSize = 0; let nftCollectionWeight = new BN(0); let civicPassType: PublicKey | undefined = undefined; - const defaultOptions = AnchorProvider.defaultOptions(); - const anchorProvider = new AnchorProvider(connection, wallet, defaultOptions); - - const isDevnet = getNetworkFromEndpoint(connection.rpcEndpoint) === 'devnet'; - const nftClient = await NftVoterClient.connect(anchorProvider, isDevnet); - const gatewayClient = await GatewayClient.connect(anchorProvider, isDevnet); - const pluginPublicKey = - configProgramAccount.account.communityTokenConfig.voterWeightAddin; - - if (pluginPublicKey && NFT_PLUGINS_PKS.includes(pluginPublicKey.toBase58())) { - if (nftClient && realm.account.communityMint) { - const programId = nftClient.program.programId; - const registrarPDA = ( - await getPluginRegistrarPDA( - realmPublicKey, - realm.account.communityMint, - programId, - ) - ).registrar; - - const registrar: any = await tryGetNftRegistrar(registrarPDA, nftClient); - - const collections = registrar?.collectionConfigs || []; - - if (collections[0]) { - nftCollection = new PublicKey(collections[0].collection); - nftCollectionSize = collections[0].size; - nftCollectionWeight = collections[0].weight; - } + let qvCoefficients: Coefficients | undefined = undefined; + + const nftClient = currentPlugins.find((plugin) => plugin.name === 'NFT') + ?.client as NftVoterClient | undefined; + const gatewayClient = currentPlugins.find( + (plugin) => plugin.name === 'gateway', + )?.client as GatewayClient | undefined; + const quadraticPlugin = currentPlugins.find((plugin) => plugin.name === 'QV'); + + if (nftClient && realm.account.communityMint) { + const programId = nftClient.program.programId; + const registrarPDA = ( + await getPluginRegistrarPDA( + realmPublicKey, + realm.account.communityMint, + programId, + ) + ).registrar; + + const registrar: any = await tryGetNftRegistrar(registrarPDA, nftClient); + + const collections = registrar?.collectionConfigs || []; + + if (collections[0]) { + nftCollection = new PublicKey(collections[0].collection); + nftCollectionSize = collections[0].size; + nftCollectionWeight = collections[0].weight; } } - if ( - pluginPublicKey && - GATEWAY_PLUGINS_PKS.includes(pluginPublicKey.toBase58()) - ) { - if (gatewayClient && realm.account.communityMint) { - const registrar = await tryGetGatewayRegistrar(realm, gatewayClient); - civicPassType = registrar?.gatekeeperNetwork; - } + if (gatewayClient && realm.account.communityMint) { + const registrar = await gatewayClient.getRegistrarAccount( + realm.pubkey, + realm.account.communityMint, + ); + civicPassType = registrar?.gatekeeperNetwork; + } + + if (quadraticPlugin && realm.account.communityMint) { + const anchorCoefficients = (quadraticPlugin?.params as + | AnchorParams + | undefined)?.quadraticCoefficients; + qvCoefficients = anchorCoefficients + ? QuadraticClient.convertCoefficientsFromAnchorType(anchorCoefficients) + : undefined; } const mintPkStr = realm.account.communityMint.toBase58(); @@ -180,5 +189,7 @@ export async function fetchConfig( config: realmConfig, configAccount: configProgramAccount.account, realmAuthority: realm.account.authority, + chainingEnabled: false, + qvCoefficients, }; } diff --git a/hub/components/EditRealmConfig/index.tsx b/hub/components/EditRealmConfig/index.tsx index b3b8fa6002..8f1864f08b 100644 --- a/hub/components/EditRealmConfig/index.tsx +++ b/hub/components/EditRealmConfig/index.tsx @@ -17,6 +17,7 @@ import { useRealmQuery } from '@hooks/queries/realm'; import useCreateProposal from '@hooks/useCreateProposal'; import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'; import useQueryContext from '@hooks/useQueryContext'; +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins'; import useWalletOnePointOh from '@hooks/useWalletOnePointOh'; import { Primary, Secondary } from '@hub/components/controls/Button'; import { useQuery } from '@hub/hooks/useQuery'; @@ -79,6 +80,7 @@ export function EditRealmConfig(props: Props) { realmUrlId: props.realmUrlId, }, }); + const { plugins } = useRealmVoterWeightPlugins(); const { propose } = useCreateProposal(); const [governance, setGovernance] = useState(null); @@ -111,15 +113,12 @@ export function EditRealmConfig(props: Props) { }, [step]); useEffect(() => { - if (RE.isOk(result) && wallet?.publicKey) { - Promise.resolve(wallet.publicKey) // :-) - .then((publicKey) => - fetchConfig(connection.current, result.data.realmByUrlId.publicKey, { - publicKey, - signAllTransactions: wallet.signAllTransactions, - signTransaction: wallet.signTransaction, - }), - ) + if (RE.isOk(result)) { + fetchConfig( + connection.current, + result.data.realmByUrlId.publicKey, + plugins?.voterWeight ?? [], + ) .then((config) => { setConfig({ ...config }); setProposalTitle( @@ -320,7 +319,6 @@ export function EditRealmConfig(props: Props) { 24 * governance.minInstructionHoldupDays, prerequisiteInstructions: [], - chunkBy: 3, })), governance: governance.governanceAddress, }); diff --git a/hub/components/EditWalletRules/RulesDetailsInputs.tsx b/hub/components/EditWalletRules/RulesDetailsInputs.tsx index 940729cd40..6f1abe5492 100644 --- a/hub/components/EditWalletRules/RulesDetailsInputs.tsx +++ b/hub/components/EditWalletRules/RulesDetailsInputs.tsx @@ -1,3 +1,4 @@ +import { NFT_PLUGINS_PKS } from '@constants/plugins'; import { BN } from '@coral-xyz/anchor'; import { BigNumber } from 'bignumber.js'; import { produce } from 'immer'; @@ -6,6 +7,7 @@ import { useRealmCommunityMintInfoQuery, useRealmCouncilMintInfoQuery, } from '@hooks/queries/mintInfo'; +import { useRealmConfigQuery } from '@hooks/queries/realmConfig'; import { ButtonToggle } from '@hub/components/controls/ButtonToggle'; import { Input } from '@hub/components/controls/Input'; import { Slider } from '@hub/components/controls/Slider'; @@ -120,6 +122,7 @@ export function CanVote(props: Props) { export function VotingPowerToCreateProposals(props: Props) { const communityTokenInfo = useRealmCommunityMintInfoQuery(); const councilTokenInfo = useRealmCouncilMintInfoQuery(); + const config = useRealmConfigQuery().data?.result; const tokenInfoQuery = props.rules.tokenType === GovernanceTokenType.Community @@ -140,11 +143,27 @@ export function VotingPowerToCreateProposals(props: Props) { .multipliedBy(100) : undefined; + const isNftPlugin = + config?.account.communityTokenConfig.voterWeightAddin && + NFT_PLUGINS_PKS.includes( + config?.account.communityTokenConfig.voterWeightAddin?.toBase58(), + ); + + const isNftGovernanceWithoutCouncil = + isNftPlugin && props.govPop === 'community' && !councilTokenInfo.data; + return ( + {isNftGovernanceWithoutCouncil ? ( +
+ The council is not added. Max tokens can be 5 +
+ ) : ( + '' + )}
{ const text = e.currentTarget.value.replaceAll(/[^\d.-]/g, ''); - const value = text ? new BigNumber(text) : new BigNumber(0); + let value = text ? new BigNumber(text) : new BigNumber(0); + + if ( + isNftGovernanceWithoutCouncil && + value.isGreaterThan(new BigNumber(5)) + ) { + value = new BigNumber(5); + } const newRules = produce(props.rules, (data) => { data.votingPowerToCreateProposals = value; }); diff --git a/hub/components/GlobalFooter/index.tsx b/hub/components/GlobalFooter/index.tsx index 00dd0ab813..1aef768a90 100644 --- a/hub/components/GlobalFooter/index.tsx +++ b/hub/components/GlobalFooter/index.tsx @@ -42,7 +42,7 @@ export function GlobalFooter(props: Props) { 'sm:text-sm', )} > -
© 2022 Solana Technology Services LLC
+
© 2024 Realms Today Ltd
|
Terms diff --git a/hub/components/GlobalHeader/User/DialectNotifications/DialectNotifications.tsx b/hub/components/GlobalHeader/User/DialectNotifications/DialectNotifications.tsx index 272be8c1cc..449311ae1e 100644 --- a/hub/components/GlobalHeader/User/DialectNotifications/DialectNotifications.tsx +++ b/hub/components/GlobalHeader/User/DialectNotifications/DialectNotifications.tsx @@ -1,20 +1,12 @@ -import { - DialectSolanaSdk, - DialectSolanaWalletAdapter, - SolanaConfigProps, -} from '@dialectlabs/react-sdk-blockchain-solana'; -import { - ConfigProps, - DialectThemeProvider, - DialectUiManagementProvider, - NotificationsButton, -} from '@dialectlabs/react-ui'; +import { DialectSolanaSdk } from '@dialectlabs/react-sdk-blockchain-solana'; +import { NotificationsButton } from '@dialectlabs/react-ui'; import * as NavigationMenu from '@radix-ui/react-navigation-menu'; import { useWallet } from '@solana/wallet-adapter-react'; -import React, { useEffect, useMemo, useState } from 'react'; +import { PublicKey } from '@solana/web3.js'; -import { REALMS_PUBLIC_KEY, themeVariables } from './Notifications.constants'; -import { solanaWalletToDialectWallet } from './solanaWalletToDialectWallet'; +export const REALMS_PUBLIC_KEY = new PublicKey( + 'BUxZD6aECR5B5MopyvvYqJxwSKDBhx2jSSo1U32en6mj', +); interface Props { className?: string; @@ -23,51 +15,6 @@ interface Props { export const DialectNotifications = (props: Props) => { const wallet = useWallet(); - const [ - dialectSolanaWalletAdapter, - setDialectSolanaWalletAdapter, - ] = useState(null); - - useEffect(() => { - setDialectSolanaWalletAdapter(solanaWalletToDialectWallet(wallet)); - }, [wallet]); - - const dialectConfig = useMemo( - (): ConfigProps => ({ - environment: 'production', - dialectCloud: { - tokenStore: 'local-storage', - }, - }), - [], - ); - - const solanaConfig: SolanaConfigProps = useMemo( - () => ({ - wallet: dialectSolanaWalletAdapter, - }), - [dialectSolanaWalletAdapter], - ); - - // Uncomment when theme will be available for hub components - // const [theme, setTheme] = useState('light'); - // useEffect(() => { - // if ( - // window.matchMedia && - // window.matchMedia('(prefers-color-scheme: dark)').matches - // ) { - // setTheme('dark'); - // } else { - // setTheme('light'); - // } - // window - // .matchMedia('(prefers-color-scheme: dark)') - // .addEventListener('change', (event) => { - // const newColorScheme = event.matches ? 'dark' : 'light'; - // setTheme(newColorScheme); - // }); - // }, []); - return ( { } }} > - - - - - - + + ); diff --git a/hub/components/GlobalHeader/User/DialectNotifications/Notifications.constants.ts b/hub/components/GlobalHeader/User/DialectNotifications/Notifications.constants.ts deleted file mode 100644 index 5bf6e1ef29..0000000000 --- a/hub/components/GlobalHeader/User/DialectNotifications/Notifications.constants.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { - defaultVariables, - IncomingThemeVariables, -} from '@dialectlabs/react-ui'; -import { PublicKey } from '@solana/web3.js'; - -import cx from '@hub/lib/cx'; - -export const REALMS_PUBLIC_KEY = new PublicKey( - 'BUxZD6aECR5B5MopyvvYqJxwSKDBhx2jSSo1U32en6mj', -); - -export const themeVariables: IncomingThemeVariables = { - dark: { - bellButton: `${defaultVariables.dark.bellButton} bg-transparent !shadow-none text-neutral-300 h-10 rounded-full w-10 hover:bg-bkg-3`, - iconButton: `${defaultVariables.dark.iconButton} hover:opacity-100 bg-transparent`, - adornmentButton: `${defaultVariables.dark.adornmentButton} bg-sky-500 hover:!bg-sky-400 active:bg-sky-500 rounded transition-colors`, - buttonLoading: `${defaultVariables.dark.buttonLoading} rounded-full min-h-[40px]`, - colors: { - ...defaultVariables.dark.colors, - label: 'text-white/80', - toggleThumb: 'bg-white', - toggleBackground: 'bg-zinc-300', - toggleBackgroundActive: 'bg-sky-500', - }, - textStyles: { - ...defaultVariables.dark.textStyles, - input: `${defaultVariables.dark.textStyles.input}`, - }, - outlinedInput: `${defaultVariables.dark.outlinedInput} h-12 rounded focus-within:border-sky-500`, - disabledButton: `${defaultVariables.dark.disabledButton} border-sky-500 font-bold rounded-full border-fgd-3 text-fgd-3 cursor-not-allowed`, - modal: `${defaultVariables.dark.modal} bg-bkg-1 sm:border sm:border-fgd-4 shadow-md sm:rounded-md`, - modalWrapper: `${defaultVariables.dark.modalWrapper} sm:top-14 rounded-md`, - secondaryDangerButton: `${defaultVariables.dark.secondaryDangerButton} rounded-full`, - }, - light: { - bellButton: cx( - defaultVariables.light.bellButton, - 'bg-transparent', - 'border-none', - 'h-10', - 'shadow-none', - 'text-neutral-600', - 'w-10', - 'active:bg-neutral-300', - 'hover:bg-neutral-200', - 'dark:text-neutral-400', - 'dark:hover:text-neutral-200', - 'dark:active:bg-neutral-600', - 'dark:hover:bg-neutral-700', - ), - iconButton: `${defaultVariables.light.iconButton} hover:opacity-100 bg-transparent`, - buttonLoading: `${defaultVariables.light.buttonLoading} rounded-full min-h-[40px]`, - adornmentButton: `${defaultVariables.light.adornmentButton} bg-sky-500 hover:!bg-sky-400 active:bg-sky-500 rounded transition-colors`, - colors: { - ...defaultVariables.light.colors, - label: 'text-neutral-900', - toggleThumb: 'bg-white', - toggleBackground: 'bg-zinc-300', - toggleBackgroundActive: 'bg-sky-500', - }, - textStyles: { - input: cx( - defaultVariables.light.textStyles.input, - 'text-neutral-900', - 'placeholder:text-fgd-3', - ), - body: `${defaultVariables.light.textStyles.body} text-neutral-900`, - small: `${defaultVariables.light.textStyles.small} text-neutral-900`, - xsmall: `${defaultVariables.light.textStyles.xsmall} text-neutral-900`, - label: `${defaultVariables.light.textStyles.label} dt-text-sm dt-font-bold`, - }, - outlinedInput: `${defaultVariables.light.outlinedInput} h-12 rounded text-neutral-900 focus-within:border-sky-500`, - modal: `${defaultVariables.light.modal} sm:border sm:rounded-md sm:shadow-md`, - modalWrapper: `${defaultVariables.light.modalWrapper} sm:top-14`, - secondaryDangerButton: `${defaultVariables.light.secondaryDangerButton} rounded-full`, - }, -}; diff --git a/hub/components/GlobalHeader/User/DialectNotifications/solanaWalletToDialectWallet.ts b/hub/components/GlobalHeader/User/DialectNotifications/solanaWalletToDialectWallet.ts deleted file mode 100644 index 3d59bc64b5..0000000000 --- a/hub/components/GlobalHeader/User/DialectNotifications/solanaWalletToDialectWallet.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { DialectSolanaWalletAdapter } from '@dialectlabs/react-sdk-blockchain-solana'; -import { WalletContextState as SolanaWalletContextState } from '@solana/wallet-adapter-react'; - -export function solanaWalletToDialectWallet( - wallet: SolanaWalletContextState, -): DialectSolanaWalletAdapter | null { - if ( - !wallet.connected || - wallet.connecting || - wallet.disconnecting || - !wallet.publicKey - ) { - return null; - } - - return { - publicKey: wallet.publicKey, - signMessage: wallet.signMessage, - signTransaction: wallet.signTransaction, - signAllTransactions: wallet.signAllTransactions, - // @ts-ignore - diffieHellman: wallet.wallet?.adapter?._wallet?.diffieHellman - ? async (pubKey: any) => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return wallet.wallet?.adapter?._wallet?.diffieHellman(pubKey); - } - : undefined, - }; -} diff --git a/hub/components/GlobalStats/NumVoteRecords/index.tsx b/hub/components/GlobalStats/NumVoteRecords/index.tsx index 4d76cbc44b..485336a38c 100644 --- a/hub/components/GlobalStats/NumVoteRecords/index.tsx +++ b/hub/components/GlobalStats/NumVoteRecords/index.tsx @@ -24,7 +24,7 @@ export function NumVoteRecords(props: Props) { props.className, )} > - Number of Votes + Number of votes {formatNumber(props.voteRecords.length, undefined, { maximumFractionDigits: 0, diff --git a/hub/components/NewWallet/useNewWalletTransaction.ts b/hub/components/NewWallet/useNewWalletTransaction.ts index 9476e8d5f2..e123f0e63a 100644 --- a/hub/components/NewWallet/useNewWalletTransaction.ts +++ b/hub/components/NewWallet/useNewWalletTransaction.ts @@ -5,13 +5,14 @@ import { import { TransactionInstruction } from '@solana/web3.js'; import { useCallback } from 'react'; -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore'; +import { convertTypeToVoterWeightAction } from '../../../VoterWeightPlugins'; import { rules2governanceConfig } from '../EditWalletRules/createTransaction'; import { useLegacyVoterWeight } from '@hooks/queries/governancePower'; import { useRealmQuery } from '@hooks/queries/realm'; import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext'; import useProgramVersion from '@hooks/useProgramVersion'; +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins'; import useWalletOnePointOh from '@hooks/useWalletOnePointOh'; import { chunks } from '@utils/helpers'; import { trySentryLog } from '@utils/logs'; @@ -28,9 +29,12 @@ const useNewWalletCallback = ( ) => { const wallet = useWalletOnePointOh(); const connection = useLegacyConnectionContext(); - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient, - ); + const { + voterWeightPkForWallet, + updateVoterWeightRecords, + } = useRealmVoterWeightPlugins(); + const voterWeightPk = + wallet?.publicKey && voterWeightPkForWallet(wallet.publicKey); const programVersion = useProgramVersion(); const realm = useRealmQuery().data?.result; const { result: ownVoterWeight } = useLegacyVoterWeight(); @@ -48,6 +52,8 @@ const useNewWalletCallback = ( if (!wallet?.publicKey) throw new Error('not signed in'); if (tokenOwnerRecord === undefined) throw new Error('insufficient voting power'); + if (!voterWeightPk) + throw new Error('voterWeightPk not found for current wallet'); const config = await rules2governanceConfig( connection.current, @@ -58,13 +64,12 @@ const useNewWalletCallback = ( const instructions: TransactionInstruction[] = []; const createNftTicketsIxs: TransactionInstruction[] = []; - // client is typed such that it cant be undefined, but whatever. - const plugin = await client?.withUpdateVoterWeightRecord( - instructions, - tokenOwnerRecord.pubkey, - 'createGovernance', - createNftTicketsIxs, + const { pre: preIx, post: postIx } = await updateVoterWeightRecords( + wallet.publicKey, + convertTypeToVoterWeightAction('createGovernance'), ); + instructions.push(...preIx); + createNftTicketsIxs.push(...postIx); const governanceAddress = await withCreateGovernance( instructions, @@ -76,7 +81,7 @@ const useNewWalletCallback = ( tokenOwnerRecord.pubkey, wallet.publicKey, wallet.publicKey, - plugin?.voterWeightPk, + voterWeightPk, ); await withCreateNativeTreasury( instructions, diff --git a/hub/hooks/useProposal.ts b/hub/hooks/useProposal.ts deleted file mode 100644 index ce5bc21a23..0000000000 --- a/hub/hooks/useProposal.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { useContext } from 'react'; - -import { context } from '@hub/providers/Proposal'; - -/** @deprecated */ -export function useProposal() { - return useContext(context); -} diff --git a/hub/providers/Cluster/index.tsx b/hub/providers/Cluster/index.tsx index d73882b750..0b183c331f 100644 --- a/hub/providers/Cluster/index.tsx +++ b/hub/providers/Cluster/index.tsx @@ -6,8 +6,7 @@ import { createContext, useEffect, useState } from 'react'; const DEVNET_RPC_ENDPOINT = process.env.DEVNET_RPC || 'https://api.dao.devnet.solana.com/'; const MAINNET_RPC_ENDPOINT = - process.env.MAINNET_RPC || - 'http://realms-realms-c335.mainnet.rpcpool.com/258d3727-bb96-409d-abea-0b1b4c48af29/'; + process.env.MAINNET_RPC || 'http://realms-realms-c335.mainnet.rpcpool.com'; const TESTNET_RPC_ENDPOINT = 'http://127.0.0.1:8899'; export enum ClusterType { diff --git a/hub/providers/Proposal/createProposal.ts b/hub/providers/Proposal/createProposal.ts index 444f420a05..498c7221d4 100644 --- a/hub/providers/Proposal/createProposal.ts +++ b/hub/providers/Proposal/createProposal.ts @@ -1,22 +1,9 @@ -import { SUPPORT_CNFTS } from '@constants/flags'; -import { - VSR_PLUGIN_PKS, - NFT_PLUGINS_PKS, - GATEWAY_PLUGINS_PKS, -} from '@constants/plugins'; -import { Wallet } from '@coral-xyz/anchor'; import { serializeInstructionToBase64, getGovernance, getRealm, getTokenOwnerRecordForRealm, - getRealmConfigAddress, - GoverningTokenType, - GoverningTokenConfig, RpcContext, - GovernanceAccountParser, - RealmConfigAccount, - ProgramAccount, } from '@solana/spl-governance'; import type { Connection, @@ -29,18 +16,9 @@ import { InstructionDataWithHoldUpTime, createProposal as _createProposal, } from 'actions/createProposal'; -import { tryGetNftRegistrar } from 'VoteStakeRegistry/sdk/api'; -import { - DasNftObject, - fetchDigitalAssetsByOwner, -} from '@hooks/queries/digitalAssets'; -import { getNetworkFromEndpoint } from '@utils/connection'; -import { getRegistrarPDA as getPluginRegistrarPDA } from '@utils/plugin/accounts'; import { VotingClient } from '@utils/uiTypes/VotePlugin'; -import { fetchPlugins } from './fetchPlugins'; - interface Args { callbacks?: Parameters[12]; cluster?: string; @@ -58,6 +36,7 @@ interface Args { requestingUserPublicKey: PublicKey; signTransaction(transaction: Transaction): Promise; signAllTransactions(transactions: Transaction[]): Promise; + votingClient: VotingClient | undefined; } /** @deprecated */ @@ -67,7 +46,6 @@ export async function createProposal(args: Args) { const [ governance, tokenOwnerRecord, - realmConfigPublicKey, // eslint-disable-next-line councilTokenOwnerRecord, // eslint-disable-next-line @@ -81,7 +59,6 @@ export async function createProposal(args: Args) { args.governingTokenMintPublicKey, args.requestingUserPublicKey, ).catch(() => undefined), - getRealmConfigAddress(realm.owner, args.realmPublicKey), args.councilTokenMintPublicKey ? getTokenOwnerRecordForRealm( args.connection, @@ -102,36 +79,6 @@ export async function createProposal(args: Args) { : undefined, ]); - const realmConfigAccountInfo = await args.connection.getAccountInfo( - realmConfigPublicKey, - ); - - const realmConfig: ProgramAccount = realmConfigAccountInfo - ? GovernanceAccountParser(RealmConfigAccount)( - realmConfigPublicKey, - realmConfigAccountInfo, - ) - : { - pubkey: realmConfigPublicKey, - owner: realm.owner, - account: new RealmConfigAccount({ - realm: args.realmPublicKey, - communityTokenConfig: new GoverningTokenConfig({ - voterWeightAddin: undefined, - maxVoterWeightAddin: undefined, - tokenType: GoverningTokenType.Liquid, - reserved: new Uint8Array(), - }), - councilTokenConfig: new GoverningTokenConfig({ - voterWeightAddin: undefined, - maxVoterWeightAddin: undefined, - tokenType: GoverningTokenType.Liquid, - reserved: new Uint8Array(), - }), - reserved: new Uint8Array(), - }), - }; - let userTOR = tokenOwnerRecord; if ( @@ -174,95 +121,6 @@ export async function createProposal(args: Args) { const proposalIndex = governance.account.proposalCount; - const pluginPublicKey = - realmConfig.account.communityTokenConfig.voterWeightAddin; - let votingClient: VotingClient | undefined = undefined; - let votingNfts: DasNftObject[] = []; - - if (pluginPublicKey) { - const votingPlugins = await fetchPlugins( - args.connection, - pluginPublicKey, - { - publicKey: args.requestingUserPublicKey, - signTransaction: args.signTransaction, - signAllTransactions: args.signAllTransactions, - } as Wallet, - args.cluster === 'devnet', - ); - const pluginPublicKeyStr = pluginPublicKey.toBase58(); - let client: VotingClient['client'] = undefined; - // Check for plugins in a particular order. I'm not sure why, but I - // borrowed this from /hooks/useVotingPlugins.ts - if ( - VSR_PLUGIN_PKS.includes(pluginPublicKeyStr) && - votingPlugins.vsrClient - ) { - client = votingPlugins.vsrClient; - } - - if ( - NFT_PLUGINS_PKS.includes(pluginPublicKeyStr) && - votingPlugins.nftClient - ) { - client = votingPlugins.nftClient; - - if (client && args.communityTokenMintPublicKey) { - const programId = client.program.programId; - const registrarPDA = ( - await getPluginRegistrarPDA( - args.realmPublicKey, - args.communityTokenMintPublicKey, - programId, - ) - ).registrar; - - const registrar: any = await tryGetNftRegistrar(registrarPDA, client); - const collections: string[] = - registrar?.collectionConfigs.map((x: any) => - x.collection.toBase58(), - ) || []; - - // const nfts = await getNfts(args.requestingUserPublicKey, { - // cluster: args.cluster, - // } as any); - const network = getNetworkFromEndpoint(args.connection.rpcEndpoint); - if (network === 'localnet') throw new Error(); - const nfts = await fetchDigitalAssetsByOwner( - network, - args.requestingUserPublicKey, - ); - - votingNfts = nfts.filter((nft) => { - const collection = nft.grouping.find( - (x: any) => x.group_key === 'collection', - ); - return ( - (SUPPORT_CNFTS || !nft.compression.compressed) && - collection && - collections.includes(collection.group_value) && - nft.creators?.filter((x: any) => x.verified).length > 0 - ); - }); - } - } - - if ( - GATEWAY_PLUGINS_PKS.includes(pluginPublicKeyStr) && - votingPlugins.gatewayClient - ) { - client = votingPlugins.gatewayClient; - } - - if (client) { - votingClient = new VotingClient({ - realm, - client, - walletPk: args.requestingUserPublicKey, - }); - } - } - return _createProposal( { connection: args.connection, @@ -284,7 +142,7 @@ export async function createProposal(args: Args) { instructionData, args.isDraft, args.options, - votingClient, + args.votingClient, args.callbacks, ); } diff --git a/hub/providers/Proposal/fetchPlugins.ts b/hub/providers/Proposal/fetchPlugins.ts deleted file mode 100644 index 1de7427d70..0000000000 --- a/hub/providers/Proposal/fetchPlugins.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { AnchorProvider, Wallet } from '@coral-xyz/anchor'; -import { GatewayClient } from '@solana/governance-program-library'; -import { Connection, PublicKey } from '@solana/web3.js'; - -import { VsrClient } from 'VoteStakeRegistry/sdk/client'; - -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient'; - -/** @deprecated */ -export async function fetchPlugins( - connection: Connection, - pluginProgram: PublicKey, - wallet: Wallet, - isDevnet?: boolean, -) { - const defaultOptions = AnchorProvider.defaultOptions(); - const anchorProvider = new AnchorProvider(connection, wallet, defaultOptions); - - const [vsrClient, nftClient, gatewayClient] = await Promise.all([ - VsrClient.connect(anchorProvider, pluginProgram, isDevnet), - NftVoterClient.connect(anchorProvider, isDevnet), - GatewayClient.connect(anchorProvider, isDevnet), - ]); - - return { - vsrClient, - nftClient, - gatewayClient, - }; -} diff --git a/hub/providers/Proposal/index.tsx b/hub/providers/Proposal/index.tsx deleted file mode 100644 index 22be670995..0000000000 --- a/hub/providers/Proposal/index.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { createContext } from 'react'; - -import { ClusterType, useCluster } from '@hub/hooks/useCluster'; -import { - useProposalCreationProgress, - CreationProgress, - CreationProgressState, -} from '@hub/hooks/useProposalCreationProgress'; -import { useToast, ToastType } from '@hub/hooks/useToast'; -import { useWallet } from '@hub/hooks/useWallet'; - -import { createProposal } from './createProposal'; - -type CreateProposalsArgs = Omit< - Parameters[0], - | 'callbacks' - | 'connection' - | 'cluster' - | 'signTransaction' - | 'signAllTransactions' - | 'requestingUserPublicKey' ->; - -interface Value { - createProposal( - args: CreateProposalsArgs, - ): Promise> | null>; - progress: CreationProgress; -} - -export const DEFAULT: Value = { - createProposal: async () => { - throw new Error('Not implemented'); - }, - progress: { state: CreationProgressState.Ready }, -}; - -/** @deprecated */ -export const context = createContext(DEFAULT); - -interface Props { - children?: React.ReactNode; -} -/** @deprecated */ -export function ProposalProvider(props: Props) { - const [cluster] = useCluster(); - const { connect, signTransaction, signAllTransactions } = useWallet(); - const { publish } = useToast(); - const { callbacks, progress } = useProposalCreationProgress(); - - return ( - { - try { - const publicKey = await connect(); - - if (!publicKey) { - throw new Error('User must be signed in'); - } - - return createProposal({ - ...args, - callbacks, - cluster: - cluster.type === ClusterType.Devnet - ? 'devnet' - : cluster.type === ClusterType.Mainnet - ? 'mainnet' - : 'localnet', - connection: cluster.connection, - requestingUserPublicKey: publicKey, - signAllTransactions, - signTransaction, - }); - } catch (e) { - const message = - e instanceof Error ? e.message : 'Something went wrong'; - - publish({ - message, - type: ToastType.Error, - title: 'Couuld not create a proposal', - }); - - return null; - } - }, - }} - > - {props.children} - - ); -} diff --git a/hub/providers/Root.tsx b/hub/providers/Root.tsx index eba5bd9885..1639f45582 100644 --- a/hub/providers/Root.tsx +++ b/hub/providers/Root.tsx @@ -6,7 +6,6 @@ import cx from '@hub/lib/cx'; import { ClusterProvider } from './Cluster'; import { GraphQLProvider } from './GraphQL'; import { JWTProvider } from './JWT'; -import { ProposalProvider } from './Proposal'; import { ToastProvider } from './Toast'; import { UserPrefsProvider } from './UserPrefs'; import { WalletProvider } from './Wallet'; @@ -34,9 +33,7 @@ export function RootProvider(props: Props) { - - {props.children} - + {props.children} diff --git a/models/api.ts b/models/api.ts index 97ee0aa53c..6fb1929b10 100644 --- a/models/api.ts +++ b/models/api.ts @@ -4,9 +4,10 @@ import { booleanFilter, getGovernanceAccounts, VoteRecord, + Proposal } from '@solana/spl-governance' -import { pubkeyFilter } from '@solana/spl-governance' +import { pubkeyFilter, MemcmpFilter } from '@solana/spl-governance' import { arrayToRecord } from '@tools/core/script' // VoteRecords @@ -31,3 +32,19 @@ export async function getVoteRecordsByVoterMapByProposal( pubkeyFilter(33, voter)!, ]).then((vrs) => arrayToRecord(vrs, (vr) => vr.account.proposal.toBase58())) } + +// Proposals + +export async function getProposalsAtVotingStateByTOR( + connection: Connection, + programId: PublicKey, + tokenOwnerRecordPk: PublicKey +) { + + const enumFilter: MemcmpFilter = new MemcmpFilter(65, Buffer.from(Uint8Array.from([2]))) + + return getGovernanceAccounts(connection, programId, Proposal, [ + enumFilter, + pubkeyFilter(1 + 32 + 32 + 1, tokenOwnerRecordPk)! + ]) +} \ No newline at end of file diff --git a/models/treasury/Asset.ts b/models/treasury/Asset.ts index 855c13e901..27850b4d30 100644 --- a/models/treasury/Asset.ts +++ b/models/treasury/Asset.ts @@ -22,6 +22,7 @@ export enum AssetType { Unknown, TokenOwnerRecordAsset, Stake, + Mango, } export interface Mint { @@ -92,6 +93,12 @@ export interface Stake { value: BigNumber } +export interface Mango { + id: string + type: AssetType.Mango + value: BigNumber +} + export interface Unknown { type: AssetType.Unknown address: string @@ -118,3 +125,4 @@ export type Asset = | Token | Unknown | Stake + | Mango diff --git a/models/treasury/Wallet.ts b/models/treasury/Wallet.ts index 4e399cb9af..f680cdbc03 100644 --- a/models/treasury/Wallet.ts +++ b/models/treasury/Wallet.ts @@ -5,7 +5,7 @@ import type { Governance, } from '@solana/spl-governance' -import { Asset, Token } from './Asset' +import { Asset, Mango, Sol, Token } from './Asset' interface CommonRules { maxVotingTime: number @@ -40,7 +40,7 @@ export interface Wallet { } export interface AuxiliaryWallet { - assets: Token[] + assets: (Token | Sol | Mango)[] name: string totalValue: BigNumber } diff --git a/models/voteWeights.ts b/models/voteWeights.ts index 90faca0ffb..20ec00133b 100644 --- a/models/voteWeights.ts +++ b/models/voteWeights.ts @@ -336,8 +336,20 @@ export class VoterWeight implements VoterWeightInterface { } } - getTokenRecordToCreateProposal(config: GovernanceConfig) { - // Prefer community token owner record as proposal owner + getTokenRecordToCreateProposal( + config: GovernanceConfig, + voteByCouncil: boolean + ) { + // if the vote is by council, prefer council token + if (voteByCouncil) { + if (this.councilTokenRecord && this.hasMinCouncilWeight(config.minCouncilTokensToCreateProposal)) { + return this.councilTokenRecord + } + if (this.communityTokenRecord) { + return this.communityTokenRecord + } + } + // prefer community token owner record as proposal owner if (this.hasMinCommunityWeight(config.minCommunityTokensToCreateProposal)) { return this.communityTokenRecord! } @@ -345,7 +357,59 @@ export class VoterWeight implements VoterWeightInterface { return this.councilTokenRecord! } - throw new Error('Not enough vote weight to create proposal') + throw new Error('Current wallet has no Token Owner Records') + } +} + +// Deprecated: used to adapt the useLegacyVoterWeight hook to use the voter weight plugins, +// without having to reference each plugin individually, and to support chaining. +// Note - instead of this, you should probably be using the useRealmVoterWeightPlugins hook +export class LegacyVoterWeightAdapter extends VoterWeight { + constructor( + readonly voterWeights: { + community: BN | undefined + council: BN | undefined + }, + tokenOwnerRecords: { + community: ProgramAccount | undefined + council: ProgramAccount | undefined + } + ) { + super(tokenOwnerRecords.community, tokenOwnerRecords.council) + } + + hasAnyWeight() { + return ( + (!!this.voterWeights.community && + !this.voterWeights.community.isZero()) || + (!!this.voterWeights.council && !this.voterWeights.council.isZero()) + ) + } + + hasMinCommunityWeight(minCommunityWeight: BN) { + return ( + !!this.communityTokenRecord && + this.voterWeights.community?.gte(minCommunityWeight) + ) + } + hasMinCouncilWeight(minCouncilWeight: BN) { + return ( + !!this.councilTokenRecord && + this.voterWeights.council?.gte(minCouncilWeight) + ) + } + + hasMinAmountToVote(mintPk: PublicKey) { + const isCommunity = + this.communityTokenRecord?.account.governingTokenMint.toBase58() === + mintPk.toBase58() + const isCouncil = + this.councilTokenRecord?.account.governingTokenMint.toBase58() === + mintPk.toBase58() + + if (isCouncil) return this.hasMinCouncilWeight(new BN(0)) + if (isCommunity) return this.hasMinCommunityWeight(new BN(0)) + return false } } @@ -407,7 +471,7 @@ export class SimpleGatedVoterWeight implements VoterWeightInterface { } /** Returns max VoteWeight for given mint and max source */ -function getMintMaxVoteWeight( +export function getMintMaxVoteWeight( mint: MintInfo, maxVoteWeightSource: MintMaxVoteWeightSource ) { diff --git a/package.json b/package.json index e5d7915507..1952442851 100644 --- a/package.json +++ b/package.json @@ -29,25 +29,24 @@ ] }, "dependencies": { - "@blockworks-foundation/mango-mints-redemption": "0.0.10", - "@blockworks-foundation/mango-v4": "0.21.5", - "@blockworks-foundation/mango-v4-settings": "0.4.4", - "@blockworks-foundation/mangolana": "0.0.1-beta.15", + "@blockworks-foundation/mango-mints-redemption": "0.0.11", + "@blockworks-foundation/mango-v4": "0.33.6", + "@blockworks-foundation/mango-v4-settings": "0.14.24", + "@blockworks-foundation/mangolana": "0.1.2", "@bonfida/spl-name-service": "0.1.47", "@bundlr-network/client": "0.7.15", "@carbon/icons-react": "11.7.0", "@civic/profile": "^0.5.0-beta.1", - "@civic/solana-gateway-react": "0.15.0", - "@coral-xyz/anchor": "0.27.0", + "@civic/solana-gateway-react": "^0.16.10", + "@coral-xyz/anchor": "0.29.0", "@coral-xyz/borsh": "0.27.0", - "@dialectlabs/react-sdk-blockchain-solana": "1.0.0-beta.3", - "@dialectlabs/react-ui": "1.1.0-beta.5", - "@dual-finance/airdrop": "0.2.2", - "@dual-finance/gso": "0.0.14", + "@dialectlabs/react-sdk-blockchain-solana": "^2.0.3", + "@dialectlabs/react-ui": "^2.0.7", + "@dual-finance/airdrop": "0.3.1", + "@dual-finance/gso": "0.0.17", "@dual-finance/staking-options": "0.0.26", "@emotion/react": "11.9.0", "@emotion/styled": "11.8.1", - "@foresight-tmp/foresight-sdk": "0.1.46", "@headlessui/react": "1.6.6", "@helium/helium-sub-daos-sdk": "0.0.44", "@helium/idls": "0.0.44", @@ -65,13 +64,13 @@ "@next/bundle-analyzer": "12.1.5", "@nivo/bar": "0.79.1", "@nivo/core": "0.79.0", - "@notifi-network/notifi-core": "0.18.2", - "@notifi-network/notifi-react-hooks": "0.18.2", + "@parcl-oss/staking": "0.0.2", "@project-serum/common": "0.0.1-beta.3", "@project-serum/serum": "0.13.65", "@project-serum/sol-wallet-adapter": "0.2.6", "@pythnetwork/client": "2.17.0", - "@pythnetwork/staking": "^2.0.0", + "@pythnetwork/staking-sdk": "0.0.2", + "@pythnetwork/staking-wasm": "0.3.5", "@radix-ui/react-accordion": "1.0.0", "@radix-ui/react-aspect-ratio": "1.0.0", "@radix-ui/react-dialog": "1.0.0", @@ -88,29 +87,33 @@ "@radix-ui/react-toast": "1.0.0", "@radix-ui/react-toolbar": "1.0.0", "@radix-ui/react-tooltip": "1.0.0", + "@realms-today/spl-governance": "0.3.29", "@sentry/nextjs": "7.81.1", "@solana-mobile/wallet-adapter-mobile": "2.0.0", "@solana/buffer-layout": "4.0.0", - "@solana/governance-program-library": "npm:@civic/governance-program-library@0.16.9-beta.2", + "@solana/governance-program-library": "npm:@civic/governance-program-library@0.18.2-beta.24", + "@solana/spl-account-compression": "~0.2.0", "@solana/spl-governance": "0.3.28", + "@solana/spl-stake-pool": "1.1.5", "@solana/spl-token": "0.1.8", "@solana/wallet-adapter-backpack": "0.1.13", "@solana/wallet-adapter-base": "0.9.22", "@solana/wallet-adapter-exodus": "0.1.17", "@solana/wallet-adapter-glow": "0.1.17", "@solana/wallet-adapter-phantom": "0.9.22", - "@solana/wallet-adapter-react": "0.15.30", - "@solana/wallet-adapter-solflare": "0.6.24", + "@solana/wallet-adapter-react": "0.15.32", + "@solana/wallet-adapter-solflare": "0.6.28", "@solana/wallet-adapter-sollet": "0.11.16", "@solana/wallet-adapter-torus": "0.11.27", - "@solana/wallet-adapter-walletconnect": "0.1.14", - "@solana/wallet-adapter-wallets": "0.19.15", - "@solana/web3.js": "1.78.2", - "@solana/spl-account-compression": "~0.2.0", + "@solana/wallet-adapter-walletconnect": "0.1.16", + "@solana/wallet-adapter-wallets": "0.19.16", + "@solana/web3.js": "1.78.8", "@solendprotocol/solend-sdk": "0.5.5", "@sqds/iframe-adapter": "1.0.16", + "@sqds/mesh": "1.0.6", "@switchboard-xyz/sbv2-lite": "0.2.4", - "@switchboard-xyz/solana.js": "3.1.5", + "@switchboard-xyz/solana.js": "3.2.5", + "@symmetry-hq/baskets-sdk": "0.0.45", "@tailwindcss/forms": "0.5.3", "@tailwindcss/line-clamp": "0.4.2", "@tanstack/react-query": "4.14.3", @@ -121,6 +124,7 @@ "@urql/exchange-multipart-fetch": "1.0.1", "@urql/exchange-persisted-fetch": "2.0.0", "@urql/exchange-request-policy": "1.0.0", + "add-to-calendar-button-react": "2.6.13", "arweave": "1.11.4", "axios": "0.26.1", "bignumber.js": "9.0.2", @@ -132,6 +136,7 @@ "d3": "7.4.4", "date-fns": "2.29.2", "dayjs": "1.11.1", + "decimal.js": "10.4.3", "draft-js": "0.11.7", "figlet": "1.5.2", "fp-ts": "2.12.2", @@ -158,13 +163,14 @@ "react-headless-pagination": "0.1.0", "react-hook-form": "7.31.3", "react-icons": "4.11.0", + "react-intersection-observer": "9.5.3", "react-markdown": "7.0.0", "react-portal": "4.2.2", "react-responsive": "9.0.0-beta.10", "react-virtualized-auto-sizer": "1.0.6", - "react-window": "1.8.9", + "react-window": "1.8.10", "remark-gfm": "3.0.1", - "superstruct": "0.15.4", + "superstruct": "1.0.4", "swr": "1.3.0", "tailwind-merge": "1.6.0", "ts-node": "10.9.1", @@ -184,15 +190,15 @@ "@types/js-cookie": "3.0.2", "@types/node": "14.14.25", "@types/react": "17.0.44", - "@typescript-eslint/eslint-plugin": "5.30.6", - "@typescript-eslint/parser": "5.30.6", - "eslint": "8.17.0", - "eslint-config-prettier": "8.5.0", - "eslint-plugin-import": "2.26.0", - "eslint-plugin-prettier": "4.2.1", - "eslint-plugin-react": "7.29.4", - "eslint-plugin-react-hooks": "4.6.0", - "eslint-plugin-unused-imports": "2.0.0", + "@typescript-eslint/eslint-plugin": "8.1.0", + "@typescript-eslint/parser": "8.1.0", + "eslint": "9.9.0", + "eslint-config-prettier": "9.1.0", + "eslint-plugin-import": "2.29.1", + "eslint-plugin-prettier": "5.2.1", + "eslint-plugin-react": "7.35.0", + "eslint-plugin-react-hooks": "4.6.2", + "eslint-plugin-unused-imports": "4.1.3", "husky": "8.0.1", "jest": "29.2.0", "jest-environment-jsdom": "29.2.2", @@ -205,7 +211,7 @@ "ts-jest": "29.0.3", "ts-loader": "9.3.1", "twin.macro": "2.4.0", - "typescript": "4.9.5", + "typescript": "5.5.4", "yarn-deduplicate": "6.0.0" }, "babelMacros": { @@ -223,6 +229,8 @@ "@types/bn.js": "5.1.0", "@project-serum/sol-wallet-adapter": "0.2.6", "@project-serum/serum": "0.13.65", + "@pythnetwork/staking-sdk/@coral-xyz/anchor": "0.30.1", + "@coral-xyz/anchor": "0.29.0", "@coral-xyz/borsh": "0.27.0", "bignumber.js": "9.0.2", "lodash": "4.17.21", @@ -234,12 +242,14 @@ "@nivo/bar/**/d3-color": "3.1.0", "dset": "3.1.2", "**/@solana/spl-token-registry/cross-fetch/node-fetch": "2.6.7", + "**/@blockworks-foundation/mangolana/node-fetch": "npm:@blockworks-foundation/node-fetch@2.6.11", "@bonfida/spl-name-service": "0.1.47", "@bundlr-network/client": "0.7.15", "@carbon/icons-react": "11.7.0", "@cardinal/namespaces-components": "2.5.5", "crypto-js": ">=4.1.1", - "@solana/web3.js": "1.78.2" + "@solana/web3.js": "1.78.8", + "protobufjs": ">=7.2.5" }, "browser": { "child_process": false @@ -268,7 +278,15 @@ "@solana/web3.js>rpc-websockets>utf-8-validate": true, "@testing-library/react>@testing-library/dom>aria-query>@babel/runtime-corejs3>core-js-pure": false, "draft-js>fbjs>core-js": false, - "@switchboard-xyz/solana.js>@switchboard-xyz/common>protobufjs": false + "@switchboard-xyz/solana.js>@switchboard-xyz/common>protobufjs": false, + "@blockworks-foundation/mango-v4>@raydium-io/raydium-sdk>tsup>esbuild": true, + "@blockworks-foundation/mangolana>@solana/web3.js>bigint-buffer": true, + "@blockworks-foundation/mangolana>ws>bufferutil": true, + "@blockworks-foundation/mangolana>ws>utf-8-validate": true } + }, + "volta": { + "node": "18.19.0", + "yarn": "1.22.19" } } diff --git a/pages/_app.tsx b/pages/_app.tsx index 7fae21c616..52d793f6f8 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,5 +1,4 @@ import type { AppProps } from 'next/app' -import '@dialectlabs/react-ui/index.css' import { App as BaseApp } from '@components/App' import { App as HubApp } from '@hub/App' 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/api/daoProgramStatistics.api.ts b/pages/api/daoProgramStatistics.api.ts index 9255c1b00b..09e203784d 100644 --- a/pages/api/daoProgramStatistics.api.ts +++ b/pages/api/daoProgramStatistics.api.ts @@ -6,9 +6,9 @@ import { getAllSplGovernanceProgramIds } from './tools/realms' import { withSentry } from '@sentry/nextjs' const handler = async (req: NextApiRequest, res: NextApiResponse) => { - if (!process.env.BACKEND_MAINNET_RPC) - return res.status(500).json('BACKEND_MAINNET_RPC not provided in env') - const conn = new Connection(process.env.BACKEND_MAINNET_RPC, 'recent') + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') console.log('fetching spl-gov instances...') // Get all realms diff --git a/pages/api/daoStatistics.api.ts b/pages/api/daoStatistics.api.ts index dc59aa37e8..a64e45290b 100644 --- a/pages/api/daoStatistics.api.ts +++ b/pages/api/daoStatistics.api.ts @@ -59,9 +59,9 @@ async function getGovernances( } const handler = async (req: NextApiRequest, res: NextApiResponse) => { - if (!process.env.BACKEND_MAINNET_RPC) - return res.status(500).json('BACKEND_MAINNET_RPC not provided in env') - const conn = new Connection(process.env.BACKEND_MAINNET_RPC, 'recent') + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') console.log('fetching spl-gov instances...') // Get all realms diff --git a/pages/api/daoVoteStatistics.api.ts b/pages/api/daoVoteStatistics.api.ts index 69d47ce78f..e6170328ee 100644 --- a/pages/api/daoVoteStatistics.api.ts +++ b/pages/api/daoVoteStatistics.api.ts @@ -12,9 +12,9 @@ import { NextApiRequest, NextApiResponse } from 'next' import { getAllSplGovernanceProgramIds } from './tools/realms' const handler = async (req: NextApiRequest, res: NextApiResponse) => { - if (!process.env.BACKEND_MAINNET_RPC) - return res.status(500).json('BACKEND_MAINNET_RPC not provided in env') - const conn = new Connection(process.env.BACKEND_MAINNET_RPC, 'recent') + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') console.log('fetching spl-gov instances...') // Get all realms diff --git a/pages/api/daoVoteUserStatistics.api.ts b/pages/api/daoVoteUserStatistics.api.ts index b246b3a693..a6de475282 100644 --- a/pages/api/daoVoteUserStatistics.api.ts +++ b/pages/api/daoVoteUserStatistics.api.ts @@ -19,9 +19,9 @@ import { NextApiRequest, NextApiResponse } from 'next' import mainnetList from 'public/realms/mainnet-beta.json' const handler = async (req: NextApiRequest, res: NextApiResponse) => { - if (!process.env.BACKEND_MAINNET_RPC) - return res.status(500).json('BACKEND_MAINNET_RPC not provided in env') - const conn = new Connection(process.env.BACKEND_MAINNET_RPC, 'recent') + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') const { dao, user } = req.query if (!dao) { diff --git a/pages/api/getDecodedMangoInstructionsFromProposal.api.ts b/pages/api/getDecodedMangoInstructionsFromProposal.api.ts new file mode 100644 index 0000000000..464a1951e3 --- /dev/null +++ b/pages/api/getDecodedMangoInstructionsFromProposal.api.ts @@ -0,0 +1,92 @@ +import { NextApiRequest, NextApiResponse } from 'next' +import { withSentry } from '@sentry/nextjs' +import { Connection } from '@solana/web3.js' +import { + ProposalTransaction, + getGovernanceAccounts, + getProposal, + pubkeyFilter, +} from '@solana/spl-governance' +import { PublicKey } from '@metaplex-foundation/js' +import { MANGO_V4_ID } from '@blockworks-foundation/mango-v4' +import { MANGO_BOOST_PROGRAM_ID } from '@hooks/useMangoV4' +import { getClient } from '@utils/mangoV4Tools' +import { BN, BorshInstructionCoder } from '@coral-xyz/anchor' + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') + + const proposalPk = req.query.proposal + if (!proposalPk) { + return res.status(403).json('Please provide proposal param') + } + const proposal = await getProposal(conn, new PublicKey(proposalPk)) + const results = await getGovernanceAccounts( + conn, + proposal.owner, + ProposalTransaction, + [pubkeyFilter(1, proposal.pubkey)!] + ) + + const decodedMangoInstruction = await Promise.all( + results + .flatMap((x) => x.account.instructions) + .filter( + (x) => + x?.programId.equals(MANGO_V4_ID['mainnet-beta']) || + x?.programId.equals(MANGO_BOOST_PROGRAM_ID) + ) + .map((x) => getDataObjectFlattened(conn, x.data)) + ) + console.log(decodedMangoInstruction) + res.status(200).json([...decodedMangoInstruction]) +} + +export default withSentry(handler) + +async function getDataObjectFlattened( + connection: Connection, + data: Uint8Array +) { + 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]}`, + // } + // }) + // ) + + 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}` + } + } + } + return args as T + } catch (e) { + return {} as T + } +} diff --git a/pages/api/mangoAccountsWithDeposit.api.ts b/pages/api/mangoAccountsWithDeposit.api.ts index abf8a95d11..016092f58a 100644 --- a/pages/api/mangoAccountsWithDeposit.api.ts +++ b/pages/api/mangoAccountsWithDeposit.api.ts @@ -12,9 +12,9 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { if (!mint) { return res.status(403).json('Please provide mint param') } - if (!process.env.BACKEND_MAINNET_RPC) - return res.status(500).json('BACKEND_MAINNET_RPC not provided in env') - const conn = new Connection(process.env.BACKEND_MAINNET_RPC, 'recent') + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') const MAINNET_GROUP = new PublicKey( '78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX' ) @@ -31,7 +31,10 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { const client = await MangoClient.connect( adminProvider, clientCluster, - MANGO_V4_ID[clientCluster] + MANGO_V4_ID[clientCluster], + { + idsSource: 'api', + } ) const group = await client.getGroup(MAINNET_GROUP) @@ -48,6 +51,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => { .map((x) => ({ mangoAccount: x.publicKey.toBase58(), wallet: x.owner.toBase58(), + amount: x.getTokenBalanceUi(bankForMint[0]), })) res.status(200).json(usersWithNonZeroBalance) diff --git a/pages/api/vsrDeposits.api.ts b/pages/api/vsrDeposits.api.ts new file mode 100644 index 0000000000..72b563c21c --- /dev/null +++ b/pages/api/vsrDeposits.api.ts @@ -0,0 +1,61 @@ +import { Connection, Keypair, PublicKey } from '@solana/web3.js' + +import { NextApiRequest, NextApiResponse } from 'next' +import { withSentry } from '@sentry/nextjs' +import { AnchorProvider, BN } from '@coral-xyz/anchor' +import EmptyWallet from '@utils/Mango/listingTools' +import { toUiDecimals } from '@blockworks-foundation/mango-v4' +import { VsrClient } from 'VoteStakeRegistry/sdk/client' + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + if (!process.env.MAINNET_RPC) + return res.status(500).json('MAINNET_RPC not provided in env') + const conn = new Connection(process.env.MAINNET_RPC, 'recent') + + const options = AnchorProvider.defaultOptions() + const adminProvider = new AnchorProvider( + conn, + new EmptyWallet(Keypair.generate()), + options + ) + const registrar = new PublicKey( + '4WQSYg21RrJNYhF4251XFpoy1uYbMHcMfZNLMXA3x5Mp' + ) + + const vsr = await VsrClient.connect( + adminProvider, + new PublicKey('4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo') + ) + const voters = await vsr.program.account['voter'].all() + const resp: any[] = [] + + for (const voter of voters) { + if (voter.account.registrar.toString() != registrar.toString()) { + continue + } + + const deposited = new BN(0) + // @ts-ignore + for (const entry of voter.account.deposits) { + if (entry.isUsed && entry.votingMintConfigIdx == 0) { + deposited.iadd(entry.amountDepositedNative) + } + } + if (deposited.gt(new BN(0))) { + console.log({ + voter: voter.publicKey.toString(), + wallet: voter.account.voterAuthority.toString(), + deposited: toUiDecimals(deposited, 6), + }) + resp.push({ + voter: voter.publicKey.toString(), + wallet: voter.account.voterAuthority.toString(), + deposited: toUiDecimals(deposited, 6), + }) + } + } + + res.status(200).json(resp) +} + +export default withSentry(handler) 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 7f9c38c00c..ead1933b29 100644 --- a/pages/dao/[symbol]/index.tsx +++ b/pages/dao/[symbol]/index.tsx @@ -26,8 +26,6 @@ import Switch from '@components/Switch' import ProposalSelectCard from '@components/ProposalSelectCard' import Checkbox from '@components/inputs/Checkbox' import Button from '@components/Button' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' import { notify } from '@utils/notifications' import { sendSignedTransaction } from '@utils/send' import { compareProposals, filterProposals } from '@utils/proposals' @@ -53,9 +51,11 @@ import { useRealmProposalsQuery, } 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' +import { useNftClient } from '../../../VoterWeightPlugins/useNftClient' +import { useVotingClients } from '@hooks/useVotingClients' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const AccountsCompactWrapper = dynamic( () => import('@components/TreasuryAccount/AccountsCompactWrapper') @@ -79,7 +79,6 @@ const REALM = () => { const realmQuery = useRealmQuery() const mint = useRealmCommunityMintInfoQuery().data?.result const councilMint = useRealmCouncilMintInfoQuery().data?.result - const { result: ownVoterWeight } = useLegacyVoterWeight() const { realmInfo } = useRealm() const proposalsPerPage = 20 const [filters, setFilters] = useState(InitialFilters) @@ -96,9 +95,8 @@ const REALM = () => { SelectedProposal[] >([]) - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients() + const { nftClient } = useNftClient() const wallet = useWalletOnePointOh() const { connection } = useConnection() @@ -225,18 +223,19 @@ const REALM = () => { } }, []) + const { + ownVoterWeight: communityOwnVoterWeight, + } = useRealmVoterWeightPlugins('community') + const { ownVoterWeight: councilOwnVoterWeight } = useRealmVoterWeightPlugins( + 'council' + ) + const allVotingProposalsSelected = selectedProposals.length === votingProposals?.length const hasCommunityVoteWeight = - ownTokenRecord && - ownVoterWeight?.hasMinAmountToVote( - ownTokenRecord.account.governingTokenMint - ) + ownTokenRecord && communityOwnVoterWeight?.value?.gtn(0) const hasCouncilVoteWeight = - ownCouncilTokenRecord && - ownVoterWeight?.hasMinAmountToVote( - ownCouncilTokenRecord.account.governingTokenMint - ) + ownCouncilTokenRecord && councilOwnVoterWeight?.value?.gtn(0) const cantMultiVote = selectedProposals.length === 0 || @@ -278,6 +277,11 @@ const REALM = () => { realm.account.communityMint.toBase58() ? ownTokenRecord : ownCouncilTokenRecord + const role = + selectedProposal.proposal.governingTokenMint.toBase58() === + realm.account.communityMint.toBase58() + ? 'community' + : 'council' if (relevantTokenRecord === undefined) throw new Error('token owner record not found or not yet loaded') @@ -285,7 +289,7 @@ const REALM = () => { const instructions: TransactionInstruction[] = [] //will run only if plugin is connected with realm - const plugin = await client?.withCastPluginVote( + const plugin = await votingClients(role)?.withCastPluginVote( instructions, { account: selectedProposal.proposal, @@ -294,7 +298,7 @@ const REALM = () => { }, relevantTokenRecord.pubkey ) - if (client.client instanceof NftVoterClient === false) { + if (!nftClient) { await withCastVote( instructions, realmInfo!.programId, diff --git a/pages/dao/[symbol]/members/Members.tsx b/pages/dao/[symbol]/members/Members.tsx index ef230c195b..bfde56dda8 100644 --- a/pages/dao/[symbol]/members/Members.tsx +++ b/pages/dao/[symbol]/members/Members.tsx @@ -15,6 +15,11 @@ 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' +import VsrMembers from './VsrMembers' const Members = () => { const { @@ -25,7 +30,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 { @@ -37,7 +41,20 @@ const Members = () => { const [openAddMemberModal, setOpenAddMemberModal] = useState(false) const [searchString, setSearchString] = useState('') const [filteredMembers, setFilteredMembers] = useState([]) + const [councilMode, setCouncilMode] = useState(true) + + const { connection } = useConnection() + const realmPk = useSelectedRealmPubkey() + const { data: activeMembers } = 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 filterMembers = (v) => { if (activeMembers !== undefined) { setSearchString(v) @@ -83,134 +100,153 @@ const Members = () => { pagination?.current?.setPage(0) // 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 }, [JSON.stringify(filteredMembers)]) - + return (
-
-
-
- -
-
-
- {realmInfo?.ogImage ? ( - - ) : null} -
-

{realmInfo?.displayName}

-

Members

-
+ {openAddMemberModal && ( + setOpenAddMemberModal(false)} + isOpen={openAddMemberModal} + > + setOpenAddMemberModal(false)} /> + + )} + {!councilMode && councilOnly ? + : +
+
+
+
-
-
-
- -
-

Members

- {activeMembers !== undefined && ( -
- {activeMembers.length} -
- )} +
+
+ {realmInfo?.ogImage ? ( + + ) : null} +
+

{realmInfo?.displayName}

+

{ + councilOnly && councilMode ? 'Council ' : + councilOnly ? 'All' : '' + } Members +

+
+ {councilOnly && +
setCouncilMode(!councilMode)} + > + {councilMode ? 'All' : 'Council'} Members +
+ } +
+
+
+
+ +
+

Members

+ {activeMembers !== undefined && ( +
+ {activeMembers.length} +
+ )} +
-
-
- {activeMembers !== undefined && activeMembers.length > 15 ? ( -
- filterMembers(e.target.value)} - placeholder={`Search by Wallet Address...`} - prefix={} - /> +
+ {activeMembers !== undefined && activeMembers.length > 15 ? ( +
+ filterMembers(e.target.value)} + placeholder={`Search by Wallet Address...`} + prefix={} + /> +
+ ) : null} +
+

+ {searchString.length > 0 + ? `${filteredMembers.length} Members Found` + : `${activeMembers ? activeMembers.length : ''} Members`} +

+ + setOpenAddMemberModal(!openAddMemberModal)} + className={`flex items-center text-primary-light whitespace-nowrap ${ + addNewMemberTooltip + ? 'cursor-not-allowed pointer-events-none opacity-60' + : 'cursor-pointer' + }`} + > + + New Member + +
- ) : null} -
-

- {searchString.length > 0 - ? `${filteredMembers.length} Members Found` - : `${activeMembers ? activeMembers.length : ''} Members`} -

- - setOpenAddMemberModal(!openAddMemberModal)} - className={`flex items-center text-primary-light whitespace-nowrap ${ - addNewMemberTooltip - ? 'cursor-not-allowed pointer-events-none opacity-60' - : 'cursor-pointer' - }`} +
+ - setActiveMember( - // @ts-ignore - activeMembers.find((m) => { - return m.walletAddress === v - }) - ) - } - placeholder="Please select..." - value={activeMember?.walletAddress} - > - {activeMembers?.map((x) => { - return ( - - {x?.walletAddress} - - ) - })} - + {activeMembers?.map((x) => { + return ( + + {x?.walletAddress} + + ) + })} + +
+
+ {activeMember !== undefined && ( + setActiveMember(t)} + tabs={paginatedMembers} + /> + )} + +
-
- {activeMember !== undefined && ( - setActiveMember(t)} - tabs={paginatedMembers} +
+ {activeMember ? ( + - )} - + ) : null}
-
- {activeMember ? ( - - ) : null} -
-
- {openAddMemberModal && ( - setOpenAddMemberModal(false)} - isOpen={openAddMemberModal} - > - setOpenAddMemberModal(false)} /> - - )} + }
) } diff --git a/pages/dao/[symbol]/members/VsrMembers.tsx b/pages/dao/[symbol]/members/VsrMembers.tsx new file mode 100644 index 0000000000..b2b8fd4c2d --- /dev/null +++ b/pages/dao/[symbol]/members/VsrMembers.tsx @@ -0,0 +1,202 @@ +import MemberOverview from "@components/Members/MemberOverview" +import MembersTabs from "@components/Members/MembersTabs" +import { SearchIcon, UsersIcon } from "@heroicons/react/solid" +import { useTokenOwnerRecordsForRealmQuery } from "@hooks/queries/tokenOwnerRecord" +import Input from '@components/inputs/Input' +import { Member } from "@utils/uiTypes/members" +import { BN } from "bn.js" +import { useEffect, useMemo, useRef, useState } from "react" +import Select from '@components/inputs/Select' +import PaginationComponent from '@components/Pagination' +import useRealm from "@hooks/useRealm" +import PreviousRouteBtn from "@components/PreviousRouteBtn" + + +function VsrMembers({ + councilMode, councilOnly, setCouncilMode +} : { + councilMode: boolean, + councilOnly: boolean, + setCouncilMode: (b: boolean) => void +}) { + const { + realmInfo, + } = useRealm() + + const pagination = useRef<{ setPage: (val) => void }>(null) + const membersPerPage = 10 + + const [searchString, setSearchString] = useState('') + const [filteredMembers, setFilteredMembers] = useState([]) + const [activeMember, setActiveMember] = useState() + const [paginatedMembers, setPaginatedMembers] = useState([]) + + const {data: vsrMembersData} = useTokenOwnerRecordsForRealmQuery() + const activeMembers: Member[] | undefined = useMemo(() => ( + vsrMembersData?.map( + member => ({ + walletAddress: member.account.governingTokenOwner.toBase58(), + communityVotes: new BN(0), + councilVotes: new BN(0) + }) + ) + ), [vsrMembersData]) + + const filterMembers = (v) => { + if (activeMembers !== undefined) { + setSearchString(v) + if (v.length > 0) { + const filtered = activeMembers.filter((r) => + r.walletAddress?.toLowerCase().includes(v.toLowerCase()) + ) + setFilteredMembers(filtered) + } else { + setFilteredMembers(activeMembers) + } + } + } + + const onPageChange = (page) => { + setPaginatedMembers(paginateMembers(page)) + } + const paginateMembers = (page) => { + return filteredMembers.slice( + page * membersPerPage, + (page + 1) * membersPerPage + ) + } + + useEffect(() => { + if (activeMembers && activeMembers.length > 0) { + setActiveMember(activeMembers[0]) + setFilteredMembers(activeMembers) + } + }, [activeMembers]) + + useEffect(() => { + setPaginatedMembers(paginateMembers(0)) + pagination?.current?.setPage(0) + // 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 + }, [JSON.stringify(filteredMembers)]) + + return ( +
+
+
+ +
+
+
+ {realmInfo?.ogImage ? ( + + ) : null} +
+

{realmInfo?.displayName}

+

{ + councilOnly && councilMode ? 'Council ' : + councilOnly ? 'All' : '' + } Members +

+
+ {councilOnly && +
setCouncilMode(!councilMode)} + > + {councilMode ? 'All' : 'Council'} Members +
+ } +
+
+
+
+ +
+

Members

+ {activeMembers !== undefined && ( +
+ {activeMembers.length} +
+ )} +
+
+
+
+
+
+
+ {activeMembers !== undefined && activeMembers.length > 15 ? ( +
+ filterMembers(e.target.value)} + placeholder={`Search by Wallet Address...`} + prefix={} + /> +
+ ) : null} +
+

+ {searchString.length > 0 + ? `${filteredMembers.length} Members Found` + : `${activeMembers ? activeMembers.length : ''} Members`} +

+
+
+ +
+
+ {activeMember !== undefined && ( + setActiveMember(t)} + tabs={paginatedMembers} + vsrMode={true} + /> + )} + +
+
+
+ {activeMember ? ( + + ) : null} +
+
+ ) +} + +export default VsrMembers \ No newline at end of file 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]/params/MetadataCreationModal.tsx b/pages/dao/[symbol]/params/MetadataCreationModal.tsx index 7f7406b0da..aa4ec56b87 100644 --- a/pages/dao/[symbol]/params/MetadataCreationModal.tsx +++ b/pages/dao/[symbol]/params/MetadataCreationModal.tsx @@ -15,7 +15,7 @@ import useQueryContext from '@hooks/useQueryContext' import { useRouter } from 'next/router' import { notify } from '@utils/notifications' import useRealm from '@hooks/useRealm' -import { useEffect, useState } from 'react' +import React, { useEffect, useState } from 'react' import Button from '@components/Button' import * as yup from 'yup' import { useDropzone } from 'react-dropzone' @@ -30,6 +30,7 @@ import { Metaplex } from '@metaplex-foundation/js' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import {useVoteByCouncilToggle} from "@hooks/useVoteByCouncilToggle"; interface GovernanceConfigForm { mintAccount: AssetAccount | undefined @@ -51,7 +52,7 @@ const MetadataCreationModal = ({ }) => { const router = useRouter() const realm = useRealmQuery().data?.result - const { canChooseWhoVote, symbol, realmInfo } = useRealm() + const {symbol, realmInfo } = useRealm() const programId: PublicKey | undefined = realmInfo?.programId const { assetAccounts } = useGovernanceAssets() @@ -65,7 +66,7 @@ const MetadataCreationModal = ({ const { handleCreateProposal } = useCreateProposal() const [formErrors, setFormErrors] = useState({}) const [creatingProposal, setCreatingProposal] = useState(false) - const [voteByCouncil, setVoteByCouncil] = useState(false) + const { voteByCouncil, shouldShowVoteByCouncilToggle, setVoteByCouncil } = useVoteByCouncilToggle(); const [selectedImage, setSelectedImage] = useState(null) const [imageFile, setImageFile] = useState(null) const [mintAuthority, setMintAuthority] = useState< @@ -400,13 +401,13 @@ const MetadataCreationModal = ({ } > - {canChooseWhoVote && ( - { - setVoteByCouncil(!voteByCouncil) - }} - > + {shouldShowVoteByCouncilToggle && ( + { + setVoteByCouncil(!voteByCouncil) + }} + > )}
diff --git a/pages/dao/[symbol]/params/index.tsx b/pages/dao/[symbol]/params/index.tsx index 236526f493..e8b0233711 100644 --- a/pages/dao/[symbol]/params/index.tsx +++ b/pages/dao/[symbol]/params/index.tsx @@ -29,6 +29,8 @@ import { useRealmQuery } from '@hooks/queries/realm' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' import { useRealmCommunityMintInfoQuery } from '@hooks/queries/mintInfo' import { useRealmGovernancesQuery } from '@hooks/queries/governance' +import useFormatTokenAmount from '@hooks/useFormatTokenAmount' +import { BN } from 'bn.js' const Params = () => { const mint = useRealmCommunityMintInfoQuery().data?.result @@ -48,6 +50,7 @@ const Params = () => { const mintGovernancesWithMintInfo = assetAccounts.filter((x) => { return x.type === AccountType.MINT }) + const formatTokenAmount = useFormatTokenAmount(realm?.account.communityMint) const hasAuthorityGovernances = governancesArray?.filter((governance) => { const filteredMintGovernances = mintGovernancesWithMintInfo.filter( @@ -109,6 +112,7 @@ const Params = () => { DISABLED_VOTER_WEIGHT.eq(realmConfig.minCommunityTokensToCreateGovernance) ? 'Disabled' : realmConfig?.minCommunityTokensToCreateGovernance && + mint && fmtMintAmount(mint, realmConfig.minCommunityTokensToCreateGovernance) useEffect(() => { @@ -214,12 +218,22 @@ const Params = () => { {communityMintMaxVoteWeightSource && ( )} diff --git a/pages/dao/[symbol]/proposal/[pk]/ProposalWarnings.tsx b/pages/dao/[symbol]/proposal/[pk]/ProposalWarnings.tsx index 5699182923..1957a813de 100644 --- a/pages/dao/[symbol]/proposal/[pk]/ProposalWarnings.tsx +++ b/pages/dao/[symbol]/proposal/[pk]/ProposalWarnings.tsx @@ -1,5 +1,6 @@ import { MANGO_INSTRUCTION_FORWARDER } from '@components/instructions/tools' import { ExclamationCircleIcon } from '@heroicons/react/solid' +import { useBufferAccountsAuthority } from '@hooks/queries/bufferAuthority' import { useGovernanceByPubkeyQuery } from '@hooks/queries/governance' import { useSelectedProposalTransactions } from '@hooks/queries/proposalTransaction' import { useRealmConfigQuery } from '@hooks/queries/realmConfig' @@ -23,14 +24,14 @@ const SetRealmConfigWarning = () => (

- Instructions like this one are dangerous + Instructions like this one change the way the DAO is governed

- This proposal writes to your realm configuration, this could affect - how votes are counted. Both the instruction data AND accounts list - contain parameters. Do not pass this proposal if there are any - accounts you do not recognize. + This proposal writes to your realm configuration, which could affect how + votes are counted. Both the instruction data AND accounts list contain parameters. + Before you vote, make sure you review the proposal's instructions and the concerned + accounts, and understand the implications of passing this proposal.

@@ -74,14 +75,14 @@ const SetGovernanceConfig = () => (

- Instructions like this one are dangerous + Instructions like this one change the way the DAO is governed

- This proposal writes to your governance configuration, this could - affect how votes are counted. Both the instruction data AND accounts - list contain parameters. Do not pass this proposal if there are any - accounts you do not recognize. + This proposal writes to your governance configuration, which could affect how + votes are counted. Both the instruction data AND accounts list contain parameters. + Before you vote, make sure you review the proposal's instructions and the concerned + accounts, and understand the implications of passing this proposal.

@@ -130,6 +131,30 @@ const ProgramUpgrade = () => (
) +const BufferAuthorityMismatch = () => ( +
+
+
+
+
+

+ Danger alert: The current buffer authority does not match the DAO + wallet +

+
+

+ The current authority can change the buffer account during vote. +

+
+
+
+
+) + const ForwardWarning = () => (
@@ -160,6 +185,7 @@ const useProposalSafetyCheck = (proposal: Proposal) => { const config = useRealmConfigQuery().data?.result const { realmInfo } = useRealm() const { data: transactions } = useSelectedProposalTransactions() + const { data: bufferAuthorities } = useBufferAccountsAuthority() const governance = useGovernanceByPubkeyQuery(proposal?.governance).data ?.result @@ -203,6 +229,7 @@ const useProposalSafetyCheck = (proposal: Proposal) => { | 'possibleWrongGovernance' | 'programUpgrade' | 'usingMangoInstructionForwarder' + | 'bufferAuthorityMismatch' | undefined )[] = [] @@ -238,6 +265,19 @@ const useProposalSafetyCheck = (proposal: Proposal) => { proposalWarnings.push('possibleWrongGovernance') } + if (treasuryAddress.result) { + const treasury = treasuryAddress.result + if ( + governance && + bufferAuthorities?.some( + (authority) => + !authority.equals(treasury) && !authority.equals(governance.pubkey) + ) + ) { + proposalWarnings.push('bufferAuthorityMismatch') + } + } + return proposalWarnings }, [ realmInfo, @@ -269,6 +309,9 @@ const ProposalWarnings = ({ proposal }: { proposal: Proposal }) => { {warnings?.includes('usingMangoInstructionForwarder') && ( )} + {warnings?.includes('bufferAuthorityMismatch') && ( + + )} ) } diff --git a/pages/dao/[symbol]/proposal/[pk]/explore.tsx b/pages/dao/[symbol]/proposal/[pk]/explore.tsx index 4a03e5998a..8887b24e06 100644 --- a/pages/dao/[symbol]/proposal/[pk]/explore.tsx +++ b/pages/dao/[symbol]/proposal/[pk]/explore.tsx @@ -44,6 +44,8 @@ export default function Explore() { proposal?.account.voteType !== VoteType.SINGLE_CHOICE && proposal?.account.accountType === GovernanceAccountType.ProposalV2 + const voterCount = records.filter(r => r.voteType !== 1).length + return (
-
+

Number of Voters: {voterCount}

+

Top Voters

{ const { realmInfo, symbol } = useRealm() const proposal = useRouteProposalQuery().data?.result const governance = useProposalGovernanceQuery().data?.result + const tor = useTokenOwnerRecordByPubkeyQuery(proposal?.account.tokenOwnerRecord).data?.result + const { connection } = useConnection() const descriptionLink = proposal?.account.descriptionLink const allowDiscussion = realmInfo?.allowDiscussion ?? true const isMulti = proposal?.account.voteType !== VoteType.SINGLE_CHOICE && proposal?.account.accountType === GovernanceAccountType.ProposalV2 + const [openCalendarModal, setOpenCalendarModal] = useState(false) const [description, setDescription] = useState('') const voteData = useProposalVotes(proposal?.account) const currentWallet = useWalletOnePointOh() @@ -72,6 +81,10 @@ const Proposal = () => { } }, [descriptionLink]) + const proposedBy = + proposal && + tor?.account.governingTokenOwner.toBase58() + const { fmtUrlWithCluster } = useQueryContext() const showTokenBalance = proposal ? proposal.account.state === ProposalState.Draft || @@ -84,8 +97,21 @@ const Proposal = () => { proposal.account.state === ProposalState.Executing || proposal.account.state === ProposalState.ExecutingWithErrors) + const votingTimeEnds = + proposal?.account.signingOffAt && + governance && + proposal.account.signingOffAt.toNumber() + + governance.account.config.baseVotingTime + + const coolOffTimeEnds = + proposal?.account.signingOffAt && + governance && + proposal.account.signingOffAt.toNumber() + + governance.account.config.baseVotingTime + + governance.account.config.votingCoolOffTime + return ( -
+ {description && ( @@ -148,7 +184,69 @@ const Proposal = () => {
{proposal?.account.state === ProposalState.Voting ? (
-

Voting Now

+

+ Voting Now + setOpenCalendarModal(true)} + className="w-5" + > + {openCalendarModal && ( + setOpenCalendarModal(false)} + isOpen={openCalendarModal} + > +
+

Remind me about voting time end

+ {votingTimeEnds && ( + + )} +
+ {governance?.account.config.votingCoolOffTime && ( +
+

Remind me about cool off time end

+ {coolOffTimeEnds && ( + + )} +
+ )} +
+ )} +

) : ( diff --git a/pages/dao/[symbol]/proposal/components/GovernedAccountSelect.tsx b/pages/dao/[symbol]/proposal/components/GovernedAccountSelect.tsx index 5a3838537a..9f8e714480 100644 --- a/pages/dao/[symbol]/proposal/components/GovernedAccountSelect.tsx +++ b/pages/dao/[symbol]/proposal/components/GovernedAccountSelect.tsx @@ -71,7 +71,7 @@ const GovernedAccountSelect = ({ label?: string noMaxWidth?: boolean autoSelectFirst?: boolean - type?: 'mint' | 'token' | 'wallet' + type?: 'mint' | 'token' | 'wallet' | 'program' }) => { const realm = useRealm() const treasuryInfo = useTreasuryInfo(false) @@ -93,10 +93,13 @@ const GovernedAccountSelect = ({ { account: AssetAccount info: - | ReturnType - | ReturnType + | ReturnType + | ReturnType }[] >([]) + const [programs, setPrograms] = useState< + AssetAccount[] + >([]) const programId = realm.realmInfo?.programId useEffect(() => { @@ -118,6 +121,11 @@ const GovernedAccountSelect = ({ : getTokenAccountLabelInfo(account), })) ) + setPrograms( + governedAccounts + .filter((account) => account.type === AccountType.PROGRAM) + ) + if (programId) { const governances = new Set([]) @@ -137,8 +145,8 @@ const GovernedAccountSelect = ({ x.extensions.transferAddress?.equals(walletAddress) ) ? governedAccounts.find((x) => - x.extensions.transferAddress?.equals(walletAddress) - )! + x.extensions.transferAddress?.equals(walletAddress) + )! : account, governance: account.governance.pubkey, walletAddress, @@ -176,14 +184,14 @@ const GovernedAccountSelect = ({ const name = value.isSol ? getSolAccountLabel(value).tokenAccountName : value.isToken - ? getTokenAccountLabelInfo(value).tokenAccountName - : getMintAccountLabelInfo(value).mintAccountName + ? getTokenAccountLabelInfo(value).tokenAccountName + : getMintAccountLabelInfo(value).mintAccountName const accountName = name ? name : getAccountName(wallet.walletAddress) const walletInfo = RE.isOk(treasuryInfo) ? treasuryInfo.data.wallets.find( - (wallet) => - wallet.governanceAddress === value.governance.pubkey.toBase58() - ) + (wallet) => + wallet.governanceAddress === value.governance.pubkey.toBase58() + ) : null return ( @@ -235,25 +243,11 @@ const GovernedAccountSelect = ({ return null } - const wallet = wallets.find(({ account }) => - account.pubkey.equals(value.pubkey) - ) - - if (!wallet) { - return null - } - - const accountName = value.isSol - ? getSolAccountLabel(value).tokenAccountName - : value.isToken - ? getTokenAccountLabelInfo(value).tokenAccountName - : getMintAccountLabelInfo(value).mintAccountName - const walletInfo = RE.isOk(treasuryInfo) ? treasuryInfo.data.wallets.find( - (wallet) => - wallet.governanceAddress === value.governance.pubkey.toBase58() - ) + (wallet) => + wallet.governanceAddress === value.governance.pubkey.toBase58() + ) : null const programName = getAccountName(value.pubkey) @@ -264,20 +258,13 @@ const GovernedAccountSelect = ({
- {accountName ? ( -
{accountName}
- ) : ( -
- {abbreviateAddress(wallet.walletAddress)} -
- )} -
-
Rules: {abbreviateAddress(value.governance.pubkey)}
+
+ Program:{' '} + {programName ? programName : abbreviateAddress(value.pubkey)}
- Program:{' '} - {programName ? programName : abbreviateAddress(value.pubkey)} +
Rules: {abbreviateAddress(value.governance.pubkey)}
{walletInfo ? ( @@ -364,9 +351,9 @@ const GovernedAccountSelect = ({ const walletInfo = RE.isOk(treasuryInfo) ? treasuryInfo.data.wallets.find( - (wallet) => - wallet.governanceAddress === value.governance.pubkey.toBase58() - ) + (wallet) => + wallet.governanceAddress === value.governance.pubkey.toBase58() + ) : null const mintInfo = walletInfo?.assets.find( @@ -433,9 +420,9 @@ const GovernedAccountSelect = ({ const walletInfo = RE.isOk(treasuryInfo) ? treasuryInfo.data.wallets.find( - (wallet) => - wallet.governanceAddress === value?.governance.pubkey.toBase58() - ) + (wallet) => + wallet.governanceAddress === value?.governance.pubkey.toBase58() + ) : null return ( @@ -447,10 +434,10 @@ const GovernedAccountSelect = ({ type === 'token' ? getTokenView(value) : type === 'mint' - ? getMintView(value) - : value?.type === AccountType.PROGRAM - ? getProgramView(value, true) - : getWalletView(value, true) + ? getMintView(value) + : type === 'program' + ? getProgramView(value, true) + : getWalletView(value, true) } placeholder="Please select..." value={value?.pubkey} @@ -459,33 +446,33 @@ const GovernedAccountSelect = ({ > {type === 'token' ? tokens - .filter((token) => - !shouldBeGoverned - ? !shouldBeGoverned - : token.account?.governance?.pubkey.toBase58() === - governance?.pubkey?.toBase58() - ) - .map((token) => { - const label = getTokenView(token.account) - - return label ? ( - - {label} - - ) : null - }) - .filter(exists) + .filter((token) => + !shouldBeGoverned + ? !shouldBeGoverned + : token.account?.governance?.pubkey.toBase58() === + governance?.pubkey?.toBase58() + ) + .map((token) => { + const label = getTokenView(token.account) + + return label ? ( + + {label} + + ) : null + }) + .filter(exists) : type === 'mint' - ? mints + ? mints .filter((mint) => !shouldBeGoverned ? !shouldBeGoverned : mint.account?.governance?.pubkey.toBase58() === - governance?.pubkey?.toBase58() + governance?.pubkey?.toBase58() ) .map((mint) => { const label = getMintView(mint.account) @@ -501,30 +488,50 @@ const GovernedAccountSelect = ({ ) : null }) .filter(exists) - : wallets - .filter((wallet) => - !shouldBeGoverned - ? !shouldBeGoverned - : wallet.account?.governance?.pubkey.toBase58() === - governance?.pubkey?.toBase58() - ) - .map((wallet) => { - const label = - wallet.account.type === AccountType.PROGRAM - ? getProgramView(wallet.account) - : getWalletView(wallet.account) + : type === 'program' ? - return label ? ( - - {label} - - ) : null - }) - .filter(exists)} + programs + .filter((program) => + !shouldBeGoverned + ? !shouldBeGoverned + : program.governance?.pubkey.toBase58() === + governance?.pubkey?.toBase58() + ) + .map((program) => { + const label = getProgramView(program) + + return label ? ( + + {label} + + ) : null + }) + .filter(exists) + : wallets + .filter((wallet) => + !shouldBeGoverned + ? !shouldBeGoverned + : wallet.account?.governance?.pubkey.toBase58() === + governance?.pubkey?.toBase58() + ) + .map((wallet) => { + const label = getWalletView(wallet.account) + + return label ? ( + + {label} + + ) : null + }) + .filter(exists)} {value && walletInfo && (
diff --git a/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx b/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx index 590eadaa19..022deb0494 100644 --- a/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx +++ b/pages/dao/[symbol]/proposal/components/MyProposalsBtn.tsx @@ -2,6 +2,7 @@ import useRealm from '@hooks/useRealm' import { useCallback, useEffect, useMemo, useState } from 'react' import { getProposalDepositsByDepositPayer, + getVoteRecord, getVoteRecordAddress, ProgramAccount, Proposal, @@ -19,11 +20,8 @@ import useGovernanceAssets from '@hooks/useGovernanceAssets' import dayjs from 'dayjs' import { notify } from '@utils/notifications' import Loading from '@components/Loading' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' import { chunks } from '@utils/helpers' import { sendSignedTransaction } from '@utils/send' -import { getRegistrarPDA, getVoterWeightRecord } from '@utils/plugin/accounts' import { sendTransactionsV3, SequenceType, @@ -53,6 +51,8 @@ import { import queryClient from '@hooks/queries/queryClient' import { getFeeEstimate } from '@tools/feeEstimate' import { createComputeBudgetIx } from '@blockworks-foundation/mango-v4' +import {useVotingClients} from "@hooks/useVotingClients"; +import {useNftClient} from "../../../../../VoterWeightPlugins/useNftClient"; const MyProposalsBn = () => { const [modalIsOpen, setModalIsOpen] = useState(false) @@ -85,9 +85,9 @@ const MyProposalsBn = () => { const programVersion = useProgramVersion() ?? DEFAULT_GOVERNANCE_PROGRAM_VERSION - const client = useVotePluginsClientStore( - (s) => s.state.currentRealmVotingClient - ) + const votingClients = useVotingClients(); + const { nftClient } = useNftClient(); + const [ proposalsWithDepositedTokens, setProposalsWithDepositedTokens, @@ -237,20 +237,44 @@ const MyProposalsBn = () => { instructions, proposal: ProgramAccount ) => { - const voterTokenRecord = + let voterTokenRecord = proposal.account.governingTokenMint.toBase58() === realm?.account.communityMint.toBase58() ? ownTokenRecord : ownCouncilTokenRecord + const role = proposal.account.governingTokenMint.toBase58() === + realm?.account.communityMint.toBase58() + ? 'community' + : 'council' const governanceAuthority = wallet!.publicKey! const beneficiary = wallet!.publicKey! - const voteRecordPk = await getVoteRecordAddress( + let voteRecordPk = await getVoteRecordAddress( realm!.owner, proposal.pubkey, voterTokenRecord!.pubkey ) + + let governingTokenMint = proposal.account.governingTokenMint + + try { + await getVoteRecord(connection, voteRecordPk) + } catch { + voterTokenRecord = role === "community" ? + ownCouncilTokenRecord : + ownTokenRecord + + voteRecordPk = await getVoteRecordAddress( + realm!.owner, + proposal.pubkey, + voterTokenRecord!.pubkey + ) + governingTokenMint = role === "community" && realm?.account.config.councilMint ? + realm.account.config.councilMint : + realm?.account.communityMint! + } + const inst = await withRelinquishVote( instructions, realm!.owner, @@ -259,12 +283,12 @@ const MyProposalsBn = () => { proposal.account.governance, proposal.pubkey, voterTokenRecord!.pubkey, - proposal.account.governingTokenMint, + governingTokenMint, voteRecordPk, governanceAuthority, beneficiary ) - await client.withRelinquishVote( + await votingClients(role).withRelinquishVote( instructions, proposal, voteRecordPk, @@ -305,19 +329,12 @@ const MyProposalsBn = () => { if (!realm) throw new Error() if (!wallet?.publicKey) throw new Error('no wallet') + if (!nftClient) throw new Error('no nft client') + setIsLoading(true) const instructions: TransactionInstruction[] = [] - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - client.client!.program.programId - ) - const { voterWeightPk } = await getVoterWeightRecord( - realm!.pubkey, - realm!.account.communityMint, - wallet!.publicKey!, - client.client!.program.programId - ) + const { registrar } = nftClient.getRegistrarPDA(realm.pubkey, realm.account.communityMint); + const { voterWeightPk } = await nftClient.getVoterWeightRecordPDA(realm.pubkey, realm.account.communityMint, wallet.publicKey); const nfts = ownNftVoteRecordsFilterd.slice( 0, @@ -327,7 +344,7 @@ const MyProposalsBn = () => { const proposal = proposals.find((p) => p.pubkey.equals(i.account.proposal) ) - const relinquishNftVoteIx = await (client.client as NftVoterClient).program.methods + const relinquishNftVoteIx = await nftClient.program.methods .relinquishNftVote() .accounts({ registrar, @@ -370,7 +387,7 @@ const MyProposalsBn = () => { } const getNftsVoteRecord = useCallback(async () => { - const nftClient = client.client as NftVoterClient + if (!nftClient) throw new Error('no nft client'); const nftVoteRecords = await nftClient.program.account.nftVoteRecord.all([ { memcmp: { @@ -392,7 +409,7 @@ const MyProposalsBn = () => { ) }) setOwnNftVoteRecords(nftVoteRecordsFiltered) - }, [client.client, proposals, realm?.account.communityMint, wallet]) + }, [nftClient, proposals, realm?.account.communityMint, wallet]) const releaseSol = async () => { const instructions: TransactionInstruction[] = [] @@ -453,11 +470,11 @@ const MyProposalsBn = () => { wallet?.publicKey, ]) useEffect(() => { - if (wallet?.publicKey && isNftMode && client.client && modalIsOpen) { + if (wallet?.publicKey && isNftMode && nftClient && modalIsOpen) { getNftsVoteRecord() } }, [ - client.client, + nftClient, getNftsVoteRecord, isNftMode, modalIsOpen, diff --git a/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx b/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx index eaa945cdf5..5c1e0bbf93 100644 --- a/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx +++ b/pages/dao/[symbol]/proposal/components/NewProposalBtn.tsx @@ -2,12 +2,10 @@ import Link from 'next/link' import { PlusCircleIcon } from '@heroicons/react/outline' import useQueryContext from '@hooks/useQueryContext' import useRealm from '@hooks/useRealm' -import { useMemo } from 'react' import Tooltip from '@components/Tooltip' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' -import { useRealmGovernancesQuery } from '@hooks/queries/governance' -import { useLegacyVoterWeight } from '@hooks/queries/governancePower' +import { useRealmVoterWeightPlugins } from '@hooks/useRealmVoterWeightPlugins' const NewProposalBtn = () => { const { fmtUrlWithCluster } = useQueryContext() @@ -16,32 +14,35 @@ const NewProposalBtn = () => { const connected = !!wallet?.connected const realm = useRealmQuery().data?.result - const { result: ownVoterWeight } = useLegacyVoterWeight() + // const { result: ownVoterWeight } = useLegacyVoterWeight() + const { + ownVoterWeight: communityOwnVoterWeight, + } = useRealmVoterWeightPlugins('community') + const { + isReady, + ownVoterWeight: councilOwnVoterWeight, + } = useRealmVoterWeightPlugins('council') const { symbol, toManyCommunityOutstandingProposalsForUser, toManyCouncilOutstandingProposalsForUse, } = useRealm() - const governancesQuery = useRealmGovernancesQuery() - const governanceItems = useMemo(() => governancesQuery.data ?? [], [ - governancesQuery.data, - ]) + const hasVotingPower = + (communityOwnVoterWeight && communityOwnVoterWeight.value?.gtn(0)) || + (councilOwnVoterWeight && councilOwnVoterWeight.value?.gtn(0)) + const canCreateProposal = realm && - governanceItems.some((g) => - ownVoterWeight?.canCreateProposal(g.account.config) - ) && + hasVotingPower && !toManyCommunityOutstandingProposalsForUser && !toManyCouncilOutstandingProposalsForUse const tooltipContent = !connected ? 'Connect your wallet to create new proposal' - : governanceItems.length === 0 + : isReady && !communityOwnVoterWeight && !councilOwnVoterWeight ? 'There is no governance configuration to create a new proposal' - : !governanceItems.some((g) => - ownVoterWeight?.canCreateProposal(g.account.config) - ) + : !hasVotingPower ? "You don't have enough governance power to create a new proposal" : toManyCommunityOutstandingProposalsForUser ? 'Too many community outstanding proposals. You need to finalize them before creating a new one.' diff --git a/pages/dao/[symbol]/proposal/components/instructions/BurnTokens.tsx b/pages/dao/[symbol]/proposal/components/instructions/BurnTokens.tsx new file mode 100644 index 0000000000..565bd6927d --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/BurnTokens.tsx @@ -0,0 +1,149 @@ +import React, { useContext, useEffect, useState } from 'react' +import Input from '@components/inputs/Input' +import { getMintMinAmountAsDecimal, parseMintNaturalAmountFromDecimal } from '@tools/sdk/units' +import { precision } from '@utils/formatting' +import { + BurnTokensForm, + UiInstruction, +} from '@utils/uiTypes/proposalCreationTypes' +import { NewProposalContext } from '../../new' +import { getBurnTokensSchema } from '@utils/validations' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance, serializeInstructionToBase64 } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import GovernedAccountSelect from '../GovernedAccountSelect' +import { TOKEN_PROGRAM_ID, Token, u64} from "@solana/spl-token" +import { validateInstruction } from '@utils/instructionTools' + +const BurnTokens = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const { governedSPLTokenAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + amount: undefined, + governedTokenAccount: undefined, + mintInfo: undefined, + }) + const [governedAccount, setGovernedAccount] = useState< + ProgramAccount | undefined + >(undefined) + const [formErrors, setFormErrors] = useState({}) + const mintMinAmount = form.mintInfo + ? getMintMinAmountAsDecimal(form.mintInfo) + : 1 + const currentPrecision = precision(mintMinAmount) + const { handleSetInstructions } = useContext(NewProposalContext) + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + const setMintInfo = (value) => { + setForm({ ...form, mintInfo: value }) + } + const setAmount = (event) => { + const value = event.target.value + handleSetForm({ + value: value, + propertyName: 'amount', + }) + } + const validateAmountOnBlur = () => { + const value = form.amount + + handleSetForm({ + value: parseFloat( + Math.max( + Number(mintMinAmount), + Math.min(Number(Number.MAX_SAFE_INTEGER), Number(value)) + ).toFixed(currentPrecision) + ), + propertyName: 'amount', + }) + } + + async function getInstruction(): Promise { + const isValid = await validateInstruction({ schema, form, setFormErrors }) + let serializedInstruction = '' + + if (form.amount && isValid && form.governedTokenAccount) { + const mintPK = form.governedTokenAccount.extensions.mint!.publicKey + const tokenAccount = form.governedTokenAccount.extensions.transferAddress! + const sourceWallet = form.governedTokenAccount.extensions.token!.account.owner + + const burnAmount = parseMintNaturalAmountFromDecimal( + form.amount!, + form.governedTokenAccount.extensions.mint!.account.decimals + ) + + const burnIx = Token.createBurnInstruction( + TOKEN_PROGRAM_ID, + mintPK, + tokenAccount, + sourceWallet, + [], + new u64(burnAmount.toString()) + ) + + serializedInstruction = serializeInstructionToBase64(burnIx) + } + + return { + serializedInstruction, + isValid, + governance: form.governedTokenAccount?.governance, + chunkBy: 4 + } + } + + useEffect(() => { + handleSetInstructions( + { governedAccount: governedAccount, 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]) + + useEffect(() => { + setGovernedAccount(form.governedTokenAccount?.governance) + setMintInfo(form.governedTokenAccount?.extensions.mint?.account) + // 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.governedTokenAccount]) + + + const schema = getBurnTokensSchema({ form }) + + return ( + <> + { + handleSetForm({ value, propertyName: 'governedTokenAccount' }) + }} + value={form.governedTokenAccount} + error={formErrors['governedTokenAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type="token" + > + + + ) +} + +export default BurnTokens diff --git a/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx b/pages/dao/[symbol]/proposal/components/instructions/DistrubtionProgram/FillVaults.tsx index fed05758a5..b548b3f82d 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 = 134 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 { - inputProps, - effector, - governedAccountSelect, - wallet, - } = commonAssets( - { categoryId: '', marketListId: '' }, - index, - governance - ) - async function ixCreator(form: ForesightMakeAddMarketListToCategoryParams) { - const { ix } = await foresightGov.genAddMarketListToCategoryIx( - Buffer.from(form.categoryId.padEnd(20)), - Buffer.from(form.marketListId.padEnd(20)), - wallet!.publicKey! - ) - return ix - } - effector(ixCreator) - - return ( - <> - {governedAccountSelect} - - - - ) -} - -export default MakeAddMarketListToCategoryParams diff --git a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitCategoryParams.tsx b/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitCategoryParams.tsx deleted file mode 100644 index 04003cf3da..0000000000 --- a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitCategoryParams.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import React from 'react' -import { ForesightHasCategoryId } from '@utils/uiTypes/proposalCreationTypes' -import { Governance } from '@solana/spl-governance' -import { ProgramAccount } from '@solana/spl-governance' -import { governance as foresightGov } from '@foresight-tmp/foresight-sdk' -import { commonAssets, ForesightCategoryIdInput } from '@utils/Foresight' - -const MakeInitCategoryParams = ({ - index, - governance, -}: { - index: number - governance: ProgramAccount | null -}) => { - const { - inputProps, - effector, - governedAccountSelect, - wallet, - } = commonAssets( - { categoryId: '' }, - index, - governance - ) - async function ixCreator(form: ForesightHasCategoryId) { - const { ix } = await foresightGov.genInitCategoryIx( - Buffer.from(form.categoryId.padEnd(20)), - wallet!.publicKey! - ) - return ix - } - effector(ixCreator) - return ( - <> - {governedAccountSelect} - - - ) -} - -export default MakeInitCategoryParams diff --git a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketListParams.tsx b/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketListParams.tsx deleted file mode 100644 index 158a268b51..0000000000 --- a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketListParams.tsx +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import React from 'react' -import { ForesightHasMarketListId } from '@utils/uiTypes/proposalCreationTypes' -import { Governance } from '@solana/spl-governance' -import { ProgramAccount } from '@solana/spl-governance' -import { governance as foresightGov } from '@foresight-tmp/foresight-sdk' -import { commonAssets, ForesightMarketListIdInput } from '@utils/Foresight' - -const MakeInitMarketListParams = ({ - index, - governance, -}: { - index: number - governance: ProgramAccount | null -}) => { - const { - inputProps, - effector, - governedAccountSelect, - wallet, - } = commonAssets( - { marketListId: '' }, - index, - governance - ) - async function ixCreator(form: ForesightHasMarketListId) { - const { ix } = await foresightGov.genInitMarketListIx( - Buffer.from(form.marketListId.padEnd(20)), - wallet!.publicKey!, - form.governedAccount.extensions.transferAddress! - ) - return ix - } - effector(ixCreator) - - return ( - <> - {governedAccountSelect} - - - ) -} - -export default MakeInitMarketListParams diff --git a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketParams.tsx b/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketParams.tsx deleted file mode 100644 index c7a5386b3e..0000000000 --- a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeInitMarketParams.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import React from 'react' -import { ForesightHasMarketId } from '@utils/uiTypes/proposalCreationTypes' -import { Governance } from '@solana/spl-governance' -import { ProgramAccount } from '@solana/spl-governance' -import { governance as foresightGov, utils } from '@foresight-tmp/foresight-sdk' -import { - commonAssets, - ForesightMarketIdInput, - ForesightMarketListIdInput, -} from '@utils/Foresight' - -const MakeInitMarketParams = ({ - index, - governance, -}: { - index: number - governance: ProgramAccount | null -}) => { - const { - inputProps, - effector, - governedAccountSelect, - wallet, - } = commonAssets( - { marketListId: '', marketId: 0 }, - index, - governance - ) - async function ixCreator(form: ForesightHasMarketId) { - const { ix } = await foresightGov.genInitMarketIx( - Buffer.from(form.marketListId.padEnd(20)), - utils.intToArray(form.marketId, 1), - wallet!.publicKey! - ) - return ix - } - effector(ixCreator) - - return ( - <> - {governedAccountSelect} - - - - ) -} - -export default MakeInitMarketParams diff --git a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeResolveMarketParams.tsx b/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeResolveMarketParams.tsx deleted file mode 100644 index 928e5850b1..0000000000 --- a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeResolveMarketParams.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import React from 'react' -import { ForesightMakeResolveMarketParams } from '@utils/uiTypes/proposalCreationTypes' -import { Governance } from '@solana/spl-governance' -import { ProgramAccount } from '@solana/spl-governance' -import { governance as foresightGov, utils } from '@foresight-tmp/foresight-sdk' -import { - commonAssets, - ForesightMarketIdInput, - ForesightMarketListIdInput, - ForesightWinnerInput, -} from '@utils/Foresight' - -const MakeResolveMarketParams = ({ - index, - governance, -}: { - index: number - governance: ProgramAccount | null -}) => { - const { - inputProps, - effector, - governedAccountSelect, - } = commonAssets( - { marketListId: '', marketId: 0, winner: 0 }, - index, - governance - ) - async function ixCreator(form: ForesightMakeResolveMarketParams) { - const ix = await foresightGov.genResolveMarketIx( - form.winner, - utils.intToArray(form.marketId, 1), - Buffer.from(form.marketListId.padEnd(20)), - form.governedAccount.extensions.transferAddress! - ) - return ix - } - effector(ixCreator) - - return ( - <> - {governedAccountSelect} - - - - - ) -} - -export default MakeResolveMarketParams diff --git a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeSetMarketMetadataParams.tsx b/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeSetMarketMetadataParams.tsx deleted file mode 100644 index 4c5bfb82d4..0000000000 --- a/pages/dao/[symbol]/proposal/components/instructions/Foresight/MakeSetMarketMetadataParams.tsx +++ /dev/null @@ -1,64 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import React from 'react' -import { ForesightMakeSetMarketMetadataParams } from '@utils/uiTypes/proposalCreationTypes' -import { Governance } from '@solana/spl-governance' -import { ProgramAccount } from '@solana/spl-governance' -import { - governance as foresightGov, - consts as foresightConsts, - utils, -} from '@foresight-tmp/foresight-sdk' -import { - commonAssets, - ForesightContentInput, - ForesightMarketIdInput, - ForesightMarketListIdInput, - ForesightMarketMetadataFieldSelect, -} from '@utils/Foresight' - -export default function MakeSetMarketMetadataParams({ - index, - governance, -}: { - index: number - governance: ProgramAccount | null -}) { - const { - inputProps, - effector, - governedAccountSelect, - wallet, - } = commonAssets( - { - marketListId: '', - marketId: 0, - content: '', - field: Object.keys( - foresightConsts.MARKET_METADATA_FIELDS - )[0] as foresightConsts.MarketMetadataFieldName, - }, - index, - governance - ) - async function ixCreator(form: ForesightMakeSetMarketMetadataParams) { - const field = foresightConsts.MARKET_METADATA_FIELDS[form.field] - const { ix } = await foresightGov.genWriteToFieldMarketMetadataIx( - utils.intToArray(form.marketId, 1), - Buffer.from(form.marketListId.padEnd(20)), - form.content, - new field(), - wallet!.publicKey! - ) - return ix - } - effector(ixCreator) - return ( - <> - {governedAccountSelect} - - - - - - ) -} diff --git a/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/ConfigureGateway.tsx b/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/ConfigureGateway.tsx index d107261b44..88fc857508 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/ConfigureGateway.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/ConfigureGateway.tsx @@ -8,7 +8,6 @@ import { import { validateInstruction } from '@utils/instructionTools' import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { NewProposalContext } from '../../../new' import InstructionForm, { InstructionInput } from '../FormCreator' import { InstructionInputType } from '../inputInstructionType' @@ -18,7 +17,8 @@ import useGovernanceAssets from '@hooks/useGovernanceAssets' import { AssetAccount } from '@utils/uiTypes/assets' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' -import {configureCivicRegistrarIx} from "@utils/plugin/gateway"; +import {configureCivicRegistrarIx} from "../../../../../../../GatewayPlugin/sdk/api"; +import {useGatewayVoterWeightPlugin} from "../../../../../../../VoterWeightPlugins"; interface ConfigureGatewayForm { governedAccount: AssetAccount | undefined @@ -35,13 +35,13 @@ const ConfigureGatewayPlugin = ({ governance: ProgramAccount | null }) => { const realm = useRealmQuery().data?.result - const gatewayClient = useVotePluginsClientStore((s) => s.state.gatewayClient) const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) const [form, setForm] = useState() const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) + const { gatewayClient } = useGatewayVoterWeightPlugin(); const chosenGatekeeperNetwork = useMemo(() => { return form?.otherGatekeeperNetwork || form?.gatekeeperNetwork @@ -53,11 +53,12 @@ const ConfigureGatewayPlugin = ({ if ( isValid && form!.governedAccount?.governance?.account && - wallet?.publicKey + wallet?.publicKey && + realm && gatewayClient ) { const configureRegistrarTx = await configureCivicRegistrarIx( - realm!, - gatewayClient!, + realm, + gatewayClient, chosenGatekeeperNetwork!, ) serializedInstruction = serializeInstructionToBase64(configureRegistrarTx) @@ -80,24 +81,25 @@ const ConfigureGatewayPlugin = ({ .object() .nullable() .required('Governed account is required'), - collection: yup + gatekeeperNetwork: yup .string() .test( 'accountTests', - 'Collection address validation error', + 'Gatekeeper network address validation error', function (val: string) { + console.log('val', val) if (val) { try { return !!getValidatedPublickKey(val) } catch (e) { - console.log(e) + console.log("error with " + val, e) return this.createError({ message: `${e}`, }) } } else { return this.createError({ - message: `Collection address is required`, + message: `Gatekeeper network address is required`, }) } } diff --git a/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/CreateRegistrar.tsx b/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/CreateRegistrar.tsx index b9d4eafb29..51650cd634 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/CreateRegistrar.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/GatewayPlugin/CreateRegistrar.tsx @@ -8,7 +8,6 @@ import { import { validateInstruction } from '@utils/instructionTools' import { NameValue, UiInstruction } from '@utils/uiTypes/proposalCreationTypes' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { NewProposalContext } from '../../../new' import InstructionForm, { InstructionInput } from '../FormCreator' import { InstructionInputType } from '../inputInstructionType' @@ -20,7 +19,8 @@ import Tooltip from '@components/Tooltip' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' import {availablePasses} from "../../../../../../../GatewayPlugin/config"; -import {createCivicRegistrarIx} from "@utils/plugin/gateway"; +import {createCivicRegistrarIx} from "../../../../../../../GatewayPlugin/sdk/api"; +import {useGatewayVoterWeightPlugin} from "../../../../../../../VoterWeightPlugins"; interface CreateGatewayRegistrarForm { governedAccount: AssetAccount | undefined @@ -37,7 +37,7 @@ const CreateGatewayPluginRegistrar = ({ governance: ProgramAccount | null }) => { const realm = useRealmQuery().data?.result - const gatewayClient = useVotePluginsClientStore((s) => s.state.gatewayClient) + const { gatewayClient } = useGatewayVoterWeightPlugin(); const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) @@ -59,12 +59,12 @@ const CreateGatewayPluginRegistrar = ({ if ( isValid && form!.governedAccount?.governance?.account && - wallet?.publicKey + wallet?.publicKey && realm && gatewayClient ) { const createRegistrarIx = await createCivicRegistrarIx( - realm!, - wallet.publicKey!, - gatewayClient!, + realm, + wallet.publicKey, + gatewayClient, chosenGatekeeperNetwork!, ) serializedInstruction = serializeInstructionToBase64(createRegistrarIx) 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() @@ -326,13 +353,27 @@ const EditToken = ({ getNullOrTransform(values.maintWeightShiftLiabTarget, null, Number), values.maintWeightShiftAbort!, values.setFallbackOracle!, - getNullOrTransform(values.depositLimit, BN) + getNullOrTransform( + values.depositLimit !== null && values.depositLimit !== undefined + ? values.depositLimit?.toString() + : null, + BN + ), + getNullOrTransform(values.zeroUtilRate, null, Number), + getNullOrTransform(values.platformLiquidationFee, null, Number), + values.disableAssetLiquidation!, + getNullOrTransform(values.collateralFeePerDay, null, Number), + values.forceWithdraw!, + getNullOrTransform(values.tier, null, String) ) .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) + : PublicKey.default, }) .remainingAccounts([ { @@ -387,13 +428,18 @@ 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 - + console.log(currentToken.tier) const vals = { oraclePk: currentToken.oracle.toBase58(), + fallbackOracle: currentToken.fallbackOracle.toBase58(), oracleConfFilter: currentToken.oracleConfig.confFilter.toNumber(), maxStalenessSlots: currentToken.oracleConfig.maxStalenessSlots.toNumber(), mintPk: currentToken.mint.toBase58(), @@ -437,7 +483,12 @@ const EditToken = ({ maintWeightShiftEnd: currentToken.maintWeightShiftEnd.toNumber(), maintWeightShiftAssetTarget: currentToken.maintWeightShiftAssetTarget.toNumber(), maintWeightShiftLiabTarget: currentToken.maintWeightShiftLiabTarget.toNumber(), - depositLimit: currentToken.depositLimit.toNumber(), + depositLimit: currentToken.depositLimit.toString(), + zeroUtilRate: currentToken.zeroUtilRate.toNumber(), + platformLiquidationFee: currentToken.platformLiquidationFee.toNumber(), + collateralFeePerDay: currentToken.collateralFeePerDay, + disableAssetLiquidation: !currentToken.allowAssetLiquidation, + tier: currentToken.tier, } setForm((prevForm) => ({ ...prevForm, @@ -503,6 +554,19 @@ const EditToken = ({ type: InstructionInputType.INPUT, name: 'oraclePk', }, + { + label: keyToLabel['fallbackOracle'], + initialValue: form.fallbackOracle, + type: InstructionInputType.INPUT, + name: 'fallbackOracle', + }, + { + label: keyToLabel['setFallbackOracle'], + subtitle: getAdditionalLabelInfo('setFallbackOracle'), + initialValue: form.setFallbackOracle, + type: InstructionInputType.SWITCH, + name: 'setFallbackOracle', + }, { label: keyToLabel['oracleConfFilter'], subtitle: getAdditionalLabelInfo('oracleConfFilter'), @@ -808,13 +872,6 @@ const EditToken = ({ 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'), @@ -823,10 +880,58 @@ const EditToken = ({ 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', + }, + { + label: keyToLabel['tier'], + subtitle: getAdditionalLabelInfo('tier'), + initialValue: form.tier, + type: InstructionInputType.INPUT, + name: 'tier', + }, ] 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) => @@ -129,7 +138,8 @@ const GroupEdit = ({ values.allowedFastListingsPerInterval, null, Number - ) + ), + getNullOrTransform(values.collateralFeeInterval, BN) ) .accounts({ group: mangoGroup!.publicKey, @@ -204,6 +214,7 @@ const GroupEdit = ({ feesExpiryInterval: mangoGroup!.buybackFeesExpiryInterval?.toNumber(), allowedFastListingsPerInterval: mangoGroup! .allowedFastListingsPerInterval, + collateralFeeInterval: mangoGroup!.collateralFeeInterval.toNumber(), } setForm((prevForm) => ({ ...prevForm, @@ -324,10 +335,21 @@ const GroupEdit = ({ inputType: 'number', name: 'allowedFastListingsPerInterval', }, + { + label: keyToLabel['collateralFeeInterval'], + subtitle: getAdditionalLabelInfo('collateralFeeInterval'), + initialValue: form.collateralFeeInterval, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'collateralFeeInterval', + }, ] 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) => @@ -118,6 +124,10 @@ const IxGateSet = ({ TokenConditionalSwapCreatePremiumAuction: true, TokenConditionalSwapCreateLinearAuction: true, Serum3PlaceOrderV2: true, + TokenForceWithdraw: true, + SequenceCheck: true, + HealthCheck: true, + GroupChangeInsuranceFund: true, }) const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) @@ -634,10 +644,37 @@ const IxGateSet = ({ type: InstructionInputType.SWITCH, name: 'Serum3PlaceOrderV2', }, + { + label: 'Token Force withdraw', + initialValue: form.TokenForceWithdraw, + type: InstructionInputType.SWITCH, + name: 'TokenForceWithdraw', + }, + { + label: 'Sequence Check', + initialValue: form.SequenceCheck, + type: InstructionInputType.SWITCH, + name: 'SequenceCheck', + }, + { + label: 'Health Check', + initialValue: form.HealthCheck, + type: InstructionInputType.SWITCH, + name: 'HealthCheck', + }, + { + label: 'Group Change Insurance Fund', + initialValue: form.GroupChangeInsuranceFund, + type: InstructionInputType.SWITCH, + name: 'GroupChangeInsuranceFund', + }, ] 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( @@ -213,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) => @@ -109,6 +116,7 @@ const PerpCreate = ({ settlePnlLimitWindowSize: 60 * 60, positivePnlLiquidationFee: 0, holdupTime: 0, + platformLiquidationFee: 0, }) const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) @@ -203,7 +211,8 @@ const PerpCreate = ({ Number(form.settleTokenIndex), Number(form.settlePnlLimitFactor), new BN(form.settlePnlLimitWindowSize), - Number(form.positivePnlLiquidationFee) + Number(form.positivePnlLiquidationFee), + Number(form.platformLiquidationFee) ) .accounts({ group: mangoGroup!.publicKey, @@ -513,9 +522,20 @@ const PerpCreate = ({ inputType: 'number', name: 'positivePnlLiquidationFee', }, + { + label: `Platform Liquidation Fee`, + subtitle: getAdditionalLabelInfo('platformLiquidationFee'), + initialValue: form.platformLiquidationFee, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'platformLiquidationFee', + }, ] 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 [perps, setPerps] = useState([]) const [forcedValues, setForcedValues] = useState([]) @@ -240,7 +249,8 @@ const PerpEdit = ({ values.resetStablePrice!, getNullOrTransform(values.positivePnlLiquidationFee, null, Number), getNullOrTransform(values.name, null, String), - values.forceClose! + values.forceClose!, + getNullOrTransform(values.platformLiquidationFee, null, Number) ) .accounts({ group: mangoGroup!.publicKey, @@ -305,7 +315,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 )! @@ -587,6 +601,14 @@ const PerpEdit = ({ 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'), @@ -618,6 +640,9 @@ const PerpEdit = ({ ] 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) => @@ -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( @@ -89,6 +97,7 @@ const TokenRegister = ({ 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, @@ -122,6 +131,11 @@ const TokenRegister = ({ interestTargetUtilization: 0.5, interestCurveScaling: 4, insuranceFound: false, + zeroUtilRate: 0, + platformLiquidationFee: 0, + disableAssetLiquidation: false, + collateralFeePerDay: 0, + tier: '', }) const [formErrors, setFormErrors] = useState({}) const { handleSetInstructions } = useContext(NewProposalContext) @@ -134,7 +148,6 @@ const TokenRegister = ({ async function getInstruction(): Promise { const isValid = await validateInstruction() let serializedInstruction = '' - const additionalSerializedInstructions: string[] = [] if ( isValid && form.governedAccount?.governance?.account && @@ -181,7 +194,12 @@ const TokenRegister = ({ Number(form.interestCurveScaling), Number(form.interestTargetUtilization), form.insuranceFound, - new BN(form.depositLimit) + new BN(form.depositLimit), + Number(form.zeroUtilRate), + Number(form.platformLiquidationFee), + form.disableAssetLiquidation, + Number(form.collateralFeePerDay), + form.tier ) .accounts({ group: mangoGroup!.publicKey, @@ -190,30 +208,10 @@ const TokenRegister = ({ oracle: new PublicKey(form.oraclePk), payer: form.governedAccount.extensions.transferAddress, rent: SYSVAR_RENT_PUBKEY, + fallbackOracle: new PublicKey(form.fallbackOracle), }) .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) ) @@ -299,6 +297,12 @@ const TokenRegister = ({ type: InstructionInputType.INPUT, name: 'oraclePk', }, + { + label: `Fallback oracle`, + initialValue: form.fallbackOracle, + type: InstructionInputType.INPUT, + name: 'fallbackOracle', + }, { label: `Oracle Confidence Filter`, subtitle: getAdditionalLabelInfo('confFilter'), @@ -559,10 +563,50 @@ const TokenRegister = ({ 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', + }, + { + label: 'Token Tier', + initialValue: form.tier, + type: InstructionInputType.INPUT, + name: 'tier', + }, ] 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 { 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 realm = useRealmQuery().data?.result const mint = useRealmCommunityMintInfoQuery().data?.result - const nftClient = useVotePluginsClientStore((s) => s.state.nftClient) + const {nftClient} = useNftClient() const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) @@ -60,10 +60,10 @@ const ConfigureNftPluginCollection = ({ form!.weight, mint!.decimals ) - const { registrar } = await getRegistrarPDA( - realm!.pubkey, - realm!.account.communityMint, - nftClient!.program.programId + const { registrar } = getRegistrarPDA( + realm!.pubkey, + realm!.account.communityMint, + nftClient!.program.programId ) const { maxVoterWeightRecord } = await getMaxVoterWeightRecord( realm!.pubkey, diff --git a/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateMaxVoterWeightRecord.tsx b/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateMaxVoterWeightRecord.tsx index eadc95f85f..ed211d575f 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateMaxVoterWeightRecord.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateMaxVoterWeightRecord.tsx @@ -10,7 +10,6 @@ import { validateInstruction } from '@utils/instructionTools' import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' import useRealm from '@hooks/useRealm' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { NewProposalContext } from '../../../new' import InstructionForm, { InstructionInput } from '../FormCreator' import { InstructionInputType } from '../inputInstructionType' @@ -19,6 +18,7 @@ import { AssetAccount } from '@utils/uiTypes/assets' import useGovernanceAssets from '@hooks/useGovernanceAssets' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' +import {useNftClient} from "../../../../../../../VoterWeightPlugins/useNftClient"; interface CreateNftMaxVoterWeightRecord { governedAccount: AssetAccount | undefined @@ -34,7 +34,7 @@ const CreateNftPluginMaxVoterWeightRecord = ({ const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const nftClient = useVotePluginsClientStore((s) => s.state.nftClient) + const {nftClient} = useNftClient() const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) diff --git a/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateRegistrar.tsx b/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateRegistrar.tsx index df85ca4b6f..e94f0cd113 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateRegistrar.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/NftVotingPlugin/CreateRegistrar.tsx @@ -10,7 +10,6 @@ import { validateInstruction } from '@utils/instructionTools' import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' import useRealm from '@hooks/useRealm' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { NewProposalContext } from '../../../new' import InstructionForm from '../FormCreator' import { InstructionInputType } from '../inputInstructionType' @@ -19,6 +18,7 @@ import useGovernanceAssets from '@hooks/useGovernanceAssets' import { getRegistrarPDA } from '@utils/plugin/accounts' import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { useRealmQuery } from '@hooks/queries/realm' +import {useNftClient} from "../../../../../../../VoterWeightPlugins/useNftClient"; interface CreateNftRegistrarForm { governedAccount: AssetAccount | undefined @@ -35,7 +35,7 @@ const CreateNftPluginRegistrar = ({ const realm = useRealmQuery().data?.result const { realmInfo } = useRealm() - const nftClient = useVotePluginsClientStore((s) => s.state.nftClient) + const {nftClient} = useNftClient() const { assetAccounts } = useGovernanceAssets() const wallet = useWalletOnePointOh() const shouldBeGoverned = !!(index !== 0 && governance) @@ -50,7 +50,7 @@ const CreateNftPluginRegistrar = ({ form!.governedAccount?.governance?.account && wallet?.publicKey ) { - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realm!.pubkey, realm!.account.communityMint, nftClient!.program.programId diff --git a/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythRecoverAccount.tsx b/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythRecoverAccount.tsx new file mode 100644 index 0000000000..2ddcac791a --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythRecoverAccount.tsx @@ -0,0 +1,138 @@ +import { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' +import { isFormValid, validatePubkey } from '@utils/formValidation' +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import { serializeInstructionToBase64 } from '@solana/spl-governance' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import InstructionForm, { InstructionInput } from '../FormCreator' +import { InstructionInputType } from '../inputInstructionType' +import { NewProposalContext } from '../../../new' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { PublicKey } from '@solana/web3.js' +import { AssetAccount } from '@utils/uiTypes/assets' +import { PythStakingClient } from '@pythnetwork/staking-sdk' + +export interface PythRecoverAccountForm { + governedAccount: AssetAccount | null + stakeAccount: string +} + +const PythRecoverAccount = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const { assetAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + stakeAccount: '', + }) + 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() + + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const pythClient = new PythStakingClient({ + connection: connection.current, + }) + + const stakeAccountPublicKey = new PublicKey(form.stakeAccount) + const instruction = await pythClient.getRecoverAccountInstruction( + stakeAccountPublicKey, + form.governedAccount.governance.pubkey + ) + + return { + serializedInstruction: serializeInstructionToBase64(instruction), + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } else { + return { + serializedInstruction: '', + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } + } + + 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'), + stakeAccount: yup + .string() + .required('Stake is required') + .test( + 'is-stake-account-valid', + 'Invalid Stake Account', + function (val: string) { + return val ? validatePubkey(val) : true + } + ), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: assetAccounts, + }, + { + label: 'Stake Account', + initialValue: form.stakeAccount, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'stakeAccount', + }, + ] + + return ( + <> + {form && ( + + )} + + ) +} + +export default PythRecoverAccount diff --git a/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythUpdatePoolAuthority.tsx b/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythUpdatePoolAuthority.tsx new file mode 100644 index 0000000000..6a050cfc68 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Pyth/PythUpdatePoolAuthority.tsx @@ -0,0 +1,146 @@ +import { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' +import { isFormValid, validatePubkey } from '@utils/formValidation' +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import { serializeInstructionToBase64 } from '@solana/spl-governance' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import InstructionForm, { InstructionInput } from '../FormCreator' +import { InstructionInputType } from '../inputInstructionType' +import { NewProposalContext } from '../../../new' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { PublicKey, TransactionInstruction } from '@solana/web3.js' +import { AssetAccount } from '@utils/uiTypes/assets' +import { PythStakingClient, getConfigAddress } from '@pythnetwork/staking-sdk' + +export interface PythUpdatePoolAuthorityForm { + governedAccount: AssetAccount | null + poolAuthority: string +} + +const INSTRUCTION_DISCRIMINATOR = new Uint8Array([160, 162, 113, 9, 99, 187, 23, 239]); + +const PythUpdatePoolAuthority = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const { assetAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + poolAuthority: '', + }) + 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() + + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const pythClient = new PythStakingClient({ + connection: connection.current, + }) + + const [configAddress, _] = getConfigAddress(); + + const poolAuthorityPublicKey = new PublicKey(form.poolAuthority) + const instruction : TransactionInstruction = { + keys: [ + {pubkey : form.governedAccount.governance.pubkey, isSigner: true, isWritable: false}, + {pubkey : configAddress, isSigner: false, isWritable: true}, + ], + programId : pythClient.stakingProgram.programId, + data : Buffer.concat([INSTRUCTION_DISCRIMINATOR, poolAuthorityPublicKey.toBuffer()]) + } + + return { + serializedInstruction: serializeInstructionToBase64(instruction), + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } else { + return { + serializedInstruction: '', + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } + } + + 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'), + poolAuthority: yup + .string() + .required('Pool authority is required') + .test( + 'is-pool-authority-valid', + 'Invalid Pool Authority', + function (val: string) { + return val ? validatePubkey(val) : true + } + ), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: assetAccounts, + }, + { + label: 'Pool Authority', + initialValue: form.poolAuthority, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'poolAuthority', + }, + ] + + return ( + <> + {form && ( + + )} + + ) +} + +export default PythUpdatePoolAuthority diff --git a/pages/dao/[symbol]/proposal/components/instructions/Dual/DualVote.tsx b/pages/dao/[symbol]/proposal/components/instructions/SplGov/DaoVote.tsx similarity index 61% rename from pages/dao/[symbol]/proposal/components/instructions/Dual/DualVote.tsx rename to pages/dao/[symbol]/proposal/components/instructions/SplGov/DaoVote.tsx index 08b00d37cb..b83dd55386 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Dual/DualVote.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/SplGov/DaoVote.tsx @@ -9,7 +9,6 @@ import { Vote, withCastVote, serializeInstructionToBase64, - getProposal, getTokenOwnerRecordAddress, } from '@solana/spl-governance' import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' @@ -25,7 +24,7 @@ import Select from '@components/inputs/Select' import { isFormValid } from '@utils/formValidation' import * as yup from 'yup' import { Keypair, PublicKey, TransactionInstruction } from '@solana/web3.js' -import { DEFAULT_VSR_ID, VsrClient } from 'VoteStakeRegistry/sdk/client' +import { VsrClient } from 'VoteStakeRegistry/sdk/client' import { getRegistrarPDA, getVoterPDA, @@ -34,25 +33,39 @@ import { import { AnchorProvider } from '@coral-xyz/anchor' import EmptyWallet from '@utils/Mango/listingTools' import { fetchProgramVersion } from '@hooks/queries/useProgramVersionQuery' +import { fetchProposalByPubkeyQuery } from '@hooks/queries/proposal' +import { fetchGovernanceByPubkey } from '@hooks/queries/governance' +import { fetchRealmByPubkey } from '@hooks/queries/realm' +import { fetchRealmConfigQuery } from '@hooks/queries/realmConfig' +import { findPluginName } from '@constants/plugins' -type DualFinanceVoteForm = { - realm: string +type DaoVoteForm = { delegateToken: AssetAccount | undefined proposal: string - governanceProgram: string voteOption: 'Yes' | 'No' } +/* +const getVotingClient = async ( + connection: Connection, + realmPk: PublicKey, + governingTokenMint: PublicKey, + authority: PublicKey +) => { + 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 }) => { @@ -77,7 +87,6 @@ const DualVote = ({ .object() .nullable() .required('Program governed account is required'), - realm: yup.string().required(), proposal: yup.string().required(), voteOption: yup.string().required(), }), @@ -89,6 +98,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 +118,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 +160,52 @@ 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 } = getRegistrarPDA( + realmPk, + governingMint, + pluginPk + ) + const { voter } = getVoterPDA(registrar, walletPk, pluginPk) + voterWeightPk = 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 +224,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 +262,11 @@ const DualVote = ({ return obj } handleSetInstructions( - { governedAccount: governedAccount, getInstruction }, + { governedAccount: form.delegateToken?.governance, getInstruction }, index ) }, [ form, - governedAccount, handleSetInstructions, index, connection, @@ -218,26 +274,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']} - /> x.isSol)} + governedAccounts={assetAccounts.filter((x) => x.isToken)} onChange={(value) => { handleSetForm({ value, propertyName: 'delegateToken' }) }} @@ -283,4 +323,4 @@ const DualVote = ({ ) } -export default DualVote +export default DaoVote diff --git a/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshAddMember.tsx b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshAddMember.tsx new file mode 100644 index 0000000000..fe7f444466 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshAddMember.tsx @@ -0,0 +1,149 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' +import { isFormValid, validatePubkey } from '@utils/formValidation' +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import { serializeInstructionToBase64 } from '@solana/spl-governance' +import { MESH_PROGRAM_ID, MeshEditMemberForm } from './common' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import InstructionForm, { InstructionInput } from '../FormCreator' +import { InstructionInputType } from '../inputInstructionType' +import { NewProposalContext } from '../../../new' +import Squads from '@sqds/mesh' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { PublicKey } from '@solana/web3.js' +import { Wallet } from '@coral-xyz/anchor' + +const MeshAddMember = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const { assetAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + vault: '', + member: '', + }) + 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() + + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const squads = new Squads({ + connection: connection.current, + wallet: {} as Wallet, + multisigProgramId: MESH_PROGRAM_ID, + }) + const instruction = await squads.buildAddMember( + new PublicKey(form.vault), + form.governedAccount.governance.pubkey, + new PublicKey(form.member) + ) + return { + serializedInstruction: serializeInstructionToBase64(instruction), + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } else { + return { + serializedInstruction: '', + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } + } + + 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'), + vault: yup + .string() + .required('Vault is required') + .test('is-vault-valid', 'Invalid Vault Account', function (val: string) { + return val ? validatePubkey(val) : true + }), + member: yup + .string() + .required('Member is required') + .test( + 'is-member-valid', + 'Invalid Member Account', + function (val: string) { + return val ? validatePubkey(val) : true + } + ), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: assetAccounts, + }, + { + label: 'Vault', + initialValue: form.vault, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'vault', + }, + { + label: 'Member', + initialValue: form.member, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'member', + }, + ] + + return ( + <> + {form && ( + + )} + + ) +} + +export default MeshAddMember diff --git a/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshChangeThresholdMember.tsx b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshChangeThresholdMember.tsx new file mode 100644 index 0000000000..e4dbb5d739 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshChangeThresholdMember.tsx @@ -0,0 +1,156 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' +import { isFormValid, validatePubkey } from '@utils/formValidation' +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import { serializeInstructionToBase64 } from '@solana/spl-governance' +import { MESH_PROGRAM_ID } from './common' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import InstructionForm, { InstructionInput } from '../FormCreator' +import { InstructionInputType } from '../inputInstructionType' +import { NewProposalContext } from '../../../new' +import Squads from '@sqds/mesh' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { PublicKey } from '@solana/web3.js' +import { Wallet } from '@coral-xyz/anchor' +import { AssetAccount } from '@utils/uiTypes/assets' + +export interface MeshChangeThresholdMemberForm { + governedAccount: AssetAccount | null + vault: string + newThreshold: number +} + +const MeshChangeThresholdMember = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const { assetAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + vault: '', + newThreshold: 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() + + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const squads = new Squads({ + connection: connection.current, + wallet: {} as Wallet, + multisigProgramId: MESH_PROGRAM_ID, + }) + const instruction = await squads.buildChangeThresholdMember( + new PublicKey(form.vault), + form.governedAccount.governance.pubkey, + form.newThreshold + ) + return { + serializedInstruction: serializeInstructionToBase64(instruction), + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } else { + return { + serializedInstruction: '', + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } + } + + 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'), + vault: yup + .string() + .required('Vault is required') + .test('is-vault-valid', 'Invalid Vault Account', function (val: string) { + return val ? validatePubkey(val) : true + }), + newThreshold: yup + .number() + .required('New threshold is required') + .test( + 'is-threshold-valid', + "New threshold can't be 0", + function (val: number) { + return val > 0 + } + ), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: assetAccounts, + }, + { + label: 'Vault', + initialValue: form.vault, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'vault', + }, + { + label: 'New threshold', + initialValue: form.newThreshold, + type: InstructionInputType.INPUT, + inputType: 'number', + name: 'newThreshold', + }, + ] + + return ( + <> + {form && ( + + )} + + ) +} + +export default MeshChangeThresholdMember diff --git a/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshRemoveMember.tsx b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshRemoveMember.tsx new file mode 100644 index 0000000000..e858b7d020 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Squads/MeshRemoveMember.tsx @@ -0,0 +1,149 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' +import { isFormValid, validatePubkey } from '@utils/formValidation' +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import { Governance } from '@solana/spl-governance' +import { ProgramAccount } from '@solana/spl-governance' +import { serializeInstructionToBase64 } from '@solana/spl-governance' +import { MESH_PROGRAM_ID, MeshEditMemberForm } from './common' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import InstructionForm, { InstructionInput } from '../FormCreator' +import { InstructionInputType } from '../inputInstructionType' +import { NewProposalContext } from '../../../new' +import Squads from '@sqds/mesh' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { PublicKey } from '@solana/web3.js' +import { Wallet } from '@coral-xyz/anchor' + +const MeshRemoveMember = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const { assetAccounts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedAccount: null, + vault: '', + member: '', + }) + 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() + + if ( + isValid && + form.governedAccount?.governance?.account && + wallet?.publicKey + ) { + const squads = new Squads({ + connection: connection.current, + wallet: {} as Wallet, + multisigProgramId: MESH_PROGRAM_ID, + }) + const instruction = await squads.buildRemoveMember( + new PublicKey(form.vault), + form.governedAccount.governance.pubkey, + new PublicKey(form.member) + ) + return { + serializedInstruction: serializeInstructionToBase64(instruction), + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } else { + return { + serializedInstruction: '', + isValid, + governance: form.governedAccount?.governance, + chunkBy: 1, + } + } + } + + 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'), + vault: yup + .string() + .required('Vault is required') + .test('is-vault-valid', 'Invalid Vault Account', function (val: string) { + return val ? validatePubkey(val) : true + }), + member: yup + .string() + .required('Member is required') + .test( + 'is-member-valid', + 'Invalid Member Account', + function (val: string) { + return val ? validatePubkey(val) : true + } + ), + }) + const inputs: InstructionInput[] = [ + { + label: 'Governance', + initialValue: form.governedAccount, + name: 'governedAccount', + type: InstructionInputType.GOVERNED_ACCOUNT, + shouldBeGoverned: shouldBeGoverned as any, + governance: governance, + options: assetAccounts, + }, + { + label: 'Vault', + initialValue: form.vault, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'vault', + }, + { + label: 'Member', + initialValue: form.member, + type: InstructionInputType.INPUT, + inputType: 'text', + name: 'member', + }, + ] + + return ( + <> + {form && ( + + )} + + ) +} + +export default MeshRemoveMember diff --git a/pages/dao/[symbol]/proposal/components/instructions/Squads/common.ts b/pages/dao/[symbol]/proposal/components/instructions/Squads/common.ts new file mode 100644 index 0000000000..5ea0b04468 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Squads/common.ts @@ -0,0 +1,12 @@ +import { PublicKey } from '@solana/web3.js' +import { AssetAccount } from '@utils/uiTypes/assets' + +export const MESH_PROGRAM_ID = new PublicKey( + 'SMPLVC8MxZ5Bf5EfF7PaMiTCxoBAcmkbM2vkrvMK8ho' +) + +export interface MeshEditMemberForm { + governedAccount: AssetAccount | null + vault: string + member: string +} diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/AddTokenToBasketModal.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/AddTokenToBasketModal.tsx new file mode 100644 index 0000000000..3460856022 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/AddTokenToBasketModal.tsx @@ -0,0 +1,73 @@ +import Modal from "@components/Modal" +import Input from "@components/inputs/Input" +import { useEffect, useState } from "react" + + +const AddTokenToBasketModal = ({ + open, + onClose, + supportedTokens, + onSelect +}:{ + open: boolean, + onClose: any, + supportedTokens: any, + onSelect: any +}) => { + const [allTokens, setAllTokens] = useState(supportedTokens); + const [searchValue, setSearchValue] = useState(''); + + useEffect(() => { + if(searchValue.length > 0){ + const filteredTokens = supportedTokens.filter((token: any) => { + return token.name.toLowerCase().includes(searchValue.toLowerCase()) || token.symbol.toLowerCase().includes(searchValue.toLowerCase()) + }) + setAllTokens(filteredTokens) + } else { + setAllTokens(supportedTokens) + } + + }, [searchValue, supportedTokens]) + return <> + { + open && + onClose()} + > +

Select a Token

+ setSearchValue(e.target.value)} type="text" /> +
+ + } + + +} + +export default AddTokenToBasketModal; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx new file mode 100644 index 0000000000..16a1b34999 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryCreateBasket.tsx @@ -0,0 +1,346 @@ +import { ProgramAccount, Governance, serializeInstructionToBase64 } from '@solana/spl-governance' +import { SymmetryCreateBasketForm, UiInstruction } from '@utils/uiTypes/proposalCreationTypes'; +import { useContext, useEffect, useState } from 'react'; +import Tooltip from '@components/Tooltip' +import Input from '@components/inputs/Input' +import { NewProposalContext } from '../../../new'; +import Switch from '@components/Switch'; +import { BasketsSDK } from "@symmetry-hq/baskets-sdk"; +import { createBasketIx } from "@symmetry-hq/baskets-sdk/dist/basketInstructions"; +import { useConnection } from '@solana/wallet-adapter-react'; +import Button from '@components/Button'; +import AddTokenToBasketModal from './AddTokenToBasketModal'; +import { TrashCan } from '@carbon/icons-react'; +import { PublicKey } from '@solana/web3.js'; +import { LinkIcon } from '@heroicons/react/solid'; +import useGovernanceAssets from '@hooks/useGovernanceAssets'; +import GovernedAccountSelect from '../../GovernedAccountSelect'; + +const SymmetryCreateBasket = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount +}) => { + const {connection} = useConnection(); + const { assetAccounts } = useGovernanceAssets() + const [form, setForm] = useState({ + basketName: "", + basketSymbol: "", + basketMetadataUrl: "", + basketType: 2, + basketComposition: [], + rebalanceThreshold: 1000, + rebalanceSlippageTolerance: 50, + depositFee: 10, + feeCollectorAddress: "", + liquidityProvision: false, + liquidityProvisionRange: 0, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + const shouldBeGoverned = !!(index !== 0 && governance) + const [supportedTokens, setSupportedTokens] = useState(null); + const [addTokenModal, setAddTokenModal] = useState(false); + + + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + useEffect(() => { + BasketsSDK.init(connection).then((sdk) => { + setSupportedTokens(sdk.getTokenListData()); + }); + }, []); + + 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]) + + async function getInstruction(): Promise { + + const basketParams = { + name: form.basketName, + symbol: form.basketSymbol, + uri: form.basketMetadataUrl, + hostPlatform: new PublicKey('4Vry5hGDmbwGwhjgegHmoitjMHniSotpjBFkRuDYHcDG'), + hostPlatformFee: 10, + //@ts-ignore + manager: form.governedAccount?.extensions.transferAddress, + managerFee: form.depositFee, + activelyManaged: 1, + rebalanceInterval: 3600, + rebalanceThreshold: form.rebalanceThreshold, + rebalanceSlippage: form.rebalanceSlippageTolerance, + lpOffsetThreshold: 0, + disableRebalance: false, + disableLp: !form.liquidityProvision, + composition: form.basketComposition.map((token) => { + return { + token: token.token, + weight: token.weight, + } + }), + feeDelegate: new PublicKey(form.feeCollectorAddress) + } + //@ts-ignore + const ix = await createBasketIx(connection, basketParams) + return { + serializedInstruction: serializeInstructionToBase64(ix), + isValid: true, + governance: form.governedAccount?.governance + }; + } + return ( + <> + +

Allow anyone to Deposit

+ handleSetForm({ value: x ? 2 : 1, propertyName: 'basketType' })}/> +
+ + handleSetForm({ + value: evt.target.value, + propertyName: 'basketName', + }) + } + error={formErrors['basketName']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'basketSymbol', + }) + } + error={formErrors['basketSymbol']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'basketMetadataUrl', + }) + } + error={formErrors['basketMetadataUrl']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'depositFee', + }) + } + error={formErrors['depositFee']} + /> + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'feeCollectorAddress', + }) + } + error={formErrors['feeCollectorAddress']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'rebalanceSlippageTolerance', + }) + } + error={formErrors['rebalanceSlippageTolerance']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'rebalanceThreshold', + }) + } + error={formErrors['rebalanceThreshold']} + /> +
+

Enable Passive Rebalancing

+

Plugs into DEX Aggregators to passively allow for favorable swaps that keep the composition rebalanced. + Earns Extra Yield. +

+ handleSetForm({ value: x, propertyName: 'liquidityProvision' })}/> +
+
+

Basket Composition

+
+
+

Token

+

Mint Address

+

Token Weight

+

Actions

+
+ { form.basketComposition.length > 0 ? + form.basketComposition.map((token, i) => { + return ( +
+
+

+ { + token.name + } +

+

+ { + token.symbol + } +

+
+
+

+ { + token.token.toBase58().slice(0,6) + '...' + token.token.toBase58().slice(-6) + } +

+ + + +
+
+ { + const newComposition = form.basketComposition; + newComposition[i].weight = parseFloat(evt.target.value); + setForm({ + ...form, + basketComposition: newComposition + }); + } + } + /> +
+
+ { + const newComposition = form.basketComposition; + newComposition.splice(i, 1); + setForm({ + ...form, + basketComposition: newComposition + }); + }} + /> +
+
+ ) + }) + : +

Composition Empty. Add tokens below

+ } +
+ { + form.basketComposition.length < 15 && supportedTokens && ( + + ) + } + { + addTokenModal && + setAddTokenModal(false)} + supportedTokens={supportedTokens} + onSelect={(token) => { + if(form.basketComposition.find((t) => t.token.toBase58() === token.tokenMint) + || form.basketComposition.length >= 15) { + return; + } + + setForm({ + ...form, + basketComposition: [ + ...form.basketComposition, + { + name: token.name, + symbol: token.symbol, + token: new PublicKey(token.tokenMint), + weight: 0, + } + ] + }); + setAddTokenModal(false); + }} + /> + } + +
+ { + form.governedAccount && +
+ + + + + +

+ Make sure {form.governedAccount?.pubkey.toBase58()} has at least 0.22 SOL, which will required to deploy the basket after the proposal passes. +

+
+ } + + ) +} + +export default SymmetryCreateBasket; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx new file mode 100644 index 0000000000..208f3a0697 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryDeposit.tsx @@ -0,0 +1,186 @@ +import { ProgramAccount, Governance, serializeInstructionToBase64 } from '@solana/spl-governance' +import { SymmetryDepositForm, UiInstruction } from '@utils/uiTypes/proposalCreationTypes'; +import { useContext, useEffect, useState } from 'react'; +import Input from '@components/inputs/Input' +import { NewProposalContext } from '../../../new'; +import { BasketsSDK, FilterOption } from "@symmetry-hq/baskets-sdk"; +import { buyBasketIx } from "@symmetry-hq/baskets-sdk/dist/basketInstructions"; +import ArrowButton from './components/ArrowButton'; +import { useConnection } from '@solana/wallet-adapter-react'; +import { PublicKey } from '@solana/web3.js'; +import useGovernanceAssets from '@hooks/useGovernanceAssets'; +import Select from '@components/inputs/Select'; +import GovernedAccountSelect from '../../GovernedAccountSelect'; +import { LoaderIcon } from './SymmetryEditBasket'; + +const SymmetryDeposit = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount +}) => { + const {connection} = useConnection(); + const { assetAccounts } = useGovernanceAssets(); + const [basketsSdk, setBasketSdk] = useState(undefined); + const [form, setForm] = useState({ + governedAccount: undefined, + basketAddress: undefined, + depositToken: undefined, + depositAmount: 0, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext); + const [managedBaskets, setManagedBaskets] = useState(undefined); + const shouldBeGoverned = !!(index !== 0 && governance) + const [assetAccountsLoaded, setAssetAccountsLoaded] = useState(false); + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + useEffect(() => { + if(assetAccounts && assetAccounts.length > 0 && !assetAccountsLoaded) + setAssetAccountsLoaded(true); + }, [assetAccounts]); + + useEffect(() => { + if(form.governedAccount) { + const basketsOwnerAccounts: FilterOption[] = [{ + filterType: 'manager', + filterPubkey: form.governedAccount.pubkey + } + ] + BasketsSDK.init(connection).then((sdk) => { + setBasketSdk(sdk); + sdk.findBaskets(basketsOwnerAccounts).then((baskets) => { + sdk.getCurrentCompositions(baskets).then((compositions) => { + const basketAccounts:any[] = []; + baskets.map((basket, i) => { + + basketAccounts.push({ + governedAccount: assetAccounts.filter(x => x.pubkey.toBase58() === basket.data.manager.toBase58())[0], + basket: basket, + composition: compositions[i] + }); + }); + setManagedBaskets(basketAccounts); + }); + }); + }); + } + }, [form.governedAccount]); + + 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]) + + async function getInstruction(): Promise { + const ix = await buyBasketIx( + connection, + //@ts-ignore + form.governedAccount?.governance.nativeTreasuryAddress, + form.basketAddress, + Number(form.depositAmount) + ) + + return { + serializedInstruction: serializeInstructionToBase64(ix), + isValid: true, + governance: form.governedAccount?.governance + }; + } + + return <> + { + assetAccountsLoaded ? + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + : +
+ +

Loading DAO Accounts

+
+ } + { + form.governedAccount && + (managedBaskets ? + + : +
+ +

Loading Baskets Managed by the Account

+
+ ) + } + { + form.basketAddress && +
+ } + { + form.governedAccount && form.basketAddress && + <> + x.extensions.mint?.publicKey.toBase58() === 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v')} /* Only allow USDC deposits for now */ + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='token' + /> + + handleSetForm({ propertyName: 'depositAmount', value: e.target.value })} + error={formErrors['depositAmount']} + /> + + } + +} + +export default SymmetryDeposit; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx new file mode 100644 index 0000000000..82a4d0b314 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryEditBasket.tsx @@ -0,0 +1,415 @@ +import { ProgramAccount, Governance, serializeInstructionToBase64 } from '@solana/spl-governance' +import { SymmetryEditBasketForm, UiInstruction } from '@utils/uiTypes/proposalCreationTypes'; +import { useContext, useEffect, useState } from 'react'; +import Tooltip from '@components/Tooltip' +import Input from '@components/inputs/Input' +import { NewProposalContext } from '../../../new'; +import Switch from '@components/Switch'; +import { BasketsSDK, FilterOption } from "@symmetry-hq/baskets-sdk"; +import { editBasketIx } from "@symmetry-hq/baskets-sdk/dist/basketInstructions"; +import { useConnection } from '@solana/wallet-adapter-react'; +import Button from '@components/Button'; +import AddTokenToBasketModal from './AddTokenToBasketModal'; +import { TrashCan } from '@carbon/icons-react'; +import { PublicKey } from '@solana/web3.js'; +import { LinkIcon } from '@heroicons/react/solid'; +import useGovernanceAssets from '@hooks/useGovernanceAssets'; +import Select from '@components/inputs/Select'; +import GovernedAccountSelect from '../../GovernedAccountSelect'; +import ArrowButton from './components/ArrowButton'; + + +export const LoaderIcon = () => { + return
; +} + +const SymmetryEditBasket = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount +}) => { + const {connection} = useConnection(); + const { assetAccounts } = useGovernanceAssets() + const [form, setForm] = useState({ + + basketName: "", + basketSymbol: "", + basketMetadataUrl: "", + basketType: 2, + basketComposition: [], + rebalanceThreshold: 1000, + rebalanceSlippageTolerance: 50, + depositFee: 10, + feeCollectorAddress: "", + liquidityProvision: false, + liquidityProvisionRange: 0, + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext); + const [managedBaskets, setManagedBaskets] = useState(undefined); + const shouldBeGoverned = !!(index !== 0 && governance) + const [addTokenModal, setAddTokenModal] = useState(false); + const [supportedTokens, setSupportedTokens] = useState(null); + const [assetAccountsLoaded, setAssetAccountsLoaded] = useState(false); + const [govAccount, setGovAccount] = useState(undefined); + + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + const handleSelectBasket = (address: string) => { + const foundBasket = managedBaskets.filter(x => x.basket.ownAddress.toBase58() === address)[0] + if(!foundBasket) return; + const formData = { + governedAccount: foundBasket.governedAccount, + basketAddress: new PublicKey(address), + basketName: String.fromCharCode.apply(null, foundBasket.basket.data.name), + basketSymbol: String.fromCharCode.apply(null, foundBasket.basket.data.symbol), + basketMetadataUrl: String.fromCharCode.apply(null, foundBasket.basket.data.uri), + basketType: foundBasket.basket.data.activelyManaged.toNumber(), + basketComposition: foundBasket.composition.currentComposition.map((comp) => { + return { + name: comp.name, + symbol: comp.symbol, + token: new PublicKey(comp.mintAddress), + weight: comp.targetWeight + } + }), + rebalanceThreshold: foundBasket.basket.data.rebalanceThreshold.toNumber(), + rebalanceSlippageTolerance: foundBasket.basket.data.rebalanceSlippage.toNumber(), + depositFee: foundBasket.basket.data.managerFee.toNumber(), + feeCollectorAddress: foundBasket.basket.data.feeDelegate.toBase58(), + liquidityProvision: foundBasket.basket.data.disableLp.toNumber === 0, + liquidityProvisionRange: foundBasket.basket.data.lpOffsetThreshold.toNumber() + } + setForm(formData); + } + + useEffect(() => { + if(assetAccounts && assetAccounts.length > 0 && !assetAccountsLoaded) + setAssetAccountsLoaded(true); + }, [assetAccounts]); + + useEffect(() => { + if(form.governedAccount) { + console.log("govAcc", form.governedAccount); + const basketsOwnerAccounts: FilterOption[] = [{ + filterType: 'manager', + filterPubkey: form.governedAccount.pubkey + }] + if(basketsOwnerAccounts.length > 0) { + BasketsSDK.init(connection).then((sdk) => { + setSupportedTokens(sdk.getTokenListData()); + sdk.findBaskets(basketsOwnerAccounts).then((baskets) => { + sdk.getCurrentCompositions(baskets).then((compositions) => { + const basketAccounts:any[] = []; + baskets.map((basket, i) => { + + basketAccounts.push({ + governedAccount: assetAccounts.filter(x => x.pubkey.toBase58() === basket.data.manager.toBase58())[0], + basket: basket, + composition: compositions[i] + }); + }); + setManagedBaskets(basketAccounts); + }); + }); + }); + } + } + }, [form.governedAccount]); + + 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]) + + async function getInstruction(): Promise { + const basketParams = { + //@ts-ignore + managerFee: form.depositFee, + activelyManaged: form.basketType, + rebalanceInterval: 3600, + rebalanceThreshold: form.rebalanceThreshold, + rebalanceSlippage: form.rebalanceSlippageTolerance, + lpOffsetThreshold: 0, + disableRebalance: false, + disableLp: !form.liquidityProvision, + composition: form.basketComposition.map((token) => { + return { + token: token.token, + weight: token.weight, + } + }), + feeDelegate: new PublicKey(form.feeCollectorAddress) + } + //@ts-ignore + const ix = await editBasketIx(connection, form.basketAddress, basketParams) + + return { + serializedInstruction: serializeInstructionToBase64(ix), + isValid: true, + governance: form.governedAccount?.governance + }; + } + + return <> + { + assetAccountsLoaded ? + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + : +
+ +

Loading DAO Accounts

+
+ + } + { + form.governedAccount && + (managedBaskets ? + + : +
+ +

Loading Baskets Managed by the Account

+
) + } + + { + form.basketAddress && + <> +
+ + + +
+ +

Allow anyone to Deposit

+ handleSetForm({ value: x ? 1 : 2, propertyName: 'basketType' })}/> +
+ null} + error={formErrors['basketName']} + /> + null } + error={formErrors['basketSymbol']} + /> + null} + error={formErrors['basketMetadataUrl']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'depositFee', + }) + } + error={formErrors['depositFee']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'feeCollectorAddress', + }) + } + error={formErrors['feeCollectorAddress']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'rebalanceSlippageTolerance', + }) + } + error={formErrors['rebalanceSlippageTolerance']} + /> + + handleSetForm({ + value: evt.target.value, + propertyName: 'rebalanceThreshold', + }) + } + error={formErrors['rebalanceThreshold']} + /> +
+

Enable Passive Rebalancing

+

Plugs into DEX Aggregators to passively allow for favorable swaps that keep the composition rebalanced. + Earns Extra Yield. +

+ handleSetForm({ value: x, propertyName: 'liquidityProvision' })}/> +
+
+

Basket Composition

+
+
+

Token

+

Mint Address

+

Token Weight

+

Actions

+
+ { form.basketComposition.length > 0 ? + form.basketComposition.map((token, i) => { + return ( +
+
+

+ { + token.name + } +

+

+ { + token.symbol + } +

+
+
+

+ { + token.token.toBase58().slice(0,6) + '...' + token.token.toBase58().slice(-6) + } +

+ + + +
+
+ { + const newComposition = form.basketComposition; + newComposition[i].weight = parseFloat(evt.target.value); + setForm({ + ...form, + basketComposition: newComposition + }); + } + } + /> +
+
+ { + const newComposition = form.basketComposition; + newComposition.splice(i, 1); + setForm({ + ...form, + basketComposition: newComposition + }); + }} + /> +
+
+ ) + }) + : +

Composition Empty. Add tokens below

+ } +
+ { + form.basketComposition.length < 15 && supportedTokens && ( + + ) + } + { + addTokenModal && + setAddTokenModal(false)} + supportedTokens={supportedTokens} + onSelect={(token) => { + if(form.basketComposition.find((t) => t.token.toBase58() === token.tokenMint) + || form.basketComposition.length >= 15) { + return; + } + + setForm({ + ...form, + basketComposition: [ + ...form.basketComposition, + { + name: token.name, + symbol: token.symbol, + token: new PublicKey(token.tokenMint), + weight: 0, + } + ] + }); + setAddTokenModal(false); + }} + /> + } + +
+ + } + +} + +export default SymmetryEditBasket; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryWithdraw.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryWithdraw.tsx new file mode 100644 index 0000000000..6a10bea084 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/SymmetryWithdraw.tsx @@ -0,0 +1,237 @@ +import { ProgramAccount, Governance, serializeInstructionToBase64 } from '@solana/spl-governance' +import { SymmetryWithdrawForm, UiInstruction } from '@utils/uiTypes/proposalCreationTypes'; +import { useContext, useEffect, useState } from 'react'; +import Input from '@components/inputs/Input' +import { NewProposalContext } from '../../../new'; +import { BasketsSDK, FilterOption } from "@symmetry-hq/baskets-sdk"; +import { sellBasketIx } from "@symmetry-hq/baskets-sdk/dist/basketInstructions"; +import { useConnection } from '@solana/wallet-adapter-react'; +import useGovernanceAssets from '@hooks/useGovernanceAssets'; +import GovernedAccountSelect from '../../GovernedAccountSelect'; +import Select from '@components/inputs/Select'; +import { PublicKey } from '@solana/web3.js'; +import { LoaderIcon } from './SymmetryEditBasket'; +import ArrowButton from './components/ArrowButton'; + +const SymmetryWithdraw = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount +}) => { + const {connection} = useConnection(); + const { assetAccounts } = useGovernanceAssets(); + const [basketsSdk, setBasketSdk] = useState(undefined); + const [form, setForm] = useState({ + governedAccount: undefined, + basketAddress: undefined, + withdrawAmount: 0, + withdrawType: 3 + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext); + const [managedBaskets, setManagedBaskets] = useState(undefined); + const shouldBeGoverned = !!(index !== 0 && governance) + const [assetAccountsLoaded, setAssetAccountsLoaded] = useState(false); + const [selectedBasket, setSelectedBasket] = useState(undefined); + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + const handleSelectBasket = (basket: any) => { + handleSetForm({ propertyName: 'basketAddress', value: basket.basket.ownAddress }) + } + + useEffect(() => { + if(assetAccounts && assetAccounts.length > 0 && !assetAccountsLoaded) + setAssetAccountsLoaded(true); + }, [assetAccounts]); + + useEffect(() => { + if(form.governedAccount) { + const basketsOwnerAccounts: FilterOption[] = [{ + filterType: 'manager', + filterPubkey: form.governedAccount.pubkey + }] + BasketsSDK.init(connection).then((sdk) => { + setBasketSdk(sdk); + sdk.findBaskets(basketsOwnerAccounts).then((baskets) => { + sdk.getCurrentCompositions(baskets).then((compositions) => { + const basketAccounts:any[] = []; + baskets.map((basket, i) => { + + basketAccounts.push({ + governedAccount: assetAccounts.filter(x => x.pubkey.toBase58() === basket.data.manager.toBase58())[0], + basket: basket, + composition: compositions[i] + }); + }); + setManagedBaskets(basketAccounts); + }); + }); + }); + } + }, [form.governedAccount]); + + 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]) + + async function getInstruction(): Promise { + const ix = await sellBasketIx( + connection, + //@ts-ignore + form.governedAccount?.governance.nativeTreasuryAddress, + form.basketAddress, + Number(form.withdrawAmount), + form.withdrawType + ) + + return { + serializedInstruction: serializeInstructionToBase64(ix), + isValid: true, + governance: form.governedAccount?.governance + }; + } + + return <> + { + assetAccountsLoaded ? + x.isSol)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='wallet' + /> + : +
+ +

Loading DAO Accounts

+
+ } + { + form.governedAccount && + (managedBaskets ? + + : +
+ +

Loading Baskets Managed by the Account

+
+ ) + } + { + form.basketAddress && +
+ + + +
+ } + { + form.basketAddress && + x.isToken).filter(x => x.extensions.mint?.publicKey.toBase58() === selectedBasket?.composition?.basketTokenMint)} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedAccount' }) + }} + value={form.governedAccount} + error={formErrors['governedAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type='token' + /> + } + + { + form.basketAddress && form.governedAccount && + <> + handleSetForm({ propertyName: 'withdrawAmount', value: e.target.value })} + error={formErrors['withdrawAmount']} + /> + + + } + { + form.governedAccount && +
+ + + + + +

+ Make sure {form.governedAccount?.pubkey.toBase58()} has at least 0.08 SOL, which is required for a temporary withdrawal account, which will automatically be closed after completion & SOL will be refunded. +

+
+ } + +} + +export default SymmetryWithdraw; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx new file mode 100644 index 0000000000..1e39ed6cf4 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Symmetry/components/ArrowButton.tsx @@ -0,0 +1,37 @@ +import React from 'react'; + +const ArrowButton = ({ + title, + children=<> +}) => { + return ( + + ) +} + +export default ArrowButton; \ No newline at end of file diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumDepositStake.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumDepositStake.tsx new file mode 100644 index 0000000000..c5a3df4b0e --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumDepositStake.tsx @@ -0,0 +1,378 @@ +import React, { useContext, useEffect, useState } from 'react' + +import { + Governance, + ProgramAccount, + serializeInstructionToBase64, +} from '@solana/spl-governance' + +import { + PublicKey, + SYSVAR_CLOCK_PUBKEY, + StakeAuthorizationLayout, + StakeProgram, + TransactionInstruction, +} from '@solana/web3.js' + +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import { NewProposalContext } from '../../../new' +import { web3 } from '@coral-xyz/anchor' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import GovernedAccountSelect from '../../GovernedAccountSelect' +import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes' +import { AssetAccount, StakeAccount, StakeState } from '@utils/uiTypes/assets' +import StakeAccountSelect from '../../StakeAccountSelect' +import { getFilteredProgramAccounts } from '@utils/helpers' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { + StakePoolInstruction, + getStakePoolAccount, +} from '@solana/spl-stake-pool' +import Input from '@components/inputs/Input' +import { tryGetAta } from '@utils/validations' +import { + ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + Token, +} from '@solana/spl-token' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' + +type SanctumDepositStake = { + governedTokenAccount: AssetAccount | undefined + stakingAccount: StakeAccount | undefined + stakePool: string + voteAccount: string +} + +const SanctumDepositStake = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const stakeProgramId: PublicKey = StakeProgram.programId + const sanctumStakeProgramId = new PublicKey( + 'SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY' + ) + const { governedTokenAccountsWithoutNfts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + + const [form, setForm] = useState({ + stakingAccount: undefined, + governedTokenAccount: undefined, + stakePool: '', + voteAccount: '', + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + const [governedAccount, setGovernedAccount] = useState< + ProgramAccount | undefined + >(undefined) + + const setStakingAccount = (value) => { + handleSetForm({ + value: value, + propertyName: 'stakingAccount', + }) + } + const setStakePool = (value) => { + handleSetForm({ + value: value.target.value, + propertyName: 'stakePool', + }) + } + const setVoteAccount = (value) => { + handleSetForm({ + value: value.target.value, + propertyName: 'voteAccount', + }) + } + + const getStakeAccounts = async (): Promise => { + if (!form.governedTokenAccount) return [] + + const stakingAccounts = await getFilteredProgramAccounts( + connection.current, + stakeProgramId, + [ + { + memcmp: { + offset: 0, + bytes: bs58.encode([2, 0, 0, 0]), + }, + }, + { + memcmp: { + offset: 44, + bytes: form.governedTokenAccount.pubkey.toBase58(), + }, + }, + { + memcmp: { + offset: 172, + bytes: bs58.encode([255, 255, 255, 255, 255, 255, 255, 255]), // equivalent to u64::max for deactivation epoch / not deactivated yet + }, + }, + ] + ) + + return stakingAccounts.map((x) => { + const validatorPk = web3.PublicKey.decode( + x.accountInfo.data.slice(124, 124 + 32) + ) + return { + stakeAccount: x.publicKey, + state: StakeState.Active, + delegatedValidator: validatorPk as web3.PublicKey, + amount: x.accountInfo.lamports / web3.LAMPORTS_PER_SOL, + } + }) + } + + //getStakeAccounts().then(x => setStakeAccounts(x)) + + const [stakeAccounts, setStakeAccounts] = useState([]) + + const validateInstruction = async (): Promise => { + if (!form.governedTokenAccount) return false + + const stakingAccounts = await getStakeAccounts() + setStakeAccounts(stakingAccounts) + + if ( + !form.stakingAccount || + !form.stakingAccount.stakeAccount || + !form.stakingAccount.delegatedValidator + ) + return false + return true + } + + async function getInstruction(): Promise { + const isValid = await validateInstruction() + const returnInvalid = (): UiInstruction => { + return { + serializedInstruction: '', + isValid: false, + governance: undefined, + } + } + if ( + !connection || + !isValid || + !stakeProgramId || + !form.governedTokenAccount?.isSol || + !form.stakingAccount?.stakeAccount + ) { + console.log('Invalid form') + return returnInvalid() + } + + const prequsiteInstructions: TransactionInstruction[] = [] + + const stakePool = await getStakePoolAccount( + connection.current, + new PublicKey(form.stakePool) + ) + const ataAddress = await Token.getAssociatedTokenAddress( + ASSOCIATED_TOKEN_PROGRAM_ID, + TOKEN_PROGRAM_ID, + stakePool.account.data.poolMint, + form.governedTokenAccount.pubkey, + true + ) + const ataAccount = await tryGetAta( + connection.current, + stakePool.account.data.poolMint, + form.governedTokenAccount.pubkey + ) + + if (!ataAccount) { + prequsiteInstructions.push( + Token.createAssociatedTokenAccountInstruction( + ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID + TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID + stakePool.account.data.poolMint, // mint + ataAddress, // ata + form.governedTokenAccount.pubkey, // owner of token account + wallet!.publicKey! // fee payer + ) + ) + } + + const [withdrawAuthPk] = await PublicKey.findProgramAddress( + [new PublicKey(form.stakePool).toBuffer(), Buffer.from('withdraw')], + sanctumStakeProgramId + ) + const [validatorStake] = await PublicKey.findProgramAddress( + [ + new PublicKey(form.voteAccount).toBuffer(), + new PublicKey(form.stakePool).toBuffer(), + ], + sanctumStakeProgramId + ) + const authorizeWithdrawIx = StakeProgram.authorize({ + stakePubkey: form.stakingAccount.stakeAccount, + authorizedPubkey: form.governedTokenAccount.pubkey, + newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority, + stakeAuthorizationType: StakeAuthorizationLayout.Withdrawer, + }) + + const authorizeStakerIx = StakeProgram.authorize({ + stakePubkey: form.stakingAccount.stakeAccount, + authorizedPubkey: form.governedTokenAccount.pubkey, + newAuthorizedPubkey: stakePool.account.data.stakeDepositAuthority, + stakeAuthorizationType: StakeAuthorizationLayout.Staker, + }) + + const stakeIx = StakePoolInstruction.depositStake({ + stakePool: new PublicKey(form.stakePool), + validatorList: stakePool.account.data.validatorList, + depositAuthority: stakePool.account.data.stakeDepositAuthority, + reserveStake: stakePool.account.data.reserveStake, + managerFeeAccount: stakePool.account.data.managerFeeAccount, + referralPoolAccount: ataAddress, + destinationPoolAccount: ataAddress, + withdrawAuthority: withdrawAuthPk, + depositStake: form.stakingAccount.stakeAccount, + validatorStake: validatorStake, + poolMint: stakePool.account.data.poolMint, + }) + //don't need to be writable any more problems probably comes from old solana/web3.js version + const modifiedAuthorize1 = { + ...authorizeStakerIx.instructions[0], + keys: authorizeStakerIx.instructions[0].keys.map((x) => { + if (x.pubkey.equals(SYSVAR_CLOCK_PUBKEY)) { + return { + ...x, + isWritable: false, + } + } + return x + }), + } + //don't need to be writable any more problems probably comes from old solana/web3.js version + const modifiedAuthorize2 = { + ...authorizeWithdrawIx.instructions[0], + keys: authorizeWithdrawIx.instructions[0].keys.map((x) => { + if (x.pubkey.equals(SYSVAR_CLOCK_PUBKEY)) { + return { + ...x, + isWritable: false, + } + } + return x + }), + } + return { + prerequisiteInstructions: prequsiteInstructions, + serializedInstruction: '', + additionalSerializedInstructions: [ + serializeInstructionToBase64(modifiedAuthorize1), + serializeInstructionToBase64(modifiedAuthorize2), + serializeInstructionToBase64( + new TransactionInstruction({ + programId: sanctumStakeProgramId, + keys: stakeIx.keys, + data: stakeIx.data, + }) + ), + ], + isValid: true, + governance: form.governedTokenAccount.governance, + } + } + + useEffect(() => { + handleSetInstructions( + { + governedAccount: governedAccount, + 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]) + + useEffect(() => { + handleSetInstructions( + { governedAccount: governedAccount, 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]) + useEffect(() => { + setGovernedAccount(form.governedTokenAccount?.governance) + if (form.governedTokenAccount) { + getStakeAccounts().then((x) => setStakeAccounts(x)) + } + // 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.governedTokenAccount]) + + return ( + <> + x.isSol + )} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedTokenAccount' }) + }} + value={form.governedTokenAccount} + error={formErrors['governedTokenAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + > + + + + +
+ + ) +} + +export default SanctumDepositStake + +export function encodeData(type: any, fields?: any): Buffer { + const allocLength = type.layout.span + const data = Buffer.alloc(allocLength) + const layoutFields = Object.assign({ instruction: type.index }, fields) + type.layout.encode(layoutFields, data) + + return data +} diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumWithdrawStake.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumWithdrawStake.tsx new file mode 100644 index 0000000000..1234f5031f --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/SanctumWithdrawStake.tsx @@ -0,0 +1,311 @@ +import React, { useContext, useEffect, useState } from 'react' + +import { + Governance, + ProgramAccount, + serializeInstructionToBase64, +} from '@solana/spl-governance' + +import { + LAMPORTS_PER_SOL, + PublicKey, + StakeProgram, + SystemProgram, + TransactionInstruction, +} from '@solana/web3.js' + +import { UiInstruction } from '@utils/uiTypes/proposalCreationTypes' +import { NewProposalContext } from '../../../new' +import { BN } from '@coral-xyz/anchor' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import GovernedAccountSelect from '../../GovernedAccountSelect' +import { AssetAccount } from '@utils/uiTypes/assets' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { + StakePool, + StakePoolInstruction, + getStakePoolAccount, +} from '@solana/spl-stake-pool' +import Input from '@components/inputs/Input' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' +import { genShortestUnusedSeed } from '@utils/address' + +type SanctumWithdrawStakeForm = { + governedTokenAccount: AssetAccount | undefined + stakePool: string + voteAccount: string + amount: number +} + +const SanctumWithdrawStake = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const wallet = useWalletOnePointOh() + const connection = useLegacyConnectionContext() + const stakeProgramId: PublicKey = StakeProgram.programId + const sanctumStakeProgramId = new PublicKey( + 'SP12tWFxD9oJsVWNavTTBZvMbA6gkAmxtVgxdqvyvhY' + ) + const { governedTokenAccountsWithoutNfts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + + const [form, setForm] = useState({ + amount: 0, + governedTokenAccount: undefined, + stakePool: '9jWbABPXfc75wseAbLEkBCb1NRaX9EbJZJTDQnbtpzc1', + voteAccount: '5EYp3kCdMLq52vzZ4ucsVyYaaxQe5MKTquxahjXpcShS', + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + const [governedAccount, setGovernedAccount] = useState< + ProgramAccount | undefined + >(undefined) + const setStakePool = (value) => { + handleSetForm({ + value: value.target.value, + propertyName: 'stakePool', + }) + } + const setVoteAccount = (value) => { + handleSetForm({ + value: value.target.value, + propertyName: 'voteAccount', + }) + } + + const setAmount = (value) => { + handleSetForm({ + value: value.target.value, + propertyName: 'amount', + }) + } + + const validateInstruction = async (): Promise => { + if (!form.governedTokenAccount) return false + + return true + } + + async function getInstruction(): Promise { + const isValid = await validateInstruction() + const returnInvalid = (): UiInstruction => { + return { + serializedInstruction: '', + isValid: false, + governance: undefined, + } + } + if (!connection || !isValid || !stakeProgramId) { + console.log('Invalid form') + return returnInvalid() + } + + const stakePool = await getStakePoolAccount( + connection.current, + new PublicKey(form.stakePool) + ) + + const [withdrawAuthPk] = await PublicKey.findProgramAddress( + [new PublicKey(form.stakePool).toBuffer(), Buffer.from('withdraw')], + sanctumStakeProgramId + ) + + const poolAmount = Number(Number(form.amount) * LAMPORTS_PER_SOL) + + const stakeAccountRentExemption = await connection.current.getMinimumBalanceForRentExemption( + StakeProgram.space + ) + + const [stakeAccountAddress] = await PublicKey.findProgramAddress( + [ + new PublicKey(form.voteAccount).toBuffer(), + new PublicKey(form.stakePool).toBuffer(), + ], + sanctumStakeProgramId + ) + const stakeAccount = await connection.current.getAccountInfo( + stakeAccountAddress + ) + if (!stakeAccount) { + console.log('error') + throw new Error('Invalid Stake Account') + } + + const availableForWithdrawal = calcLamportsWithdrawAmount( + stakePool.account.data, + stakeAccount.lamports - LAMPORTS_PER_SOL - stakeAccountRentExemption + ) + + if (availableForWithdrawal < poolAmount) { + // noinspection ExceptionCaughtLocallyJS + throw new Error( + `Not enough lamports available for withdrawal from ${stakeAccountAddress}, + ${poolAmount} asked, ${availableForWithdrawal} available.` + ) + } + const tokenAccAuthority = form.governedTokenAccount!.extensions.token! + .account.owner! + const withdrawAccount = { + stakeAddress: stakeAccountAddress, + voteAddress: new PublicKey(form.voteAccount), + poolAmount, + } + + const stakeReceiver = await genShortestUnusedSeed( + connection.current, + tokenAccAuthority, + StakeProgram.programId + ) + + const createAccIx = SystemProgram.createAccountWithSeed({ + fromPubkey: wallet!.publicKey!, + newAccountPubkey: stakeReceiver.derived, + lamports: stakeAccountRentExemption, + space: StakeProgram.space, + programId: StakeProgram.programId, + seed: stakeReceiver.seed, + basePubkey: stakeReceiver.base, + }) + + const stakeIx = StakePoolInstruction.withdrawStake({ + stakePool: new PublicKey(form.stakePool), + validatorList: stakePool.account.data.validatorList, + validatorStake: withdrawAccount.stakeAddress, + destinationStake: stakeReceiver.derived, + destinationStakeAuthority: tokenAccAuthority, + sourceTransferAuthority: tokenAccAuthority, + sourcePoolAccount: form.governedTokenAccount!.extensions.token!.publicKey, + managerFeeAccount: stakePool.account.data.managerFeeAccount, + poolMint: stakePool.account.data.poolMint, + poolTokens: withdrawAccount.poolAmount, + withdrawAuthority: withdrawAuthPk, + }) + + return { + serializedInstruction: '', + additionalSerializedInstructions: [ + serializeInstructionToBase64(createAccIx), + serializeInstructionToBase64( + new TransactionInstruction({ + programId: sanctumStakeProgramId, + keys: stakeIx.keys, + data: stakeIx.data, + }) + ), + ], + isValid: true, + governance: form.governedTokenAccount!.governance, + } + } + + useEffect(() => { + handleSetInstructions( + { + governedAccount: governedAccount, + 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]) + + useEffect(() => { + handleSetInstructions( + { governedAccount: governedAccount, 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]) + useEffect(() => { + setGovernedAccount(form.governedTokenAccount?.governance) + // 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.governedTokenAccount]) + + return ( + <> + { + handleSetForm({ value, propertyName: 'governedTokenAccount' }) + }} + value={form.governedTokenAccount} + error={formErrors['governedTokenAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type="token" + > + + + +
+ + ) +} + +export default SanctumWithdrawStake + +export function encodeData(type: any, fields?: any): Buffer { + const allocLength = type.layout.span + const data = Buffer.alloc(allocLength) + const layoutFields = Object.assign({ instruction: type.index }, fields) + type.layout.encode(layoutFields, data) + + return data +} + +export function calcLamportsWithdrawAmount( + stakePool: StakePool, + poolTokens: number +): number { + const numerator = new BN(poolTokens).mul(stakePool.totalLamports) + const denominator = stakePool.poolTokenSupply + if (numerator.lt(denominator)) { + return 0 + } + return divideBnToNumber(numerator, denominator) +} + +export function divideBnToNumber(numerator: BN, denominator: BN): number { + if (denominator.isZero()) { + return 0 + } + const quotient = numerator.div(denominator).toNumber() + const rem = numerator.umod(denominator) + const gcd = rem.gcd(denominator) + return quotient + rem.div(gcd).toNumber() / denominator.div(gcd).toNumber() +} diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/SplitStake.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/SplitStake.tsx index 6705686075..d04c42c7cc 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Validators/SplitStake.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/SplitStake.tsx @@ -7,7 +7,7 @@ import { serializeInstructionToBase64, } from '@solana/spl-governance' -import { Connection, PublicKey, StakeProgram } from '@solana/web3.js' +import { PublicKey, StakeProgram } from '@solana/web3.js' import { UiInstruction, @@ -25,6 +25,7 @@ import { StakeAccount, StakeState } from '@utils/uiTypes/assets' import { parseMintNaturalAmountFromDecimal } from '@tools/sdk/units' import { getFilteredProgramAccounts } from '@utils/helpers' import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import { genShortestUnusedSeed } from '@utils/address' const SplitStake = ({ index, @@ -268,49 +269,4 @@ const SplitStake = ({ ) } -const genShortestUnusedSeed = async ( - connection: Connection, - basePubkey: PublicKey, - programId: PublicKey -) => { - const MAX_SEED_LEN = 32 - const ASCII_MAX = 127 - let len = 1 - // find the smallest available seed to optimize for small tx size - while (len <= MAX_SEED_LEN) { - const codes = new Array(len).fill(0) - while (!codes.every((c) => c === ASCII_MAX)) { - // check current seed unused - const seed = String.fromCharCode(...codes) - // eslint-disable-next-line no-await-in-loop - const derived = await PublicKey.createWithSeed( - basePubkey, - seed, - programId - ) - // eslint-disable-next-line no-await-in-loop - const balance = await connection.getBalance(derived) - if (balance === 0) { - return { - base: basePubkey, - derived, - seed, - } - } - // current seed used, increment code - codes[codes.length - 1]++ - for (let i = codes.length - 1; i > 0; i--) { - const prevI = i - 1 - if (codes[i] > ASCII_MAX) { - codes[i] = 0 - codes[prevI]++ - } - } - } - // all seeds of current len are used - len++ - } - throw new Error('No unused seeds found') -} - export default SplitStake diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/StakeValidator.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/StakeValidator.tsx index fee3558215..a7415d8ccb 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Validators/StakeValidator.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/StakeValidator.tsx @@ -93,7 +93,7 @@ const StakeValidator = ({ .oneOf(validators), amount: yup .number() - .min(1, 'Amount must be positive number') + .min(0.1, 'Amount must be positive number') .required('Amount is required'), seed: yup .number() @@ -200,6 +200,7 @@ const StakeValidator = ({ isValid: true, governance: form.governedTokenAccount.governance, prerequisiteInstructions: prerequisiteInstructions, + chunkBy: 1, } } diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/WithdrawStake.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/WithdrawStake.tsx index daf02a0ec4..49cc87fcca 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Validators/WithdrawStake.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/WithdrawStake.tsx @@ -257,7 +257,7 @@ const WithdrawValidatorStake = ({ marginTop: '18px', }} > - Withraw from staking account for a validator. You can only withdraw from + Withdraw from staking account for a validator. You can only withdraw from inactivated stake accounts.
diff --git a/pages/dao/[symbol]/proposal/components/instructions/Validators/removeLockup.tsx b/pages/dao/[symbol]/proposal/components/instructions/Validators/removeLockup.tsx new file mode 100644 index 0000000000..9a7a9236f4 --- /dev/null +++ b/pages/dao/[symbol]/proposal/components/instructions/Validators/removeLockup.tsx @@ -0,0 +1,276 @@ +import React, { useContext, useEffect, useState } from 'react' +import * as yup from 'yup' + +import { + Governance, + ProgramAccount, + serializeInstructionToBase64, +} from '@solana/spl-governance' + +import { + PublicKey, + StakeProgram, + TransactionInstruction, +} from '@solana/web3.js' +import BufferLayout from 'buffer-layout' + +import { + UiInstruction, + ValidatorRemoveLockup, +} from '@utils/uiTypes/proposalCreationTypes' +import { NewProposalContext } from '../../../new' +import { isFormValid } from '@utils/formValidation' +//import { web3 } from '@coral-xyz/anchor' +import useGovernanceAssets from '@hooks/useGovernanceAssets' +import GovernedAccountSelect from '../../GovernedAccountSelect' +import Input from '@components/inputs/Input' +//import { bs58 } from '@coral-xyz/anchor/dist/cjs/utils/bytes' +//import { StakeAccount, StakeState } from '@utils/uiTypes/assets' +//import { getFilteredProgramAccounts } from '@utils/helpers' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' + +const RemoveLockup = ({ + index, + governance, +}: { + index: number + governance: ProgramAccount | null +}) => { + const connection = useLegacyConnectionContext() + const programId: PublicKey = StakeProgram.programId + const { governedTokenAccountsWithoutNfts } = useGovernanceAssets() + const shouldBeGoverned = !!(index !== 0 && governance) + const [form, setForm] = useState({ + governedTokenAccount: undefined, + stakeAccount: '', + }) + const [formErrors, setFormErrors] = useState({}) + const { handleSetInstructions } = useContext(NewProposalContext) + + const handleSetForm = ({ propertyName, value }) => { + setFormErrors({}) + setForm({ ...form, [propertyName]: value }) + } + + const [governedAccount, setGovernedAccount] = useState< + ProgramAccount | undefined + >(undefined) + + const setStakeAccount = (event) => { + const value = event.target.value + handleSetForm({ + value: value, + propertyName: 'stakeAccount', + }) + } + + // const getStakeAccounts = async (): Promise => { + // if (!form.governedTokenAccount) return [] + + // const accountsNotYetStaked = await getFilteredProgramAccounts( + // connection.current, + // StakeProgram.programId, + // [ + // { + // memcmp: { + // offset: 0, + // bytes: bs58.encode([1, 0, 0, 0]), + // }, + // }, + // { + // memcmp: { + // offset: 44, + // bytes: form.governedTokenAccount.pubkey.toBase58(), + // }, + // }, + // ] + // ) + + // const accountsStaked = await getFilteredProgramAccounts( + // connection.current, + // StakeProgram.programId, + // [ + // { + // memcmp: { + // offset: 0, + // bytes: bs58.encode([2, 0, 0, 0]), + // }, + // }, + // { + // memcmp: { + // offset: 44, + // bytes: form.governedTokenAccount.pubkey.toBase58(), + // }, + // }, + // ] + // ) + + // const stakingAccounts = accountsNotYetStaked.concat( + // accountsStaked.filter((x) => { + // // filter all accounts which are not yet deactivated + // const data = x.accountInfo.data.slice(172, 172 + 8) + // return !data.equals( + // Buffer.from([255, 255, 255, 255, 255, 255, 255, 255]) + // ) + // }) + // ) + + // return stakingAccounts.map((x) => { + // return { + // stakeAccount: x.publicKey, + // state: StakeState.Inactive, + // delegatedValidator: web3.PublicKey.default, + // amount: x.accountInfo.lamports / web3.LAMPORTS_PER_SOL, + // } + // }) + // } + + //const [stakeAccounts, setStakeAccounts] = useState([]) + + const validateInstruction = async (): Promise => { + //const stakingAccounts = await getStakeAccounts() + //setStakeAccounts(stakingAccounts) + + if (!form.stakeAccount) return false + + const schema = yup.object().shape({ + stakeAccount: yup.string().required('Stake account is required'), + }) + const { isValid, validationErrors } = await isFormValid(schema, form) + setFormErrors(validationErrors) + return isValid + } + + async function getInstruction(): Promise { + const isValid = await validateInstruction() + const governancePk = governance?.pubkey + const returnInvalid = (): UiInstruction => { + return { + serializedInstruction: '', + isValid: false, + governance: undefined, + } + } + const governanceAccount = governance?.account + console.log(governanceAccount) + if ( + !connection || + !isValid || + !programId || + !governanceAccount || + !governancePk || + !form.governedTokenAccount?.isSol || + !form.stakeAccount + ) { + return returnInvalid() + } + + const authorizedPubkey = form.governedTokenAccount.extensions + .transferAddress! + const stakePubkey = new PublicKey(form.stakeAccount) + + //greed dao test pubkey stake account pk 14SPGuYJANnAhmpKy6bwXKJ5Njqxnr8k2jZ9DnzN84de + + const layout = BufferLayout.struct([ + BufferLayout.u32('instruction'), + BufferLayout.u8('hasUnixTimestamp'), + BufferLayout.ns64('unixTimestamp'), + BufferLayout.u8('hasEpoch'), + //add epoch field if needed + BufferLayout.u8('hasCustodian'), + //add custodian field if needed + ]) + const data = Buffer.alloc(layout.span) + + //any date in past will unlock the stake account. + layout.encode( + { + //lockup instruction index in stake program + instruction: 6, + //option padding + hasUnixTimestamp: 1, + //any past time unixtimestamp + unixTimestamp: 1715685793, + }, + data + ) + + const keys = [ + { + pubkey: stakePubkey, + isWritable: true, + isSigner: false, + }, + { + pubkey: authorizedPubkey, + isWritable: false, + isSigner: true, + }, + ] + + const instruction = new TransactionInstruction({ + keys, + programId, + data, + }) + + return { + serializedInstruction: serializeInstructionToBase64(instruction), + additionalSerializedInstructions: [], + isValid: true, + governance: form.governedTokenAccount.governance, + chunkBy: 1, + } + } + + useEffect(() => { + handleSetInstructions( + { + governedAccount: governedAccount, + 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]) + + useEffect(() => { + handleSetInstructions( + { governedAccount: governedAccount, 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, governedAccount]) + useEffect(() => { + setGovernedAccount(form.governedTokenAccount?.governance) + // 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.governedTokenAccount]) + + return ( + <> + x.isSol + )} + onChange={(value) => { + handleSetForm({ value, propertyName: 'governedTokenAccount' }) + }} + value={form.governedTokenAccount} + error={formErrors['governedTokenAccount']} + shouldBeGoverned={shouldBeGoverned} + governance={governance} + type="token" + > + + + ) +} + +export default RemoveLockup diff --git a/pages/dao/[symbol]/proposal/components/instructions/Vsr/CreateRegistrar.tsx b/pages/dao/[symbol]/proposal/components/instructions/Vsr/CreateRegistrar.tsx index 1a5879ce68..e202bd6897 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Vsr/CreateRegistrar.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Vsr/CreateRegistrar.tsx @@ -107,7 +107,7 @@ const CreateVsrRegistrar = ({ return returnInvalid() } - const { registrar, registrarBump } = await getRegistrarPDA( + const { registrar, registrarBump } = getRegistrarPDA( realm.pubkey, realm.account.communityMint, vsrClient.program.programId diff --git a/pages/dao/[symbol]/proposal/components/instructions/Vsr/VotingMintConfig.tsx b/pages/dao/[symbol]/proposal/components/instructions/Vsr/VotingMintConfig.tsx index 2cf941727b..f8cd102531 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/Vsr/VotingMintConfig.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/Vsr/VotingMintConfig.tsx @@ -122,7 +122,7 @@ const VotingMintConfig = ({ ...form, } - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realm.pubkey, realm.account.communityMint, vsrClient.program.programId diff --git a/pages/dao/[symbol]/proposal/components/instructions/bpfUpgradeableLoader/ProgramUpgrade.tsx b/pages/dao/[symbol]/proposal/components/instructions/bpfUpgradeableLoader/ProgramUpgrade.tsx index f5163e114c..a30fd718d2 100644 --- a/pages/dao/[symbol]/proposal/components/instructions/bpfUpgradeableLoader/ProgramUpgrade.tsx +++ b/pages/dao/[symbol]/proposal/components/instructions/bpfUpgradeableLoader/ProgramUpgrade.tsx @@ -171,6 +171,7 @@ const ProgramUpgrade = ({ <> { handleSetForm({ diff --git a/pages/dao/[symbol]/proposal/new.tsx b/pages/dao/[symbol]/proposal/new.tsx index c6709da8ac..30fe0ba643 100644 --- a/pages/dao/[symbol]/proposal/new.tsx +++ b/pages/dao/[symbol]/proposal/new.tsx @@ -57,18 +57,14 @@ import ConfigureNftPluginCollection from './components/instructions/NftVotingPlu import SwitchboardFundOracle from './components/instructions/Switchboard/FundOracle' import WithdrawFromOracle from './components/instructions/Switchboard/WithdrawFromOracle' import StakeValidator from './components/instructions/Validators/StakeValidator' +import SanctumDepositStake from './components/instructions/Validators/SanctumDepositStake' +import SanctumWithdrawStake from './components/instructions/Validators/SanctumWithdrawStake' import DeactivateValidatorStake from './components/instructions/Validators/DeactivateStake' import WithdrawValidatorStake from './components/instructions/Validators/WithdrawStake' import DelegateStake from './components/instructions/Validators/DelegateStake' import SplitStake from './components/instructions/Validators/SplitStake' import useCreateProposal from '@hooks/useCreateProposal' -import MakeInitMarketParams from './components/instructions/Foresight/MakeInitMarketParams' -import MakeInitMarketListParams from './components/instructions/Foresight/MakeInitMarketListParams' -import MakeInitCategoryParams from './components/instructions/Foresight/MakeInitCategoryParams' -import MakeResolveMarketParams from './components/instructions/Foresight/MakeResolveMarketParams' -import MakeAddMarketListToCategoryParams from './components/instructions/Foresight/MakeAddMarketListToCategoryParams' import RealmConfig from './components/instructions/RealmConfig' -import MakeSetMarketMetadataParams from './components/instructions/Foresight/MakeSetMarketMetadataParams' import CloseTokenAccount from './components/instructions/CloseTokenAccount' import CloseMultipleTokenAccounts from './components/instructions/CloseMultipleTokenAccounts' import { InstructionDataWithHoldUpTime } from 'actions/createProposal' @@ -132,12 +128,24 @@ import InitStrike from './components/instructions/Dual/InitStrike' import IdlSetBuffer from './components/instructions/Mango/MangoV4/IdlSetBuffer' import { useRealmQuery } from '@hooks/queries/realm' import { usePrevious } from '@hooks/usePrevious' -import DualVote from './components/instructions/Dual/DualVote' +import DaoVote from './components/instructions/SplGov/DaoVote' import DualGso from './components/instructions/Dual/DualGso' import DualGsoWithdraw from './components/instructions/Dual/DualGsoWithdraw' import MultiChoiceForm from '../../../../components/MultiChoiceForm' import CloseVaults from './components/instructions/DistrubtionProgram/CloseVaults' import FillVaults from './components/instructions/DistrubtionProgram/FillVaults' +import MeshRemoveMember from './components/instructions/Squads/MeshRemoveMember' +import MeshAddMember from './components/instructions/Squads/MeshAddMember' +import MeshChangeThresholdMember from './components/instructions/Squads/MeshChangeThresholdMember' +import PythRecoverAccount from './components/instructions/Pyth/PythRecoverAccount' +import { useVoteByCouncilToggle } from '@hooks/useVoteByCouncilToggle' +import BurnTokens from './components/instructions/BurnTokens' +import RemoveLockup from './components/instructions/Validators/removeLockup' +import SymmetryCreateBasket from './components/instructions/Symmetry/SymmetryCreateBasket' +import SymmetryEditBasket from './components/instructions/Symmetry/SymmetryEditBasket' +import SymmetryDeposit from './components/instructions/Symmetry/SymmetryDeposit' +import SymmetryWithdraw from './components/instructions/Symmetry/SymmetryWithdraw' +import PythUpdatePoolAuthority from './components/instructions/Pyth/PythUpdatePoolAuthority' const TITLE_LENGTH_LIMIT = 130 // the true length limit is either at the tx size level, and maybe also the total account size level (I can't remember) @@ -192,14 +200,17 @@ const New = () => { const { handleCreateProposal, proposeMultiChoice } = useCreateProposal() const { fmtUrlWithCluster } = useQueryContext() const realm = useRealmQuery().data?.result - - const { symbol, realmInfo, canChooseWhoVote } = useRealm() + const { symbol, realmInfo } = useRealm() const { availableInstructions } = useGovernanceAssets() - const [voteByCouncil, setVoteByCouncil] = useState(false) const [form, setForm] = useState({ title: typeof router.query['t'] === 'string' ? router.query['t'] : '', description: '', }) + const { + voteByCouncil, + shouldShowVoteByCouncilToggle, + setVoteByCouncil, + } = useVoteByCouncilToggle() const [multiChoiceForm, setMultiChoiceForm] = useState<{ governance: PublicKey | undefined options: string[] @@ -458,6 +469,7 @@ const New = () => { | null } = useMemo( () => ({ + [Instructions.Burn]: BurnTokens, [Instructions.Transfer]: SplTokenTransfer, [Instructions.ProgramUpgrade]: ProgramUpgrade, [Instructions.Mint]: Mint, @@ -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, @@ -502,6 +514,11 @@ const New = () => { [Instructions.MeanWithdrawFromAccount]: MeanWithdrawFromAccount, [Instructions.MeanCreateStream]: MeanCreateStream, [Instructions.MeanTransferStream]: MeanTransferStream, + [Instructions.SquadsMeshRemoveMember]: MeshRemoveMember, + [Instructions.SquadsMeshAddMember]: MeshAddMember, + [Instructions.SquadsMeshChangeThresholdMember]: MeshChangeThresholdMember, + [Instructions.PythRecoverAccount]: PythRecoverAccount, + [Instructions.PythUpdatePoolAuthority]: PythUpdatePoolAuthority, [Instructions.CreateSolendObligationAccount]: CreateObligationAccount, [Instructions.InitSolendObligationAccount]: InitObligationAccount, [Instructions.DepositReserveLiquidityAndObligationCollateral]: DepositReserveLiquidityAndObligationCollateral, @@ -514,12 +531,6 @@ const New = () => { [Instructions.WithdrawFromOracle]: WithdrawFromOracle, [Instructions.RefreshSolendObligation]: RefreshObligation, [Instructions.RefreshSolendReserve]: RefreshReserve, - [Instructions.ForesightInitMarket]: MakeInitMarketParams, - [Instructions.ForesightInitMarketList]: MakeInitMarketListParams, - [Instructions.ForesightInitCategory]: MakeInitCategoryParams, - [Instructions.ForesightResolveMarket]: MakeResolveMarketParams, - [Instructions.ForesightAddMarketListToCategory]: MakeAddMarketListToCategoryParams, - [Instructions.ForesightSetMarketMetadata]: MakeSetMarketMetadataParams, [Instructions.RealmConfig]: RealmConfig, [Instructions.CreateNftPluginRegistrar]: CreateNftPluginRegistrar, [Instructions.CreateNftPluginMaxVoterWeight]: CreateNftPluginMaxVoterWeightRecord, @@ -534,9 +545,12 @@ const New = () => { [Instructions.CreateTokenMetadata]: CreateTokenMetadata, [Instructions.UpdateTokenMetadata]: UpdateTokenMetadata, [Instructions.StakeValidator]: StakeValidator, + [Instructions.SanctumDepositStake]: SanctumDepositStake, + [Instructions.SanctumWithdrawStake]: SanctumWithdrawStake, [Instructions.DeactivateValidatorStake]: DeactivateValidatorStake, [Instructions.WithdrawValidatorStake]: WithdrawValidatorStake, [Instructions.DelegateStake]: DelegateStake, + [Instructions.RemoveStakeLock]: RemoveLockup, [Instructions.SplitStake]: SplitStake, [Instructions.DifferValidatorStake]: null, [Instructions.TransferDomainName]: TransferDomainName, @@ -590,6 +604,10 @@ const New = () => { [Instructions.RemoveServiceFromDID]: RemoveServiceFromDID, [Instructions.RevokeGoverningTokens]: RevokeGoverningTokens, [Instructions.SetMintAuthority]: SetMintAuthority, + [Instructions.SymmetryCreateBasket]: SymmetryCreateBasket, + [Instructions.SymmetryEditBasket]: SymmetryEditBasket, + [Instructions.SymmetryDeposit]: SymmetryDeposit, + [Instructions.SymmetryWithdraw]: SymmetryWithdraw, }), [governance?.pubkey?.toBase58()] ) @@ -711,7 +729,7 @@ const New = () => { })} />
- {canChooseWhoVote && ( + {shouldShowVoteByCouncilToggle && ( { diff --git a/pages/dao/[symbol]/token-stats/index.tsx b/pages/dao/[symbol]/token-stats/index.tsx index 7d3a281042..55f891ffc7 100644 --- a/pages/dao/[symbol]/token-stats/index.tsx +++ b/pages/dao/[symbol]/token-stats/index.tsx @@ -15,14 +15,13 @@ import dayjs from 'dayjs' import dynamic from 'next/dynamic' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import useGovernanceAssetsStore from 'stores/useGovernanceAssetsStore' -import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { DAYS_PER_MONTH, getMinDurationFmt, getTimeLeftFromNowFmt, } from '@utils/dateTools' import InfoBox from 'VoteStakeRegistry/components/LockTokenStats/InfoBox' -import { LockupType } from 'VoteStakeRegistry/sdk/accounts' +import { LockupType, Registrar } from 'VoteStakeRegistry/sdk/accounts' import { DepositWithWallet, getProposalsTransactions, @@ -47,6 +46,7 @@ import { useRealmProposalsQuery } from '@hooks/queries/proposal' import { useQuery } from '@tanstack/react-query' import { IDL } from 'VoteStakeRegistry/sdk/voter_stake_registry' import { ProfileImage, ProfileName } from '@components/Profile' +import {useVsrClient} from "../../../../VoterWeightPlugins/useVsrClient"; const VestingVsTime = dynamic( () => import('VoteStakeRegistry/components/LockTokenStats/VestingVsTime'), @@ -134,13 +134,10 @@ const LockTokenStats = () => { const mint = useRealmCommunityMintInfoQuery().data?.result const { symbol } = useRouter().query const { realmInfo } = useRealm() - const vsrClient = useVotePluginsClientStore((s) => s.state.vsrClient) - const voteStakeRegistryRegistrarPk = useVotePluginsClientStore( - (s) => s.state.voteStakeRegistryRegistrarPk - ) - const voteStakeRegistryRegistrar = useVotePluginsClientStore( - (s) => s.state.voteStakeRegistryRegistrar - ) + const { vsrClient, plugin } = useVsrClient(); + const voteStakeRegistryRegistrar = plugin?.params as Registrar | undefined; + const voteStakeRegistryRegistrarPk = plugin?.registrarPublicKey; + const governedTokenAccounts = useGovernanceAssetsStore( (s) => s.governedTokenAccounts ) 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..b9a067bc6c 100644 --- a/pages/realms/new/community-token/index.tsx +++ b/pages/realms/new/community-token/index.tsx @@ -1,42 +1,43 @@ -import { useState } from 'react' import { useRouter } from 'next/router' +import { useState } from 'react' +import useQueryContext from '@hooks/useQueryContext' import { PublicKey } from '@solana/web3.js' import createTokenizedRealm from 'actions/createTokenizedRealm' -import useQueryContext from '@hooks/useQueryContext' import { DEFAULT_GOVERNANCE_PROGRAM_ID } from '@components/instructions/tools' import { notify } from '@utils/notifications' import FormPage from '@components/NewRealmWizard/PageTemplate' +import AddCouncilForm, { + AddCouncil, + AddCouncilSchema, +} from '@components/NewRealmWizard/components/steps/AddCouncilForm' import BasicDetailsForm, { - BasicDetailsSchema, BasicDetails, + BasicDetailsSchema, } from '@components/NewRealmWizard/components/steps/BasicDetailsForm' import CommunityTokenDetailsForm, { - CommunityTokenSchema, CommunityToken, + CommunityTokenSchema, } from '@components/NewRealmWizard/components/steps/CommunityTokenDetailsForm' +import InviteMembersForm, { + InviteMembers, + InviteMembersSchema, +} from '@components/NewRealmWizard/components/steps/InviteMembersForm' import YesVotePercentageForm, { - CommunityYesVotePercentageSchema, CommunityYesVotePercentage, + CommunityYesVotePercentageSchema, CouncilYesVotePercentageSchema, } from '@components/NewRealmWizard/components/steps/YesVotePercentageThresholdForm' -import AddCouncilForm, { - AddCouncilSchema, - AddCouncil, -} from '@components/NewRealmWizard/components/steps/AddCouncilForm' -import InviteMembersForm, { - InviteMembersSchema, - InviteMembers, -} from '@components/NewRealmWizard/components/steps/InviteMembersForm' +import { PluginName } from '@constants/plugins' +import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' +import useWalletOnePointOh from '@hooks/useWalletOnePointOh' import { GoverningTokenConfigAccountArgs, GoverningTokenType, } from '@solana/spl-governance' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' -import useLegacyConnectionContext from '@hooks/useLegacyConnectionContext' export const FORM_NAME = 'tokenized' @@ -55,6 +56,12 @@ const transformFormData2RealmCreation = (formData: CommunityTokenForm) => { const programIdAddress = formData?.programId || DEFAULT_GOVERNANCE_PROGRAM_ID + // If plugins are being added to the realm, we want to delay setting the realm authority + // until after they are added, so that the plugins can be added by the current wallet, without going through + // a proposal. + // If more plugins are included in the Community token flow, then we should generalise this + const shouldSkipSettingRealmAuthority = formData.isQuadratic ?? false + const params = { ...{ programIdAddress, @@ -72,7 +79,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, @@ -80,6 +91,11 @@ const transformFormData2RealmCreation = (formData: CommunityTokenForm) => { formData.transferCouncilMintAuthority ?? true, councilWalletPks: formData?.memberAddresses?.map((w) => new PublicKey(w)) || [], + skipRealmAuthority: shouldSkipSettingRealmAuthority, + coefficientA: formData.coefficientA, + coefficientB: formData.coefficientB, + coefficientC: formData.coefficientC, + civicPass: formData.civicPass, }, ...(formData._programVersion === 3 ? ({ @@ -157,10 +173,18 @@ export default function CommunityTokenWizard() { throw new Error('No valid wallet connected') } + // A Quadratic Voting DAO includes two plugins: + // - Gateway Plugin: sybil resistance protection (by default provided by civic.com) + // - QV Plugin: adapt the vote weight according to the quadratic formula: ax^1/2 + bx + c + const pluginList: PluginName[] = formData.isQuadratic + ? ['gateway', 'QV'] + : [] + const results = await createTokenizedRealm({ wallet, connection: connection.current, ...transformFormData2RealmCreation(formData), + pluginList, }) if (results) { diff --git a/public/actions.json b/public/actions.json new file mode 100644 index 0000000000..72f60ddb4e --- /dev/null +++ b/public/actions.json @@ -0,0 +1,8 @@ +{ + "rules": [ + { + "pathPattern": "/dao/**", + "apiPath": "https://realms.dial.to/vote/dao/**" + } + ] +} diff --git a/public/img/pyth.svg b/public/img/pyth.svg new file mode 100644 index 0000000000..e8a3bbffcb --- /dev/null +++ b/public/img/pyth.svg @@ -0,0 +1,6 @@ + + + + diff --git a/public/img/squads.png b/public/img/squads.png new file mode 100644 index 0000000000..25ffdf2c7a Binary files /dev/null and b/public/img/squads.png differ diff --git a/public/img/symmetry.png b/public/img/symmetry.png new file mode 100644 index 0000000000..27ac77afe4 Binary files /dev/null and b/public/img/symmetry.png differ diff --git a/public/realms/Advocat/AdvocatBusiness.png b/public/realms/Advocat/AdvocatBusiness.png new file mode 100644 index 0000000000..403d36a0ef Binary files /dev/null and b/public/realms/Advocat/AdvocatBusiness.png differ diff --git a/public/realms/Advocat/AdvocatDev.png b/public/realms/Advocat/AdvocatDev.png new file mode 100644 index 0000000000..9a224ddb90 Binary files /dev/null and b/public/realms/Advocat/AdvocatDev.png differ diff --git a/public/realms/Advocat/banner.jpg b/public/realms/Advocat/banner.jpg new file mode 100644 index 0000000000..34df5759e1 Binary files /dev/null and b/public/realms/Advocat/banner.jpg differ diff --git a/public/realms/Advocat/logo.png b/public/realms/Advocat/logo.png new file mode 100644 index 0000000000..2e770d43db Binary files /dev/null and b/public/realms/Advocat/logo.png differ diff --git a/public/realms/Allie-Coin-DAO/Allie-Coin-Logo.png b/public/realms/Allie-Coin-DAO/Allie-Coin-Logo.png index 156f0a5575..41954359c7 100644 Binary files a/public/realms/Allie-Coin-DAO/Allie-Coin-Logo.png and b/public/realms/Allie-Coin-DAO/Allie-Coin-Logo.png differ 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/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/BootstrapDAO/BootRealms.png b/public/realms/BootstrapDAO/BootRealms.png index 599e81c6d9..259a41fe86 100644 Binary files a/public/realms/BootstrapDAO/BootRealms.png and b/public/realms/BootstrapDAO/BootRealms.png differ diff --git a/public/realms/CoalitionDAO/banner.png b/public/realms/CoalitionDAO/banner.png new file mode 100644 index 0000000000..ed08c93880 Binary files /dev/null and b/public/realms/CoalitionDAO/banner.png differ diff --git a/public/realms/CoalitionDAO/logo.png b/public/realms/CoalitionDAO/logo.png new file mode 100644 index 0000000000..36a1e7797f Binary files /dev/null and b/public/realms/CoalitionDAO/logo.png differ diff --git a/public/realms/CryptoHelp/cryptohelp.png b/public/realms/CryptoHelp/cryptohelp.png index 58c65e3020..18d0713458 100644 Binary files a/public/realms/CryptoHelp/cryptohelp.png and b/public/realms/CryptoHelp/cryptohelp.png differ diff --git a/public/realms/EpicentralLabsDAO/Epicentral-Labs-Logo.png b/public/realms/EpicentralLabsDAO/Epicentral-Labs-Logo.png new file mode 100644 index 0000000000..a54df83969 Binary files /dev/null and b/public/realms/EpicentralLabsDAO/Epicentral-Labs-Logo.png differ diff --git a/public/realms/EpicentralLabsDAO/EpicentralDAOBanner.png b/public/realms/EpicentralLabsDAO/EpicentralDAOBanner.png new file mode 100644 index 0000000000..bb9bca54d9 Binary files /dev/null and b/public/realms/EpicentralLabsDAO/EpicentralDAOBanner.png differ diff --git a/public/realms/FABS/img/fabio.png b/public/realms/FABS/img/fabio.png new file mode 100644 index 0000000000..e429e1415a Binary files /dev/null and b/public/realms/FABS/img/fabio.png differ diff --git a/public/realms/FABS/img/fabs-banner.jpeg b/public/realms/FABS/img/fabs-banner.jpeg new file mode 100644 index 0000000000..a91cb864f0 Binary files /dev/null and b/public/realms/FABS/img/fabs-banner.jpeg differ diff --git a/public/realms/FOXTAG/FOXTAG.png b/public/realms/FOXTAG/FOXTAG.png new file mode 100644 index 0000000000..bde9ca9c68 Binary files /dev/null and b/public/realms/FOXTAG/FOXTAG.png differ diff --git a/public/realms/FinanceIsMagic/Banner.png b/public/realms/FinanceIsMagic/Banner.png new file mode 100644 index 0000000000..6604018935 Binary files /dev/null and b/public/realms/FinanceIsMagic/Banner.png differ diff --git a/public/realms/FinanceIsMagic/Logo.png b/public/realms/FinanceIsMagic/Logo.png new file mode 100644 index 0000000000..0e37c39d7a Binary files /dev/null and b/public/realms/FinanceIsMagic/Logo.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/GCDC/img/gaycoinz-banner.png b/public/realms/GCDC/img/gaycoinz-banner.png new file mode 100644 index 0000000000..b85f506404 Binary files /dev/null and b/public/realms/GCDC/img/gaycoinz-banner.png differ diff --git a/public/realms/GCDC/img/gaycoinz-logo.png b/public/realms/GCDC/img/gaycoinz-logo.png new file mode 100644 index 0000000000..97ebe6b197 Binary files /dev/null and b/public/realms/GCDC/img/gaycoinz-logo.png differ diff --git a/public/realms/Guacamole/Guacamole_Banner.png b/public/realms/Guacamole/Guacamole_Banner.png new file mode 100644 index 0000000000..06a3b4f5c1 Binary files /dev/null and b/public/realms/Guacamole/Guacamole_Banner.png differ diff --git a/public/realms/Guacamole/Guacamole_Token_Logo_Green.png b/public/realms/Guacamole/Guacamole_Token_Logo_Green.png new file mode 100644 index 0000000000..20fa58838d Binary files /dev/null and b/public/realms/Guacamole/Guacamole_Token_Logo_Green.png differ diff --git a/public/realms/IKB/ikb_dao_banner.jpg b/public/realms/IKB/ikb_dao_banner.jpg new file mode 100644 index 0000000000..bf5a4c2b4b Binary files /dev/null and b/public/realms/IKB/ikb_dao_banner.jpg differ diff --git a/public/realms/IKB/ikb_dao_logo.jpg b/public/realms/IKB/ikb_dao_logo.jpg new file mode 100644 index 0000000000..f780ccc9c8 Binary files /dev/null and b/public/realms/IKB/ikb_dao_logo.jpg differ diff --git a/public/realms/JetSkiDAO/banner.png b/public/realms/JetSkiDAO/banner.png new file mode 100644 index 0000000000..7ad7afea5a Binary files /dev/null and b/public/realms/JetSkiDAO/banner.png differ diff --git a/public/realms/JetSkiDAO/logo.jpeg b/public/realms/JetSkiDAO/logo.jpeg new file mode 100644 index 0000000000..a2f9dbec4f Binary files /dev/null and b/public/realms/JetSkiDAO/logo.jpeg differ diff --git a/public/realms/Jito/jito.png b/public/realms/Jito/jito.png new file mode 100644 index 0000000000..efd5f85459 Binary files /dev/null and b/public/realms/Jito/jito.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/MewfasaDAO/banner-dao.jpg b/public/realms/MewfasaDAO/banner-dao.jpg new file mode 100644 index 0000000000..841d64044a Binary files /dev/null and b/public/realms/MewfasaDAO/banner-dao.jpg differ diff --git a/public/realms/MewfasaDAO/mewfasadao.jpg b/public/realms/MewfasaDAO/mewfasadao.jpg new file mode 100644 index 0000000000..e84cf13d22 Binary files /dev/null and b/public/realms/MewfasaDAO/mewfasadao.jpg differ diff --git a/public/realms/PAWN/img/pawn.png b/public/realms/PAWN/img/pawn.png new file mode 100644 index 0000000000..3c1c6f8008 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/PAWNGO/img/pawngo.png b/public/realms/PAWNGO/img/pawngo.png new file mode 100644 index 0000000000..2bcde3a6b7 Binary files /dev/null and b/public/realms/PAWNGO/img/pawngo.png differ diff --git a/public/realms/PAWNGO/img/pawngodao.png b/public/realms/PAWNGO/img/pawngodao.png new file mode 100644 index 0000000000..17d85663f0 Binary files /dev/null and b/public/realms/PAWNGO/img/pawngodao.png differ diff --git a/public/realms/PibbleDAO/Banner.png b/public/realms/PibbleDAO/Banner.png new file mode 100644 index 0000000000..de51395995 Binary files /dev/null and b/public/realms/PibbleDAO/Banner.png differ diff --git a/public/realms/PibbleDAO/logo.png b/public/realms/PibbleDAO/logo.png new file mode 100644 index 0000000000..14cea48313 Binary files /dev/null and b/public/realms/PibbleDAO/logo.png differ diff --git a/public/realms/Poll DAO/Vote Vote Vote.png b/public/realms/Poll DAO/Vote Vote Vote.png new file mode 100644 index 0000000000..c2f6941c3d Binary files /dev/null and b/public/realms/Poll DAO/Vote Vote Vote.png differ diff --git a/public/realms/Poll DAO/poll.jpg b/public/realms/Poll DAO/poll.jpg new file mode 100644 index 0000000000..8dc81347b8 Binary files /dev/null and b/public/realms/Poll DAO/poll.jpg differ diff --git a/public/realms/Solsaur/solsaur.png b/public/realms/Solsaur/solsaur.png index 1b74053e51..128c25fbca 100644 Binary files a/public/realms/Solsaur/solsaur.png and b/public/realms/Solsaur/solsaur.png differ diff --git a/public/realms/TensorDAO/TensorDAO_banner.png b/public/realms/TensorDAO/TensorDAO_banner.png new file mode 100644 index 0000000000..8dc41f1999 Binary files /dev/null and b/public/realms/TensorDAO/TensorDAO_banner.png differ diff --git a/public/realms/TensorDAO/TensorDAO_logo.png b/public/realms/TensorDAO/TensorDAO_logo.png new file mode 100644 index 0000000000..038b745f32 Binary files /dev/null and b/public/realms/TensorDAO/TensorDAO_logo.png differ diff --git a/public/realms/The $GREED Experiment/The $GREED Experiment logo.png b/public/realms/The $GREED Experiment/The $GREED Experiment logo.png new file mode 100644 index 0000000000..ed17caa4a6 Binary files /dev/null and b/public/realms/The $GREED Experiment/The $GREED Experiment logo.png differ diff --git a/public/realms/The $GREED Experiment/The_$GREED_Experiment_logo.png b/public/realms/The $GREED Experiment/The_$GREED_Experiment_logo.png new file mode 100644 index 0000000000..ed17caa4a6 Binary files /dev/null and b/public/realms/The $GREED Experiment/The_$GREED_Experiment_logo.png differ diff --git a/public/realms/about.json b/public/realms/about.json index be0616fea4..87e08e86f7 100644 --- a/public/realms/about.json +++ b/public/realms/about.json @@ -3830,24 +3830,6 @@ } ] }, - "6NzVDMfEBJvkFDnjPx53K7mLGW3yQdSjLhsamS8go4cn": { - "symbol": "Bonfida", - "heading": "Bonfida has a simple, yet realistic goal of providing products and services that will enhance the Solana blockchain experience. ", - "about": [ - { - "heading": "Introduction", - "content": [ - "Bonfida is known as the top infrastructure developer on Solana. This accolade has been earned from our contributions to the ecosystem by providing services and products that allow for the wider ecosystem to flourish.", - "Bonfida’s primary product is the Solana Name Service (SNS). SNS has a straightforward mission of providing users with a Web3 ID. One of the clear benefits of the name service is a human-readable name that maps to a SOL address. Wallet address formats can be a barrier to entry, and therefore having an identifiable address can facilitate payments, efficiency, and overall user experience in our sphere. A name, not a number.", - "Besides SNS, Bonfida’s contributions to the ecosystem include; (1) creating a new Serum Core engine, the Asset Agnostic Orderbook (AOB), (2) xMS, the cross-messaging service, to name a few. As a result of these contributions, our developers are highly respected and sought after within the Solana ecosystem." - ] - } - ], - "documentation": { - "title": "Docs", - "url": "https://docs.bonfida.org/collection/overview" - } - }, "3MMDxjv1SzEFQDKryT7csAvaydYtrgMAc3L9xL9CVLCg": { "symbol": "Project Serum", "heading": "Faster, Cheaper and more Powerful DeFi", diff --git a/public/realms/devnet.json b/public/realms/devnet.json index cf00d616e5..d6c8dce3fd 100644 --- a/public/realms/devnet.json +++ b/public/realms/devnet.json @@ -254,5 +254,34 @@ "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" + }, + { + "symbol": "Drift Protocol", + "bannerImage": "https://i.imgur.com/b9pPf3S.png", + "displayName": "Drift Protocol", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "9nUyxzVL2FUMuWUiVZG66gwK15CJiM3PoLkfrnGfkvt6", + "ogImage": "https://i.imgur.com/HnF1Zzy.png", + "shortDescription": "A lightning-fast and scalable perpetual futures DEX.", + "sortRank": 3, + "website": "https://www.drift.trade/", + "twitter": "@DriftProtocol", + "discord": "http://discord.com/invite/drifting", + "github": "https://github.com/drift-labs/protocol-v2" } -] \ No newline at end of file +] diff --git a/public/realms/mainnet-beta.json b/public/realms/mainnet-beta.json index ea5c33391c..0e7ef9d80c 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", @@ -47,6 +54,19 @@ "website": "https://governance.so/dao/BVfB1PfxCdcKozoQQ5kvC9waUY527bZuwJVyT7Qvf8N2", "shortDescription": "A small but mighty developer DAO! 🚀 We're like the little engines that could, tirelessly building, testing, and occasionally chewing glass to create a better ecosystem" }, + { + "symbol": "POLL", + "displayName": "POLL", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "WUd1MpRwqw15cJpodXBiuyGv3rqYW99weEqrvkZpYFW", + "bannerImage": "/realms/Poll DAO/Vote Vote Vote.png", + "website": "-", + "twitter": "@PollDAO", + "discord": "-", + "ogImage": "/realms/Poll DAO/poll.jpg", + "github": "-", + "shortDescription": "Poll it" + }, { "symbol": "Dean's List Network State", "displayName": "Dean's List Network State", @@ -99,9 +119,26 @@ "github": "https://github.com/blockworks-foundation/" }, { - "symbol": "XAND", + "symbol": "OBV2", + "category": "defi", + "displayName": "OpenBook V2 Council", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "EVDdDLdhSMU8nzLEmoRMuH7rReXXgDibAtTPg66m4JHW", + "communityMint": "A5tGJvsUpehqSzzWY2whuPfBvBXTRQsUCDcjZ2HC479m" + }, + { + "symbol": "NLDAO", + "ogImage": "https://arweave.net/SEOxljn_3ij0m9Rzp06l3SBJ692TdQcCsX7oFvx-jfs", + "category": "legal", + "displayName": "Nous Legal DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "Hyi8vJopSGFa36uF1rdvjvG5yptAcFWYTxqr2YF3hA8j", + "communityMint": "Fj1tPZzgBnsbQMWgJM3CNjM8NZ9XHED7hhnHTN6GNZAF" + }, + { + "symbol": "XANDC", "category": "defi", - "displayName": "Xandeum DAO", + "displayName": "Xandeum DevNet DAO", "programId": "DcG2PZTnj8s4Pnmp7xJswniCskckU5E6XsrKuyD7NYFK", "realmId": "CFprdZRYitjPYEDUQKDQZwao1jcRcU1z1GsFspMpN8Ci", "communityMint": "2j437Lt84XvysJiYbXTSJfAMy26Et9HiVGFvGFp8nYWH", @@ -192,7 +229,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" }, { @@ -339,6 +376,15 @@ "twitter": "@only_raindrops", "github": "https://github.com/raindrops-protocol/raindrops" }, + { + "symbol": "FABS", + "displayName": "Founders Wif Abs", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "2iWqzA6j5jDVsbVjBJHM2DFX4qJX7AAohArAR8VLDVV6", + "ogImage": "/realms/FABS/img/fabio.png", + "bannerImage": "/realms/FABS/img/fabs-banner.jpeg", + "twitter": "@fabsonsol" + }, { "symbol": "UkraineUnchained", "displayName": "#Unchain_Ukraine", @@ -703,6 +749,18 @@ "website": "https://app.goblin.gold/", "twitter": "@goblingold_fi" }, + { + "symbol": "pumpkinSOL", + "displayName": "Pumpkin's Pool", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "EpvSHe3dnTQvz5qK8ks7zEbzA3ZABqaXW7fJfr8ULFiy", + "ogImage": "/realms/pumpkinspool/pumpkin_logo_cropped.png", + "bannerImage": "/realms/pumpkinspool/pumpkin_header.png", + "website": "https:/pumpkinspool.eco", + "twitter": "@pumpkinspool", + "discord": "https://discord.gg/pF6pMHApwP", + "shortDescription": "Pumpkin’s Pool delivers top staking returns while supporting animal welfare." + }, { "symbol": "DAINV", "displayName": "Digital Asset Investing", @@ -719,22 +777,6 @@ "realmId": "AvfMYqHjddR93zvmZXcQGUTkRu3GJYppTU93iKhMUWRF", "ogImage": "/realms/KiwiDAO/img/kiwi_logo.png" }, - { - "symbol": "FIDA", - "category": "web3", - "bannerImage": "https://i.imgur.com/zXTrhXU.png", - "displayName": "Bonfida DAO", - "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", - "realmId": "6NzVDMfEBJvkFDnjPx53K7mLGW3yQdSjLhsamS8go4cn", - "ogImage": "https://i.imgur.com/34Ss9kj.png", - "shortDescription": "Bonfida has a simple, yet realistic goal of providing products and services that will enhance the Solana blockchain experience.", - "sortRank": 2, - "website": "https://bonfida.org/", - "twitter": "@bonfida", - "keywords": "Bonfida, REALM, Governance, Serum, SRM, Serum DEX, DEFI, Decentralized Finance, Decentralised Finance, Crypto, ERC20, Ethereum, Decentralize, Solana, SOL, SPL, Cross-Chain, Trading, Fastest, Fast, SerumBTC, SerumUSD, SRM Tokens, SPL Tokens", - "discord": "https://discord.gg/tusXFZXGTV", - "github": "https://github.com/Bonfida" - }, { "symbol": "N&F", "displayName": "Nick & Family", @@ -1453,20 +1495,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", @@ -1497,20 +1525,6 @@ "discord": "https://discord.gg/Bv8JhaPF", "github": "https://github.com/sher9n/Lighthouse" }, - { - "symbol": "Drift Protocol", - "bannerImage": "https://i.imgur.com/b9pPf3S.png", - "displayName": "Drift Protocol", - "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", - "realmId": "9nUyxzVL2FUMuWUiVZG66gwK15CJiM3PoLkfrnGfkvt6", - "ogImage": "https://i.imgur.com/HnF1Zzy.png", - "shortDescription": "A lightning-fast and scalable perpetual futures DEX.", - "sortRank": 3, - "website": "https://www.drift.trade/", - "twitter": "@DriftProtocol", - "discord": "http://discord.com/invite/drifting", - "github": "https://github.com/drift-labs/protocol-v2" - }, { "symbol": "Zeta Markets", "category": "defi", @@ -2344,13 +2358,12 @@ { "symbol": "Parcl", "category": "defi", - "bannerImage": "https://uploads-ssl.webflow.com/6320eecd0f98b4666b218021/635bd63143eea412576055d3_banner.png", - "displayName": "Parcl", - "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", - "realmId": "8msNFq5VBectsGAv66zYx5QRve1p3m6ZEz49xaWX3tbd", - "ogImage": "https://uploads-ssl.webflow.com/6320eecd0f98b4666b218021/635bd4c7c5a75162302a70a4_ms6lYn6g_400x400.jpg", - "shortDescription": "Parcl is an investment protocol that allows users to trade the price movements of real estate markets around the world. ", - + "bannerImage": "", + "displayName": "Parcl DAO", + "programId": "Di9ZVJeJrRZdQEWzAFYmfjukjR5dUQb7KMaDmv34rNJg", + "realmId": "9Waj7NNTzEhyHf1j1F36xgtnXaLoAxVBFhf6VxE9fgaf", + "ogImage": "https://ipfs.filebase.io/ipfs/QmVDpnYjKMCBdmqGddQNyW8cc3tBU5cKZFiSV5y18J5YnK", + "shortDescription": "Parcl is an investment protocol that allows users to trade the price movements of real estate markets around the world.", "website": "https://parcl.co", "twitter": "@parcl", "discord": "http://discord.gg/parcl", @@ -3238,6 +3251,45 @@ "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": "PAWNGO", + "displayName": "Pawngo DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "shortDescription": "A very good girl.", + "discord": "https://discord.gg/Td7QFn2ePz", + "bannerImage": "/realms/PAWNGO/img/pawngodao.png", + "category": "Memecoin", + "sortRank": 3, + "realmId": "2cS5Epb9b1hGifzWi6iYmpHbNueM9FReh8kqNaKrcTFJ", + "twitter": "@pawnspl24", + "ogImage": "/realms/PAWNGO/img/pawngo.png" + }, + { + "symbol": "GCDC", + "displayName": "Gay Coinz DAO Coin", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "shortDescription": "We're gonna need a bigger tote!", + "discord": "", + "bannerImage": "/realms/GCDC/img/gaycoinz-banner.png", + "category": "Web3", + "sortRank": 3, + "realmId": "5aXNavdJkzp8j2kPbvQbf15kmxdqJgjXJ8CqJ4S1ZTpG", + "twitter": "", + "ogImage":"/realms/GCDC/img/gaycoinz-logo.png" + }, { "symbol": "COMRADE", "displayName": "ComradeDAO", @@ -3393,5 +3445,255 @@ "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": "" + }, + { + "symbol": "sinDAO", + "displayName": "sinDAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "7boMaQ9LG3eHXEsiWWWs7RDP2Z8ASJ3wJevTmuTh1qhL", + "ogImage": "/realms/sinDAO/sindao.png", + "website": "https://sindao.org", + "twitter": "@thesinDAO" + }, + { + "symbol": "TNSR", + "category": "NFT", + "bannerImage": "https://i.imgur.com/PMLtfh6.png", + "displayName": "Tensor DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "4sgAydAiSvnpT73rALCcnYGhi5K2LrB9pJFAEbLMfrXt", + "communityMint": "TNSRxcUxoT9xBG3de7PiJyTDYu7kskLqcpddxnEJAS6", + "ogImage": "https://i.imgur.com/IP2FsY7.png", + "shortDescription": "Future of NFT trading. Built on Solana.", + "website": "https://www.tensor.foundation", + "keywords": "Tensor, REALM, Governance, TNSR, Tensor NFT Marketplace, NFT, Crypto, Solana, SOL, Trading, Fastest, Fast", + "twitter": "@TensorFdn", + "discord": "https://discord.gg/a8spfqxEpC", + "github": "https://github.com/tensor-foundation" + }, + { + "symbol": "Jito", + "displayName": "Jito", + "programId": "jtogvBNH3WBSWDYD5FJfQP2ZxNTuf82zL8GkEhPeaJx", + "realmId": "jjCAwuuNpJCNMLAanpwgJZ6cdXzLPXe2GfD6TaDQBXt", + "ogImage": "/realms/Jito/jito.png", + "website": "https://jito.network", + "twitter": "@jito_sol" + }, + { + "symbol": "FIM", + "category": "defi", + "bannerImage": "/realms/FinanceIsMagic/Banner.png", + "displayName": "Finance Is Magic", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "JCv4VFAMUrwwGfjnRsS2DmujNEEfNs9KT3jentpQYnsg", + "communityMint": "64pwL5YCL1ctSVUpNsBAsw7V6ZPiZmrEJ1dNhdsQwKx2", + "ogImage": "/realms/FinanceIsMagic/Logo.png", + "shortDescription": "DeFi magic with memecoins and liquidity.", + "website": "https://fimcoin.com", + "keywords": "DeFi, REALM, Governance, FIM, Decentralized Finance, Crypto, Decentralize, Solana, SOL, SPL, Cross-Chain, Trading, SPL Tokens", + "twitter": "@financeismagic" + }, + { + "symbol": "KING", + "displayName": "Mewfasa DAO", + "category": "web3", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "2Gn1tf4WyFv8tk4kzd7GZCrw44P5d3mq6qEzjWyq159H", + "bannerImage": "/realms/MewfasaDAO/banner-dao.jpg", + "ogImage": "/realms/MewfasaDAO/mewfasadao.jpg", + "twitter": "@MewfasaK53969", + "website": "https://mewfasa.fun/", + "shortDescription": "Mewfasa - The Lion Cat King", + "keywords": "Web3, Governance, Community, Solana" + }, + { + "symbol": "DRIFT", + "bannerImage": "https://i.imgur.com/b9pPf3S.png", + "displayName": "Drift Protocol", + "programId": "dgov7NC8iaumWw3k8TkmLDybvZBCmd1qwxgLAGAsWxf", + "realmId": "FVVXu18aNUqyFCfq8sGktPM62mqJAGaenv4z6UGUs5em", + "ogImage": "https://i.imgur.com/HnF1Zzy.png", + "shortDescription": "A lightning-fast and scalable perpetual futures DEX.", + "sortRank": 4, + "website": "https://www.drift.trade/", + "twitter": "@DriftProtocol", + "discord": "http://discord.com/invite/drifting", + "github": "https://github.com/drift-labs/protocol-v2" + }, + { + "symbol": "GREED", + "displayName": "The $GREED Experiment", + "programId": "GovRp7uazvmYkQ7gqjdfjKFwr6pHDcYFWH3SP9DHzdtR", + "realmId": "8KG5Z3thhSwQCVWdnNdPZV5JQJya2gNaBELjLA8xhEcs", + "ogImage": "https://cdn.blastctrl.com/greed/dao_logo.png", + "bannerImage": "https://cdn.blastctrl.com/greed/dao_banner.png", + "website": "https://x.com/voshy", + "twitter": "@voshy" + }, + { + "symbol": "GUAC", + "displayName": "The Guacamole AvocaDAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "Ha56K8MGrJuiJSyK2UaYRpAf7Hu2BZw2XALEmW9EQemu", + "ogImage": "/realms/Guacamole/Guacamole_Token_Logo_Green.png", + "bannerImage": "/realms/Guacamole/Guacamole_Banner.png", + "website": "https://guac.gg", + "twitter": "@guac_gg" + }, + { "symbol": "Advocat", + "displayName": "Advocat DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "FDZPbcWoPfeVZxKev7syLPA7RNiEbK8wW5upW7KnMcSY", + "ogImage": "/realms/Advocat/logo.png", + "bannerImage": "/realms/Advocat/AdvocatBusiness.png", + "website": "https://advocat.live", + "twitter": "@notacatcoin" + }, + { + "symbol": "FOXTAG", + "displayName": "$SOLFOX Official DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "8PzqFQWeiyQLAtiDG4GV8bmS1YDCM7xy6SNz1eMsiw8A", + "ogImage": "/realms/FOXTAG/FOXTAG.png", + "website": "https://solfoxlegion.com", + "twitter": "@solfoxlegion" + }, + { + "symbol": "LABS", + "category": "defi", + "bannerImage": "/realms/EpicentralLabsDAO/EpicentralDAOBanner.png", + "displayName": "EpicentralDAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "5PP7vKjJyLw1MR55LoexRsCj3CpZj9MdD6aNXRrvxG42", + "communityMint": "LABSh5DTebUcUbEoLzXKCiXFJLecDFiDWiBGUU1GpxR", + "ogImage": "/realms/EpicentralLabsDAO/Epicentral-Labs-Logo.png", + "shortDescription": "Epicentral Labs introduces innovative solutions and services for new or already existing Solana-based projects with the main goal to connect, collaborate, and educate today's webspace with how blockchain can immerse user experience.", + "website": "https://epicentrallabs.com/", + "keywords": "Epicentral Labs, REALM, Governance, DEFI, Decentralized Finance, Developer Tooling, Crypto, Solana, Ethereum, Decentralize, Community, SOL, SPL, Integrated, Trading, Infrastructure, SPL Tokens", + "twitter": "@EpicentralLabs", + "discord": "https://discord.gg/5asAuY2sR8", + "github": "https://github.com/EpicentralLabs" + }, + { + "symbol": "COAL", + "bannerImage": "/realms/CoalitionDAO/banner.png", + "displayName": "CoalitionDAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "4HRDvxcErtP4MxWqpmem7CfwGU9LbYfJd9JCNz5s5RTd", + "communityMint": "E3yUqBNTZxV8ELvW99oRLC7z4ddbJqqR4NphwrMug9zu", + "ogImage": "/realms/CoalitionDAO/logo.png", + "shortDescription": "A coalition of miners and engineers.", + "website": "https://coal.digital/", + "keywords": "Proof of work, Crypto mining, Community, Governance, Solana", + "twitter": "@coalonsolana", + "discord": "https://discord.gg/WJVYcHHGHr", + "github": "https://github.com/coal-digital" + }, + { + "symbol": "JETSKI", + "bannerImage": "/realms/JetSkiDAO/banner.png", + "displayName": "JetSki DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "FEPMbc7rB8BF3anr9eHHfi2VeZKnCdWKWZW9guu3oxuT", + "communityMint": "E7saHtwrZ3i6QNNB15Kq4R8e4mLz5J5XMtJybHNhpump", + "ogImage": "/realms/JetSkiDAO/logo.jpeg", + "shortDescription": "The first community managed basket DAO on Solana.", + "website": "https://deanslistdao.notion.site/JetSki-DAO-380d86533e154e4c8bbd66a11c54194f", + "twitter": "@JetSkiDAO", + "telegram": "https://t.me/+mlW159EpFtY1N2U0D" + }, + { + "symbol": "IKB", + "bannerImage": "/realms/IKB/ikb_dao_banner.jpg", + "displayName": "International Klein Blue DAO", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "6Tae5nNMnyNpCqrBMHoyNVVRdbYkwnvL9EgzQkin9aHN", + "communityMint": "F7viRR7XKFeDxMG441DC1KDZu8cFjPvGFF6tnKYNVvFc", + "ogImage": "/realms/IKB/ikb_dao_logo.jpg", + "shortDescription": "The first modern art meme token. The IKB DAO federates $IKB token holders, enabling them to collaborate to perform experiments and to support the art community.", + "keywords": "blue, International Klein Blue, art, modern art, artmeme, meme, art community, art experiments", + "website": "https://ikb-token.co", + "twitter": "@ikb_token", + "telegram": "https://t.me/+8Fzp2CFx2yZiMDI5" + }, + { + "symbol": "MRGY", + "displayName": "Mergey", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "GgXxU6HPCMFmwYkuFdbkm8QAvVhWiexraZAy9CX4CYRU", + "communityMint": "4i1ZW16fF5EHunJ9hCV4nqz9ckmeM6hg11BREy5x2Knw", + "ogImage": "/realms/mergey/logo.png", + "shortDescription": "Acquire. Merge. Divest. Permissionless memecoin M&A on Solana.", + "website": "https://mergey.fun", + "twitter": "@mergeydotfun", + "telegram": "https://t.me/+vUtROD2-n_4xNzZh" + }, + { + "symbol": "PIBBLE", + "bannerImage": "/realms/PibbleDAO/Banner.png", + "displayName": "Pibble's Treats", + "programId": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "realmId": "GqPQwmN6VdqPEez9MrHCwLGfjy8z7g1fe432thRBrpLL", + "communityMint": "6qoHodWitraGtWFiLEvUZPz9THQt2vUJzV9Xd68ykAYP", + "ogImage": "/realms/PibbleDAO/logo.png", + "website": "https://pibble.xyz", + "twitter": "@PibbleSolana" } -] + ] diff --git a/public/realms/mergey/logo.png b/public/realms/mergey/logo.png new file mode 100644 index 0000000000..e0f64a8935 Binary files /dev/null and b/public/realms/mergey/logo.png differ diff --git a/public/realms/pumpkinspool/pumpkin_header.png b/public/realms/pumpkinspool/pumpkin_header.png new file mode 100644 index 0000000000..0017c2bb15 Binary files /dev/null and b/public/realms/pumpkinspool/pumpkin_header.png differ diff --git a/public/realms/pumpkinspool/pumpkin_logo_cropped.png b/public/realms/pumpkinspool/pumpkin_logo_cropped.png new file mode 100644 index 0000000000..6b0c0cca3f Binary files /dev/null and b/public/realms/pumpkinspool/pumpkin_logo_cropped.png differ diff --git a/public/realms/sinDAO/sindao.png b/public/realms/sinDAO/sindao.png new file mode 100644 index 0000000000..43294212d0 Binary files /dev/null and b/public/realms/sinDAO/sindao.png differ diff --git a/stores/useGovernanceAssetsStore.tsx b/stores/useGovernanceAssetsStore.tsx index d8eff6e898..7660794963 100644 --- a/stores/useGovernanceAssetsStore.tsx +++ b/stores/useGovernanceAssetsStore.tsx @@ -28,10 +28,10 @@ import { getMultipleAccountInfoChunked, MintAccount, parseMintAccountData, - parseTokenAccountData, TokenAccount, TokenProgramAccount, } from '@utils/tokens' +import { parseTokenAccountData } from '@utils/parseTokenAccountData' import tokenPriceService from '@utils/services/tokenPrice' import { ConnectionContext } from '@utils/connection' import { @@ -57,6 +57,7 @@ const additionalPossibleMintAccounts = { new PublicKey('EGk8Gw7Z484mzAKb7GwCcqrZd4KwwsyU2Dv9woY6uDQu'), new PublicKey('8gjzxiqcU87cvRc7hFiUJgxqLSV7AQnSttfWC5fD9aim'), new PublicKey('G1Yc5696GcfL28uAWG6iCaKJwZd8sQzwPJTc2UacsjHN'), + new PublicKey('oW7juZxrhaGvWw5giRp3P3qTHEZpg2t8n8aXTCpBjNK'), ], } const tokenAccountOwnerOffset = 32 @@ -179,7 +180,7 @@ const useGovernanceAssetsStore = create((set, _get) => ({ const stakeAccounts = await loadStakeAccounts( connection, governedTokenAccounts.filter( - (x) => x.isSol && x.extensions.solAccount?.lamports + (x) => x.isSol ) ) accounts.push(...stakeAccounts) diff --git a/stores/useNotificationStore.tsx b/stores/useNotificationStore.tsx index a4a891d399..e81de5fb6e 100644 --- a/stores/useNotificationStore.tsx +++ b/stores/useNotificationStore.tsx @@ -10,13 +10,6 @@ interface NotificationStore extends State { txid?: string }> set: (x: any) => void - modalState: ModalStates -} - -export enum ModalStates { - Selection = 1, - Dialect = 2, - Notifi = 3, } const useNotificationStore = create( @@ -24,7 +17,6 @@ const useNotificationStore = create( (set, _get) => ({ notifications: [], set: (fn) => set(produce(fn)), - modalState: ModalStates.Selection, }), { name: 'notifications', diff --git a/stores/useVotePluginsClientStore.tsx b/stores/useVotePluginsClientStore.tsx deleted file mode 100644 index d22261a98d..0000000000 --- a/stores/useVotePluginsClientStore.tsx +++ /dev/null @@ -1,254 +0,0 @@ -import create, { State } from 'zustand' -import { GatewayClient } from '@solana/governance-program-library' -import { getRegistrarPDA, Registrar } from 'VoteStakeRegistry/sdk/accounts' -import { getRegistrarPDA as getPluginRegistrarPDA } from '@utils/plugin/accounts' -import { AnchorProvider, Wallet } from '@coral-xyz/anchor' -import { - tryGetNftRegistrar, - tryGetRegistrar, - tryGetHeliumRegistrar, -} from 'VoteStakeRegistry/sdk/api' -import { SignerWalletAdapter } from '@solana/wallet-adapter-base' -import { ConnectionContext } from '@utils/connection' -import { ProgramAccount, Realm } from '@solana/spl-governance' -import { VotingClient, VotingClientProps } from '@utils/uiTypes/VotePlugin' -import { PublicKey } from '@solana/web3.js' -import { tryGetGatewayRegistrar } from '../GatewayPlugin/sdk/api' -import { VsrClient } from 'VoteStakeRegistry/sdk/client' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' -import { Registrar as HeliumVsrRegistrar } from 'HeliumVotePlugin/sdk/types' -import * as heliumVsrSdk from '@helium/voter-stake-registry-sdk' -import { NftVoterClient } from '@utils/uiTypes/NftVoterClient' -import { StakeConnection as PythClient } from '@pythnetwork/staking' - -interface UseVotePluginsClientStore extends State { - state: { - //diffrent plugins to choose because we will still have functions related only to one plugin - vsrClient: VsrClient | undefined - heliumVsrClient: HeliumVsrClient | undefined - nftClient: NftVoterClient | undefined - gatewayClient: GatewayClient | undefined - pythClient: PythClient | undefined - nftMintRegistrar: any - gatewayRegistrar: any - currentRealmVotingClient: VotingClient - voteStakeRegistryRegistrar: Registrar | null - voteStakeRegistryRegistrarPk: PublicKey | null - heliumVsrRegistrar: HeliumVsrRegistrar | null - maxVoterWeight: PublicKey | undefined - } - handleSetVsrClient: ( - wallet: SignerWalletAdapter | undefined, - connection: ConnectionContext, - programId: PublicKey - ) => void - handleSetHeliumVsrClient: ( - wallet: SignerWalletAdapter | undefined, - connection: ConnectionContext, - programId: PublicKey - ) => void - handleSetNftClient: ( - wallet: SignerWalletAdapter | undefined, - connection: ConnectionContext - ) => void - handleSetGatewayClient: ( - wallet: SignerWalletAdapter | undefined, - connection: ConnectionContext - ) => void - handleSetVsrRegistrar: ( - client: VsrClient, - realm: ProgramAccount | undefined - ) => void - handleSetHeliumVsrRegistrar: ( - client: HeliumVsrClient, - realm: ProgramAccount | undefined - ) => void - handleSetNftRegistrar: ( - client: NftVoterClient, - realm: ProgramAccount | undefined - ) => void - handleSetGatewayRegistrar: ( - client: GatewayClient, - realm: ProgramAccount | undefined - ) => void - handleSetCurrentRealmVotingClient: ({ - client, - realm, - walletPk, - }: VotingClientProps) => void - handleSetPythClient: ( - wallet: SignerWalletAdapter | undefined, - connection: ConnectionContext - ) => void -} - -const defaultState = { - vsrClient: undefined, - heliumVsrClient: undefined, - nftClient: undefined, - gatewayClient: undefined, - pythClient: undefined, - voteStakeRegistryRegistrar: null, - heliumVsrRegistrar: null, - voteStakeRegistryRegistrarPk: null, - nftMintRegistrar: null, - gatewayRegistrar: null, - currentRealmVotingClient: new VotingClient({ - client: undefined, - realm: undefined, - walletPk: undefined, - }), - maxVoterWeight: undefined, -} - -const useVotePluginsClientStore = create( - (set, _get) => ({ - state: { - ...defaultState, - }, - handleSetVsrClient: async (wallet, connection, programId) => { - const options = AnchorProvider.defaultOptions() - const provider = new AnchorProvider( - connection.current, - (wallet as unknown) as Wallet, - options - ) - const vsrClient = await VsrClient.connect( - provider, - programId, - connection.cluster === 'devnet' - ) - set((s) => { - s.state.vsrClient = vsrClient - }) - }, - handleSetHeliumVsrClient: async (wallet, connection, programId) => { - const options = AnchorProvider.defaultOptions() - const provider = new AnchorProvider( - connection.current, - (wallet as unknown) as Wallet, - options - ) - - const heliumVsrClient = await HeliumVsrClient.connect( - provider, - programId, - connection.cluster === 'devnet' - ) - - set((s) => { - s.state.heliumVsrClient = heliumVsrClient - }) - }, - handleSetVsrRegistrar: async (client, realm) => { - console.log('setting vsr registrar') - if (realm === undefined) return - - const clientProgramId = client.program.programId - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - const existingRegistrar = await tryGetRegistrar(registrar, client) - set((s) => { - s.state.voteStakeRegistryRegistrar = existingRegistrar - s.state.voteStakeRegistryRegistrarPk = registrar - }) - }, - handleSetHeliumVsrRegistrar: async (client, realm) => { - if (realm === undefined) return - - const clientProgramId = client.program.programId - const [registrar] = heliumVsrSdk.registrarKey( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - - const existingRegistrar = await tryGetHeliumRegistrar(registrar, client) - - set((s) => { - s.state.heliumVsrRegistrar = existingRegistrar as HeliumVsrRegistrar - s.state.voteStakeRegistryRegistrarPk = registrar - }) - }, - handleSetNftClient: async (wallet, connection) => { - const options = AnchorProvider.defaultOptions() - const provider = new AnchorProvider( - connection.current, - (wallet as unknown) as Wallet, - options - ) - const nftClient = await NftVoterClient.connect( - provider, - connection.cluster === 'devnet' - ) - set((s) => { - s.state.nftClient = nftClient - }) - }, - handleSetNftRegistrar: async (client, realm) => { - if (realm === undefined) return - - const clientProgramId = client.program.programId - const { registrar } = await getPluginRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - const existingRegistrar = await tryGetNftRegistrar(registrar, client) - set((s) => { - s.state.nftMintRegistrar = existingRegistrar - }) - }, - handleSetGatewayRegistrar: async (client, realm) => { - if (realm === undefined) return - - const clientProgramId = client.program.programId - const { registrar } = await getPluginRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - const existingRegistrar = await tryGetGatewayRegistrar(registrar, client) - set((s) => { - s.state.gatewayRegistrar = existingRegistrar - }) - }, - handleSetCurrentRealmVotingClient: ({ client, realm, walletPk }) => { - set((s) => { - s.state.currentRealmVotingClient = new VotingClient({ - client, - realm, - walletPk, - }) - }) - }, - handleSetGatewayClient: async (wallet, connection) => { - const options = AnchorProvider.defaultOptions() - const provider = new AnchorProvider( - connection.current, - (wallet as unknown) as Wallet, - options - ) - const gatewayClient = await GatewayClient.connect( - provider, - connection.cluster === 'devnet' - ) - set((s) => { - s.state.gatewayClient = gatewayClient - }) - }, - handleSetPythClient: async (wallet, connection) => { - if (wallet) { - const pythClient = await PythClient.connect(connection.current, wallet as unknown as Wallet) - set((s) => { - s.state.pythClient = pythClient - }) - } - }, - }) -) - -export default useVotePluginsClientStore diff --git a/styles/index.css b/styles/index.css index 0930162d18..ede89b7679 100644 --- a/styles/index.css +++ b/styles/index.css @@ -380,8 +380,19 @@ https://developer.mozilla.org/en-US/docs/Web/CSS/word-break#values */ overflow-wrap: anywhere; } +.gatewayButton > span:hover{ + @apply !text-fgd-1; +} + .gatewayButton > span { - @apply !text-bkg-2 !pl-0 !text-sm; + @apply !text-primary-light !pl-0 hover:!text-fgd-1; + margin-left: 23px; +} + +.gatewayButton > svg { + filter: brightness(0) saturate(100%) invert(71%) sepia(67%) saturate(514%) hue-rotate(161deg) brightness(97%) contrast(90%); + min-width: 24px; + padding-top: 4px; } .react-grid-item.react-grid-placeholder { @@ -398,3 +409,92 @@ https://developer.mozilla.org/en-US/docs/Web/CSS/word-break#values */ .react-resizable-handle-se::after { border-color: white !important; } + +@import url('@dialectlabs/react-ui/index.css'); + +.dialect input { + border: none; +} + +.dialect input:focus { + outline: none; + box-shadow: none; +} + +.dialect { + --dt-bg-primary: #17161c; + --dt-bg-secondary: #201f27; + --dt-bg-tertiary: #2a2d34; + --dt-bg-brand: #81ccf6; + --dt-input-primary: #40474f; + --dt-input-secondary: #17161c; + --dt-input-checked: #81ccf6; + --dt-input-unchecked: #6c727f; + --dt-input-disabled: #363d44; + --dt-button-primary: #81ccf6; + --dt-button-primary-hover: #81ccf6; + --dt-button-primary-disabled: #81ccf6; + --dt-button-secondary: #201f27; + --dt-button-secondary-hover: #2a2d34; + --dt-button-secondary-disabled: #201f27; + --dt-text-primary: #ffffff; + --dt-text-secondary: #d6d6d6; + --dt-text-tertiary: #b3b7bd; + --dt-text-quaternary: #7a7a7a; + --dt-text-inverse: #101010; + --dt-text-accent: #81ccf6; + --dt-stroke-primary: #2a2d34; + --dt-icon-primary: #fcfcfc; + --dt-icon-secondary: #6c727f; + --dt-icon-tertiary: #6c727f; + --dt-icon-inverse: #17161c; + --dt-accent-brand: #81ccf6; + --dt-accent-success: #30c89a; + --dt-accent-warning: #f7a531; + --dt-accent-error: #ff5353; + --dt-brand-transparent: #00e4ff1a; + --dt-success-transparent: #30c89a1a; + --dt-warning-transparent: #f7a5311a; + --dt-error-transparent: #e540331a; +} + +:root[data-theme='Light'] .dialect { + --dt-bg-primary: #fcfcfc; + --dt-bg-secondary: #f0f0f0; + --dt-bg-tertiary: #f0f0f0; + --dt-bg-brand: #42bae1; + --dt-input-primary: #d6d6d6; + --dt-input-secondary: #fcfcfc; + --dt-input-checked: #42bae1; + --dt-input-unchecked: #adadad; + --dt-input-disabled: #b3b7bd; + --dt-button-primary: #42bae1; + --dt-button-primary-hover: #42bae1; + --dt-button-primary-disabled: #42bae1; + --dt-button-secondary: #e0e0e0; + --dt-button-secondary-hover: #d6d6d6; + --dt-button-secondary-disabled: #f0f0f0; + --dt-text-primary: #17161c; + --dt-text-secondary: #2f343a; + --dt-text-tertiary: #7a7a7a; + --dt-text-quaternary: #adadad; + --dt-text-inverse: #ffffff; + --dt-text-accent: #42bae1; + --dt-stroke-primary: #e0e0e0; + --dt-icon-primary: #ffffff; + --dt-icon-secondary: #adadad; + --dt-icon-tertiary: #adadad; + --dt-icon-inverse: #ffffff; + --dt-accent-brand: #42bae1; + --dt-accent-success: #6cbf00; + --dt-accent-warning: #f48f25; + --dt-accent-error: #e54033; + --dt-brand-transparent: #00e4ff1a; + --dt-success-transparent: #6cbf001a; + --dt-warning-transparent: #f7a5311a; + --dt-error-transparent: #e540331a; +} + +.dialect > div > button { + border-radius: 999px !important; +} diff --git a/test/tools/validators/pubkey.test.ts b/test/tools/validators/pubkey.test.ts deleted file mode 100644 index 353f53ea59..0000000000 --- a/test/tools/validators/pubkey.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { tryParseDomain } from '@tools/validators/pubkey' - -describe('Public Key Resolves ', () => { - const domain = 'realms.sol' - const pubkey = '8aHFSYp3K2X2qEfUqQhfCuCHvjDumdiMzfCyrJhdJxmQ' - - test('domains to publicKey', async () => { - const resolvedKey = await tryParseDomain(domain) - expect(resolvedKey?.toBase58()).toEqual(pubkey) - }) -}) diff --git a/tools/feeEstimate.ts b/tools/feeEstimate.ts index 0c79d874f8..3227c6cd70 100644 --- a/tools/feeEstimate.ts +++ b/tools/feeEstimate.ts @@ -1,5 +1,6 @@ import { Connection, + LAMPORTS_PER_SOL, PublicKey, RecentPrioritizationFees, } from '@solana/web3.js' @@ -7,7 +8,7 @@ import { getClient, getGroupForClient } from '@utils/mangoV4Tools' import { groupBy, mapValues, maxBy, sampleSize } from 'lodash' export const getFeeEstimate = async (connection: Connection) => { - const defaultFee = 5000 + const defaultFee = 50000 try { //Use mango client to find good fee const MAINNET_MANGO_GROUP = new PublicKey( @@ -16,7 +17,7 @@ export const getFeeEstimate = async (connection: Connection) => { const MAX_PRIORITY_FEE_KEYS = 128 const client = await getClient(connection) const group = await getGroupForClient(client, MAINNET_MANGO_GROUP) - const feeMultiplier = 1.2 + const feeMultiplier = 2 const altResponse = await connection.getAddressLookupTable( group.addressLookupTables[0] ) @@ -48,7 +49,8 @@ export const getFeeEstimate = async (connection: Connection) => { recentFees[mid].prioritizationFee) / 2 const feeEstimate = Math.ceil(medianFee * feeMultiplier) - return feeEstimate + + return Math.min(feeEstimate, LAMPORTS_PER_SOL * 0.001) } catch (e) { return defaultFee } diff --git a/tools/governance/prepareRealmCreation.ts b/tools/governance/prepareRealmCreation.ts index 0f4951d71b..7a616076d2 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 = { @@ -79,6 +79,8 @@ type RealmCreationV3 = { export type RealmCreation = RealmCreationV2 | RealmCreationV3 +export const DEFAULT_MINT_DECIMALS = 6; + export async function prepareRealmCreation({ connection, wallet, @@ -146,7 +148,7 @@ export async function prepareRealmCreation({ ? (await fetchMintInfoByPubkey(connection, existingCouncilMintPk)).result : undefined - const communityMintDecimals = existingCommunityMint?.decimals || 6 + const communityMintDecimals = existingCommunityMint?.decimals || DEFAULT_MINT_DECIMALS const communityMaxVoteWeightSource = parseMintMaxVoteWeight( useSupplyFactor, @@ -234,6 +236,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 @@ -267,6 +270,12 @@ export async function prepareRealmCreation({ params._programVersion === 3 ? params.councilTokenConfig : undefined ) + const doesRealmExist = await connection.getAccountInfo(realmPk) + + if (doesRealmExist?.data) { + throw new Error('Realm with the same name already exists.') + } + console.log('Prepare realm - council members', councilWalletPks) for (const teamWalletPk of councilWalletPks) { // In version 3 we just deposit council tokens directly into the DAO diff --git a/tools/routing.ts b/tools/routing.ts index 2ad2cc1a05..fe218f958b 100644 --- a/tools/routing.ts +++ b/tools/routing.ts @@ -3,5 +3,5 @@ import { RealmInfo } from 'models/registry/api' export function getRealmExplorerHost(realmInfo: RealmInfo | undefined) { return realmInfo?.symbol === 'MNGO' ? 'dao.mango.markets' - : 'realms-explorer.com' + : 'solscan.io' } diff --git a/utils/Foresight/index.tsx b/utils/Foresight/index.tsx deleted file mode 100644 index 014f74f066..0000000000 --- a/utils/Foresight/index.tsx +++ /dev/null @@ -1,422 +0,0 @@ -import _ from 'lodash' -import useGovernanceAssets from '@hooks/useGovernanceAssets' -import { - governance as foresightGov, - consts as foresightConsts, -} from '@foresight-tmp/foresight-sdk' -import { isFormValid } from '@utils/formValidation' -import { AssetAccount } from '@utils/uiTypes/assets' -import { - Governance, - ProgramAccount, - serializeInstructionToBase64, -} from '@solana/spl-governance' -import GovernedAccountSelect from '../../pages/dao/[symbol]/proposal/components/GovernedAccountSelect' -import { Dispatch, useContext, useEffect, useState } from 'react' -import { - ForesightHasCategoryId, - ForesightHasGovernedAccount, - ForesightHasMarketId, - ForesightHasMarketListId, - ForesightMakeResolveMarketParams, - ForesightMakeSetMarketMetadataParams, - UiInstruction, -} from '@utils/uiTypes/proposalCreationTypes' -import Input from '@components/inputs/Input' -import { SignerWalletAdapter } from '@solana/wallet-adapter-base' -import { PublicKey, TransactionInstruction } from '@solana/web3.js' -import * as yup from 'yup' -import { ObjectSchema, StringSchema, NumberSchema } from 'yup' -import useRealm from '@hooks/useRealm' -import { NewProposalContext } from '../../pages/dao/[symbol]/proposal/new' -import Select from '@components/inputs/Select' -import TextareaProps from '@components/inputs/Textarea' -import useWalletOnePointOh from '@hooks/useWalletOnePointOh' - -type EmptyObject = Record -type SetFormErrors = Dispatch> - -function getFilteredTokenAccounts(): AssetAccount[] { - // eslint-disable-next-line react-hooks/rules-of-hooks -- TODO this is potentially quite serious! please fix next time the file is edited, -@asktree - const { governedTokenAccountsWithoutNfts } = useGovernanceAssets() - return governedTokenAccountsWithoutNfts.filter((x) => { - const transferAddress = x.extensions.transferAddress - return ( - transferAddress?.equals(foresightGov.DEVNET_TREASURY) || - transferAddress?.equals(foresightGov.MAINNET_TREASURY) - ) - }) -} - -type HandleSetForm = ({ - propertyName, - value, -}: { - propertyName: string - value: any -}) => void - -type HandleSetInstructions = ( - val: { - governedAccount: ProgramAccount | undefined - getInstruction: GetInstruction - }, - index: number -) => void - -function makeValidateInstruction( - schema: ObjectSchema, - form: ForesightHasGovernedAccount, - setFormErrors: SetFormErrors -): () => Promise { - async function validateInstruction(): Promise { - const { isValid, validationErrors } = await isFormValid(schema, form) - setFormErrors(validationErrors) - return isValid - } - return validateInstruction -} - -function makeHandleSetFormWithErrors( - form: T, - setForm: Dispatch>, - setFormErrors: SetFormErrors -): HandleSetForm { - function handleSetForm({ - propertyName, - value, - }: { - propertyName: string - value: any - }) { - setFormErrors({}) - setForm({ ...form, [propertyName]: value }) - } - return handleSetForm -} - -type GetInstruction = () => Promise - -type IxCreator = ( - form: T -) => Promise - -function makeGetInstruction( - ixCreator: IxCreator, - form: T, - programId: PublicKey | undefined, - wallet: SignerWalletAdapter | undefined, - schema: ObjectSchema, - setFormErrors: SetFormErrors -): GetInstruction { - const validateInstruction = makeValidateInstruction( - schema, - form, - setFormErrors - ) - async function getInstruction(): Promise { - const isValid = await validateInstruction() - let serializedInstruction = '' - if (isValid && programId && wallet?.publicKey) { - const ix = await ixCreator(form) - serializedInstruction = serializeInstructionToBase64(ix) - } - return getUiInstruction(serializedInstruction, isValid, form) - } - return getInstruction -} - -type NonDefault = Omit< - T, - 'governedAccount' -> -type ValueOf = T[keyof T] -type AllowedSchema = NumberSchema | StringSchema - -function defaultValToYupSchema( - val: ValueOf> -): AllowedSchema { - if (typeof val === 'number') { - return yup.number().required() - } - return yup.string().required() -} - -type formEntryToSchema = { - [name in keyof NonDefault]: AllowedSchema -} - -export function commonAssets( - formDefaults: NonDefault, - index: number, - governance: ProgramAccount | null -): { - inputProps: InputProps - effector: (ixCreator: IxCreator) => void - governedAccountSelect: JSX.Element - wallet: SignerWalletAdapter | undefined -} { - const extraSchemaFields: formEntryToSchema = _.mapValues( - formDefaults, - defaultValToYupSchema - ) - const schema = getSchema(extraSchemaFields) - // eslint-disable-next-line react-hooks/rules-of-hooks -- TODO this is potentially quite serious! please fix next time the file is edited, -@asktree - const wallet = useWalletOnePointOh() - const filteredTokenAccounts = getFilteredTokenAccounts() - // eslint-disable-next-line react-hooks/rules-of-hooks -- TODO this is potentially quite serious! please fix next time the file is edited, -@asktree - const [formErrors, setFormErrors] = useState({}) - // eslint-disable-next-line react-hooks/rules-of-hooks -- TODO this is potentially quite serious! please fix next time the file is edited, -@asktree - const { handleSetInstructions } = useContext(NewProposalContext) - // eslint-disable-next-line react-hooks/rules-of-hooks -- TODO this is potentially quite serious! please fix next time the file is edited, -@asktree - const [form, setForm] = useState({ - governedAccount: filteredTokenAccounts[0], - ...formDefaults, - } as T) - const handleSetForm = makeHandleSetFormWithErrors( - form, - setForm, - setFormErrors - ) - const inputProps = { - form, - handleSetForm, - formErrors, - } - function effector(ixCreator: IxCreator): void { - ForesightUseEffects( - handleSetForm, - form, - handleSetInstructions, - ixCreator, - wallet, - schema, - setFormErrors, - index - ) - } - const governedAccountSelect = ( - - ) - return { - inputProps, - effector, - governedAccountSelect, - wallet, - } -} - -function ForesightUseEffects( - handleSetForm: HandleSetForm, - form: T, - handleSetInstructions: HandleSetInstructions, - ixCreator: IxCreator, - wallet: SignerWalletAdapter | undefined, - schema: ObjectSchema, - setFormErrors: SetFormErrors, - index: number -): void { - const { realmInfo } = useRealm() - const programId: PublicKey | undefined = realmInfo?.programId - const getInstruction = makeGetInstruction( - ixCreator, - form, - programId, - wallet, - schema, - setFormErrors - ) - useEffect(() => { - handleSetForm({ - propertyName: 'programId', - value: programId?.toString(), - }) - // 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 - }, [programId]) - - 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]) -} - -function getSchema( - extraFields: { - [name in keyof Omit]: StringSchema | NumberSchema - } -) { - return yup.object().shape({ - governedAccount: yup - .object() - .nullable() - .required('Program governed account is required'), - ...extraFields, - }) -} - -function getUiInstruction( - serializedInstruction: string, - isValid: boolean, - form: ForesightHasGovernedAccount -): UiInstruction { - return { - serializedInstruction: serializedInstruction, - isValid, - governance: form.governedAccount?.governance, - } -} - -function ForesightGovernedAccountSelect(props: { - filteredTokenAccounts: AssetAccount[] - form: ForesightHasGovernedAccount - handleSetForm: HandleSetForm - index: number - governance: ProgramAccount | null -}) { - const shouldBeGoverned = !!(props.index !== 0 && props.governance) - return ( - { - props.handleSetForm({ value, propertyName: 'governedAccount' }) - }} - value={props.form.governedAccount} - shouldBeGoverned={shouldBeGoverned} - governance={props.governance} - > - ) -} - -type InputProps = { - form: T - handleSetForm: HandleSetForm - formErrors: EmptyObject -} - -export function ForesightCategoryIdInput( - props: InputProps -) { - return ( - - props.handleSetForm({ - value: evt.target.value, - propertyName: 'categoryId', - }) - } - error={props.formErrors['categoryId']} - /> - ) -} - -export function ForesightMarketListIdInput( - props: InputProps -) { - return ( - - props.handleSetForm({ - value: evt.target.value, - propertyName: 'marketListId', - }) - } - error={props.formErrors['marketListId']} - /> - ) -} - -export function ForesightMarketIdInput( - props: InputProps -) { - return ( - - props.handleSetForm({ - value: evt.target.value, - propertyName: 'marketId', - }) - } - error={props.formErrors['marketId']} - /> - ) -} - -export function ForesightWinnerInput( - props: InputProps -) { - return ( - - props.handleSetForm({ - value: evt.target.value, - propertyName: 'winner', - }) - } - error={props.formErrors['winner']} - /> - ) -} - -export function ForesightContentInput( - props: InputProps -) { - return ( - - props.handleSetForm({ - value: evt.target.value, - propertyName: 'content', - }) - } - error={props.formErrors['content']} - /> - ) -} - -export function ForesightMarketMetadataFieldSelect( - props: InputProps -) { - return ( - - ) -} diff --git a/utils/Mango/listingTools.ts b/utils/Mango/listingTools.ts index 38734dee65..a995aa4f23 100644 --- a/utils/Mango/listingTools.ts +++ b/utils/Mango/listingTools.ts @@ -4,6 +4,7 @@ import { I80F48, OPENBOOK_PROGRAM_ID, RouteInfo, + USDC_MINT, toNative, toUiDecimals, toUiDecimalsForQuote, @@ -14,11 +15,8 @@ import { 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' import { Market } from '@project-serum/serum' import { PythHttpClient, parsePriceData } from '@pythnetwork/client' import { @@ -30,6 +28,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' @@ -47,7 +46,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 @@ -61,6 +60,7 @@ export type FlatListingArgs = { maintLiabWeight: number initLiabWeight: number liquidationFee: number + platformLiquidationFee: number minVaultToDepositsRatio: number netBorrowLimitPerWindowQuote: number netBorrowLimitWindowSizeTs: number @@ -80,6 +80,9 @@ export type FlatListingArgs = { interestCurveScaling: number setFallbackOracle: boolean maintWeightShiftAbort: boolean + zeroUtilRate: number + disableAssetLiquidation: boolean + collateralFeePerDay: number } export type FlatEditArgs = { @@ -100,6 +103,7 @@ export type FlatEditArgs = { maintLiabWeightOpt: number initLiabWeightOpt: number liquidationFeeOpt: number + platformLiquidationFeeOpt: number minVaultToDepositsRatioOpt: number netBorrowLimitPerWindowQuoteOpt: number netBorrowLimitWindowSizeTsOpt: number @@ -123,13 +127,18 @@ export type FlatEditArgs = { maintWeightShiftAbort: boolean setFallbackOracle: boolean depositLimitOpt: number + zeroUtilRateOpt: number + disableAssetLiquidationOpt: boolean + collateralFeePerDayOpt: number + forceWithdrawOpt: boolean + forceCloseOpt: boolean } export type ListingArgsFormatted = { tokenIndex: number tokenName: string oracleConfidenceFilter: string - oracleMaxStalenessSlots: number + oracleMaxStalenessSlots: number | null interestRateUtilizationPoint1: string interestRateUtilizationPoint0: string interestRatePoint0: string @@ -143,6 +152,7 @@ export type ListingArgsFormatted = { maintLiabWeight: string initLiabWeight: string liquidationFee: string + platformLiquidationFee: string minVaultToDepositsRatio: string netBorrowLimitPerWindowQuote: number netBorrowLimitWindowSizeTs: number @@ -153,13 +163,16 @@ export type ListingArgsFormatted = { stablePriceGrowthLimit: string tokenConditionalSwapMakerFeeRate: number tokenConditionalSwapTakerFeeRate: number - flashLoanSwapFeeRate: number + flashLoanSwapFeeRate: string reduceOnly: string oracle: string depositLimit: string interestTargetUtilization: number interestCurveScaling: number groupInsuranceFund: boolean + zeroUtilRate: string + disableAssetLiquidation: boolean + collateralFeePerDay: string } export type EditTokenArgsFormatted = ListingArgsFormatted & { @@ -169,12 +182,17 @@ export type EditTokenArgsFormatted = ListingArgsFormatted & { maintWeightShiftLiabTarget: number maintWeightShiftAbort: boolean setFallbackOracle: boolean + forceWithdraw: boolean + forceClose: boolean } 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, @@ -200,32 +218,35 @@ type ProposedListingPresets = { } export const getFormattedListingPresets = ( - isPythOracle: boolean, - currentTotalDepositsInUsdc?: number, + uiDeposits?: number, decimals?: number, tokenPrice?: number ) => { - const PRESETS = !isPythOracle - ? getSwitchBoardPresets(LISTING_PRESETS) - : getPythPresets(LISTING_PRESETS) + const PRESETS = LISTING_PRESETS const PROPOSED_LISTING_PRESETS: ProposedListingPresets = Object.keys( PRESETS ).reduce((accumulator, key) => { let adjustedPreset = PRESETS[key] - if (currentTotalDepositsInUsdc) { - adjustedPreset = getPresetWithAdjustedNetBorrows( - PRESETS[key], - currentTotalDepositsInUsdc - ) - } + try { + if (uiDeposits && tokenPrice) { + adjustedPreset = getPresetWithAdjustedNetBorrows( + PRESETS[key], + uiDeposits, + tokenPrice, + toUiDecimals(PRESETS[key].netBorrowLimitPerWindowQuote, 6) + ) + } - if (decimals && tokenPrice) { - adjustedPreset = getPresetWithAdjustedDepositLimit( - adjustedPreset, - tokenPrice, - decimals - ) + if (decimals && tokenPrice) { + adjustedPreset = getPresetWithAdjustedDepositLimit( + adjustedPreset, + tokenPrice, + decimals + ) + } + } catch (e) { + console.log(e) } accumulator[key] = transformPresetToProposed(adjustedPreset) return accumulator @@ -252,8 +273,11 @@ const fetchJupiterRoutes = async ( swapMode, }).toString() + const jupiterSwapBaseUrl = + process.env.NEXT_PUBLIC_JUPTER_SWAP_API_ENDPOINT || + 'https://quote-api.jup.ag/v6' const response = await fetch( - `https://quote-api.jup.ag/v6/quote?${paramsString}` + `${jupiterSwapBaseUrl}/quote?${paramsString}` ) const res = await response.json() @@ -269,78 +293,73 @@ const fetchJupiterRoutes = async ( } } -export const getSuggestedCoinPresetInfo = async ( - outputMint: string, - hasPythOracle: boolean -) => { +export const getSuggestedCoinPresetInfo = async (outputMint: string) => { try { - const PRESETS = !hasPythOracle - ? getSwitchBoardPresets(LISTING_PRESETS) - : getPythPresets(LISTING_PRESETS) + const PRESETS = LISTING_PRESETS const swaps = await Promise.all([ fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(250000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(100000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(20000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(10000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(5000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(1000, 6).toNumber() ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(250000, 6).toNumber(), 'ExactOut' ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(100000, 6).toNumber(), 'ExactOut' ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(20000, 6).toNumber(), 'ExactOut' ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(20000, 6).toNumber(), 'ExactOut' ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(5000, 6).toNumber(), 'ExactOut' ), fetchJupiterRoutes( - MAINNET_USDC_MINT.toBase58(), + USDC_MINT.toBase58(), outputMint, toNative(1000, 6).toNumber(), 'ExactOut' @@ -396,7 +415,7 @@ export const getSuggestedCoinPresetInfo = async ( console.log(e) return { presetKey: 'UNTRUSTED', - priceImpact: 100, + priceImpact: '100', } } } @@ -441,7 +460,7 @@ const isSwitchboardOracle = async ( const feed = feeds.find((x) => x.publicKey.equals(feedPk)) return feed - ? `https://app.switchboard.xyz/solana/mainnet-beta/feed/${feedPk.toBase58()}` + ? `https://app.switchboard.xyz/solana/mainnet/feed/${feedPk.toBase58()}` : '' } @@ -535,9 +554,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()}`) @@ -546,12 +562,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', + }) } } @@ -613,7 +643,8 @@ export const getFormattedBankValues = (group: Group, bank: Bank) => { publicKey: bank.publicKey.toBase58(), vault: bank.vault.toBase58(), oracle: bank.oracle.toBase58(), - stablePrice: group.toUiPrice( + fallbackOracle: bank.fallbackOracle.toBase58(), + stablePrice: toUiDecimals( I80F48.fromNumber(bank.stablePriceModel.stablePrice), bank.mintDecimals ), @@ -627,9 +658,9 @@ export const getFormattedBankValues = (group: Group, bank: Bank) => { stablePriceGrowthLimitsStable: ( 100 * bank.stablePriceModel.stableGrowthLimit ).toFixed(2), - loanFeeRate: (10000 * bank.loanFeeRate.toNumber()).toFixed(2), + loanFeeRate: (100 * bank.loanFeeRate.toNumber()).toFixed(2), loanOriginationFeeRate: ( - 10000 * bank.loanOriginationFeeRate.toNumber() + 100 * bank.loanOriginationFeeRate.toNumber() ).toFixed(2), collectedFeesNative: toUiDecimals( bank.collectedFeesNative.toNumber(), @@ -700,6 +731,9 @@ export const getFormattedBankValues = (group: Group, bank: Bank) => { 6 ), liquidationFee: (bank.liquidationFee.toNumber() * 100).toFixed(2), + platformLiquidationFee: ( + bank.platformLiquidationFee.toNumber() * 100 + ).toFixed(2), netBorrowLimitWindowSizeTs: secondsToHours( bank.netBorrowLimitWindowSizeTs.toNumber() ), diff --git a/utils/address.ts b/utils/address.ts index 9b2c27beab..d91ba2b143 100644 --- a/utils/address.ts +++ b/utils/address.ts @@ -1,3 +1,51 @@ -export const shortenAddress = (address: string, chars = 5): string => `${address.substring(0, chars)}...${address.substring( +import { Connection, PublicKey } from '@solana/web3.js' + +export const shortenAddress = (address: string, chars = 5): string => + `${address.substring(0, chars)}...${address.substring( address.length - chars -)}`; \ No newline at end of file + )}` + +export const genShortestUnusedSeed = async ( + connection: Connection, + basePubkey: PublicKey, + programId: PublicKey +) => { + const MAX_SEED_LEN = 32 + const ASCII_MAX = 127 + let len = 1 + // find the smallest available seed to optimize for small tx size + while (len <= MAX_SEED_LEN) { + const codes = new Array(len).fill(0) + while (!codes.every((c) => c === ASCII_MAX)) { + // check current seed unused + const seed = String.fromCharCode(...codes) + // eslint-disable-next-line no-await-in-loop + const derived = await PublicKey.createWithSeed( + basePubkey, + seed, + programId + ) + // eslint-disable-next-line no-await-in-loop + const balance = await connection.getBalance(derived) + if (balance === 0) { + return { + base: basePubkey, + derived, + seed, + } + } + // current seed used, increment code + codes[codes.length - 1]++ + for (let i = codes.length - 1; i > 0; i--) { + const prevI = i - 1 + if (codes[i] > ASCII_MAX) { + codes[i] = 0 + codes[prevI]++ + } + } + } + // all seeds of current len are used + len++ + } + throw new Error('No unused seeds found') +} diff --git a/utils/connection.ts b/utils/connection.ts index 36b808f6ec..cbef2e0fd8 100644 --- a/utils/connection.ts +++ b/utils/connection.ts @@ -1,17 +1,20 @@ import type { EndpointTypes } from '@models/types' import { Connection } from '@solana/web3.js' import type { EndpointInfo } from '../@types/types' +import { DEVNET_RPC, MAINNET_RPC } from '@constants/endpoints' + +export const BACKUP_CONNECTIONS = [ + new Connection(`https://rpc.mngo.cloud/rlmk0lo5odee/`, 'recent'), +] const ENDPOINTS: EndpointInfo[] = [ { name: 'mainnet', - url: - process.env.MAINNET_RPC || - 'http://realms-realms-c335.mainnet.rpcpool.com/258d3727-bb96-409d-abea-0b1b4c48af29/', + url: MAINNET_RPC, }, { name: 'devnet', - url: process.env.DEVNET_RPC || 'https://api.dao.devnet.solana.com/', + url: DEVNET_RPC, }, { name: 'localnet', diff --git a/utils/formValidation.tsx b/utils/formValidation.tsx index 9bb8198ef4..7bbe2f6bb5 100644 --- a/utils/formValidation.tsx +++ b/utils/formValidation.tsx @@ -45,6 +45,59 @@ export const isFormValid = async (schema, formValues, abortEarly = false) => { return values } +export const isBatchFormValid = async (schema, formValues, abortEarly = false) => { + if (!schema) { + throw 'please provide schema' + } + + const values = new SanitizedObject({ + isValid: false, + validationErrors: new SanitizedObject({}), + }) as formValidation + + values.validationErrors.amount = formValues.amount.map(_ => "") + values.validationErrors.destinationAccount = formValues.destinationAccount.map(_ => "") + + try { + await schema.validate(formValues, { abortEarly }) + values.isValid = true + } catch (err) { + console.log('Validation Error', err) + + values.isValid = false + const fieldName = err.path + if ( + abortEarly && + Object.prototype.hasOwnProperty.call(schema.fields, fieldName) + ) { + values.validationErrors[fieldName] = err.errors + + } else { + err.inner?.forEach((error) => { + const fieldName = error.path + + if (fieldName.includes("amount")) { + const idx = parseInt(fieldName.replace(/^\D+/g, '')) + values.validationErrors.amount[idx] = error.message + } else if (fieldName.includes("destinationAccount")) { + const idx = parseInt(fieldName.replace(/^\D+/g, '')) + values.validationErrors.destinationAccount[idx] = error.message + } + + if ( + error.path && + Object.prototype.hasOwnProperty.call(schema.fields, fieldName) + ) { + + values.validationErrors[fieldName] = error.message + } + }) + } + } + + return values +} + export function validatePubkey(address: string) { try { new PublicKey(address) diff --git a/utils/instructionTools.ts b/utils/instructionTools.ts index 8682bff76e..213bf22098 100644 --- a/utils/instructionTools.ts +++ b/utils/instructionTools.ts @@ -20,7 +20,7 @@ import { } from '@tools/sdk/units' import { ConnectionContext } from 'utils/connection' import { getATA } from './ataTools' -import { isFormValid } from './formValidation' +import { isBatchFormValid, isFormValid } from './formValidation' import { UiInstruction } from './uiTypes/proposalCreationTypes' import { AssetAccount } from '@utils/uiTypes/assets' import { @@ -40,6 +40,16 @@ export const validateInstruction = async ({ return isValid } +export const validateBatchInstruction = async ({ + schema, + form, + setFormErrors, +}): Promise => { + const { isValid, validationErrors } = await isBatchFormValid(schema, form) + setFormErrors(validationErrors) + return isValid +} + /** @deprecated */ export async function getTransferInstruction({ schema, @@ -121,6 +131,97 @@ export async function getTransferInstruction({ return obj } +/** @deprecated */ +export async function getBatchTransferInstruction({ + schema, + form, + programId, + connection, + wallet, + currentAccount, + setFormErrors, +}: { + schema: any + form: any + programId: PublicKey | undefined + connection: ConnectionContext + wallet: WalletAdapter | undefined + currentAccount: AssetAccount | null + setFormErrors: any +}): Promise { + const isValid = await validateBatchInstruction({ schema, form, setFormErrors }) + + const ixs: { + serializedInstruction: string, + prerequisiteInstructions: TransactionInstruction[] + }[] = [] + + for (let i = 0; i < form.destinationAccount.length; i++) { + let serializedInstruction = '' + const prerequisiteInstructions: TransactionInstruction[] = [] + const governedTokenAccount = form.governedTokenAccount as AssetAccount + if ( + isValid && + programId && + governedTokenAccount.extensions?.token?.publicKey && + governedTokenAccount.extensions?.token && + governedTokenAccount.extensions?.mint?.account + ) { + const sourceAccount = governedTokenAccount.extensions.transferAddress + //this is the original owner + const destinationAccount = new PublicKey(form.destinationAccount[i]) + const mintPK = form.governedTokenAccount.extensions.mint.publicKey + const mintAmount = parseMintNaturalAmountFromDecimal( + form.amount[i]!, + governedTokenAccount.extensions.mint.account.decimals + ) + + //we find true receiver address if its wallet and we need to create ATA the ata address will be the receiver + const { currentAddress: receiverAddress, needToCreateAta } = await getATA({ + connection: connection, + receiverAddress: destinationAccount, + mintPK, + wallet: wallet!, + }) + //we push this createATA instruction to transactions to create right before creating proposal + //we don't want to create ata only when instruction is serialized + if (needToCreateAta) { + prerequisiteInstructions.push( + Token.createAssociatedTokenAccountInstruction( + ASSOCIATED_TOKEN_PROGRAM_ID, // always ASSOCIATED_TOKEN_PROGRAM_ID + TOKEN_PROGRAM_ID, // always TOKEN_PROGRAM_ID + mintPK, // mint + receiverAddress, // ata + destinationAccount, // owner of token account + wallet!.publicKey! // fee payer + ) + ) + } + + const transferIx = Token.createTransferInstruction( + TOKEN_PROGRAM_ID, + sourceAccount!, + receiverAddress, + currentAccount!.extensions!.token!.account.owner, + [], + new u64(mintAmount.toString()) + ) + serializedInstruction = serializeInstructionToBase64(transferIx) + } + ixs.push({serializedInstruction, prerequisiteInstructions}) + } + + const obj: UiInstruction[] = ixs.map(ix => ({ + serializedInstruction: ix.serializedInstruction, + isValid, + governance: currentAccount?.governance, + prerequisiteInstructions: ix.prerequisiteInstructions, + chunkBy: 4, + })) + + return obj +} + export async function getSolTransferInstruction({ schema, form, @@ -166,6 +267,63 @@ export async function getSolTransferInstruction({ return obj } +export async function getBatchSolTransferInstruction({ + schema, + form, + programId, + currentAccount, + setFormErrors, +}: { + schema: any + form: any + programId: PublicKey | undefined + connection: ConnectionContext + wallet: WalletAdapter | undefined + currentAccount: AssetAccount | null + setFormErrors: any +}): Promise { + const isValid = await validateBatchInstruction({ schema, form, setFormErrors }) + + const ixs: { + serializedInstruction: string, + prerequisiteInstructions: TransactionInstruction[] + }[] = [] + + for (let i = 0; i < form.destinationAccount.length; i++) { + let serializedInstruction = '' + const prerequisiteInstructions: TransactionInstruction[] = [] + const governedTokenAccount = form.governedTokenAccount as AssetAccount + if (isValid && programId && governedTokenAccount?.extensions.mint?.account) { + const sourceAccount = governedTokenAccount.extensions.transferAddress + const destinationAccount = new PublicKey(form.destinationAccount[i]) + //We have configured mint that has same decimals settings as SOL + const mintAmount = parseMintNaturalAmountFromDecimal( + form.amount[i]!, + governedTokenAccount.extensions.mint.account.decimals + ) + + const transferIx = SystemProgram.transfer({ + fromPubkey: sourceAccount!, + toPubkey: destinationAccount, + lamports: mintAmount, + }) + serializedInstruction = serializeInstructionToBase64(transferIx) + } + + ixs.push({serializedInstruction,prerequisiteInstructions}) + } + + const obj: UiInstruction[] = ixs.map(ix => ({ + serializedInstruction: ix.serializedInstruction, + isValid, + governance: currentAccount?.governance, + prerequisiteInstructions: ix.prerequisiteInstructions, + chunkBy: 4, + })) + + return obj +} + export async function getMintInstruction({ schema, form, diff --git a/utils/instructions/Dual/airdrop.ts b/utils/instructions/Dual/airdrop.ts index 356d15f48d..abc10b653b 100644 --- a/utils/instructions/Dual/airdrop.ts +++ b/utils/instructions/Dual/airdrop.ts @@ -10,6 +10,8 @@ import { WalletAdapter } from '@solana/wallet-adapter-base' import { Airdrop, AirdropConfigureContext } from '@dual-finance/airdrop' import { BN } from '@coral-xyz/anchor' import { getMintNaturalAmountFromDecimalAsBN } from '@tools/sdk/units' +import { TransactionInstruction } from '@solana/web3.js' +import { TOKEN_PROGRAM_ID, Token } from '@solana/spl-token' interface AirdropArgs { connection: ConnectionContext @@ -53,20 +55,30 @@ export async function getMerkleAirdropInstruction({ } const airdropTransactionContext: AirdropConfigureContext = await airdrop.createConfigMerkleTransaction( form.treasury.pubkey, // source - form.treasury.extensions.token!.account.owner!, // authority - amountNatural, - root + wallet.publicKey, + new BN(0), + root, + undefined, + form.treasury.extensions.token!.account.owner!, // close authority ) - + const prerequisiteInstructions: TransactionInstruction[] = [] for (const instruction of airdropTransactionContext.transaction .instructions) { - additionalSerializedInstructions.push( - serializeInstructionToBase64(instruction) - ) + prerequisiteInstructions.push(instruction) } + const vaultAddress = airdrop.getVaultAddress(airdropTransactionContext.airdropState); + const transferIx = Token.createTransferInstruction( + TOKEN_PROGRAM_ID, + form.treasury.pubkey, + vaultAddress, + form.treasury.extensions.token!.account.owner!, + [], + amountNatural.toNumber(), + ) + return { - serializedInstruction, + serializedInstruction: serializeInstructionToBase64(transferIx), additionalSerializedInstructions, isValid: true, governance: form.treasury?.governance, diff --git a/utils/instructions/Dual/delegate.ts b/utils/instructions/Dual/delegate.ts index f6555c4286..0fb68b428d 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 @@ -175,17 +200,17 @@ export async function getVoteDepositInstruction({ const systemProgram = SystemProgram.programId const clientProgramId = vsrClient!.program.programId - const { registrar } = await getRegistrarPDA( + const { registrar } = getRegistrarPDA( realmPk, communityMintPk, clientProgramId ) - const { voter, voterBump } = await getVoterPDA( + const { voter, voterBump } = getVoterPDA( registrar, daoWallet, clientProgramId ) - const { voterWeightPk, voterWeightBump } = await getVoterWeightPDA( + const { voterWeightPk, voterWeightBump } = getVoterWeightPDA( registrar, daoWallet, clientProgramId @@ -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..04f33d24af 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, @@ -45,7 +45,8 @@ export const getUpdateVoterWeightRecordInstruction = async ( ) } const updateVoterWeightRecordIx = await program.methods - .updateVoterWeightRecord({ [type]: {} }) + // The cast to any works around an anchor issue with interpreting enums + .updateVoterWeightRecord({ [type]: {} } as any) .accounts({ registrar: registrar, voterWeightRecord: voterWeightPk, @@ -103,7 +104,8 @@ export const getUpdateVoterWeightRecordInstructionV2 = async ( for (const chunk of [...nftChunks]) { createNftTicketIxs.push( await program.methods - .createNftActionTicket({ [type]: {} }) + // The cast to any works around an anchor issue with interpreting enums + .createNftActionTicket({ [type]: {} } as any) .accounts({ registrar, voterWeightRecord: voterWeightPk, @@ -130,8 +132,17 @@ 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]) + // The cast to any works around an anchor issue with interpreting enums + .createCnftActionTicket({ [type]: {} } as any, typesafeParams) .accounts({ registrar, voterWeightRecord: voterWeightPk, @@ -150,7 +161,8 @@ export const getUpdateVoterWeightRecordInstructionV2 = async ( } const updateVoterWeightRecordIx = await program.methods - .updateVoterWeightRecord({ [type]: {} }) + // The cast to any works around an anchor issue with interpreting enums + .updateVoterWeightRecord({ [type]: {} } as any) .accounts({ registrar: registrar, voterWeightRecord: voterWeightPk, diff --git a/utils/mangoV4Tools.ts b/utils/mangoV4Tools.ts index 295865a4d8..c2e932f3d3 100644 --- a/utils/mangoV4Tools.ts +++ b/utils/mangoV4Tools.ts @@ -58,7 +58,10 @@ export const getClient = async (connection: Connection) => { const client = MangoClient.connect( adminProvider, 'mainnet-beta', - MANGO_V4_ID['mainnet-beta'] + MANGO_V4_ID['mainnet-beta'], + { + idsSource: 'api', + } ) return client diff --git a/utils/parseTokenAccountData.tsx b/utils/parseTokenAccountData.tsx new file mode 100644 index 0000000000..61e57d3e6a --- /dev/null +++ b/utils/parseTokenAccountData.tsx @@ -0,0 +1,42 @@ +import { PublicKey } from '@solana/web3.js' +import { AccountInfo, AccountLayout, u64 } from '@solana/spl-token' + +/** @asktree its very unclear why this must exist, like... why doesn't spl-token do this? */ + +export function parseTokenAccountData( + account: PublicKey, + data: Buffer +): AccountInfo { + const accountInfo = AccountLayout.decode(data) + accountInfo.address = account + accountInfo.mint = new PublicKey(accountInfo.mint) + accountInfo.owner = new PublicKey(accountInfo.owner) + accountInfo.amount = u64.fromBuffer(accountInfo.amount) + + if (accountInfo.delegateOption === 0) { + accountInfo.delegate = null + accountInfo.delegatedAmount = new u64(0) + } else { + accountInfo.delegate = new PublicKey(accountInfo.delegate) + accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount) + } + + accountInfo.isInitialized = accountInfo.state !== 0 + accountInfo.isFrozen = accountInfo.state === 2 + + if (accountInfo.isNativeOption === 1) { + accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative) + accountInfo.isNative = true + } else { + accountInfo.rentExemptReserve = null + accountInfo.isNative = false + } + + if (accountInfo.closeAuthorityOption === 0) { + accountInfo.closeAuthority = null + } else { + accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority) + } + + return accountInfo +} diff --git a/utils/plugin/accounts.ts b/utils/plugin/accounts.ts index 787bdd5636..a52e89c49b 100644 --- a/utils/plugin/accounts.ts +++ b/utils/plugin/accounts.ts @@ -1,12 +1,22 @@ +import { PluginName } from '@constants/plugins' import { PublicKey } from '@solana/web3.js' -export const getRegistrarPDA = async ( +export const getRegistrarPDA = ( realmPk: PublicKey, mint: PublicKey, - clientProgramId: PublicKey + clientProgramId: PublicKey, + pluginName?: PluginName ) => { - const [registrar, registrarBump] = await PublicKey.findProgramAddress( - [Buffer.from('registrar'), realmPk.toBuffer(), mint.toBuffer()], + const PLUGIN_NAME_SEEDS = { + VSR: [realmPk.toBuffer(), Buffer.from('registrar'), mint.toBuffer()], + } + const seed = (pluginName && PLUGIN_NAME_SEEDS[pluginName]) ?? [ + Buffer.from('registrar'), + realmPk.toBuffer(), + mint.toBuffer(), + ] + const [registrar, registrarBump] = PublicKey.findProgramAddressSync( + seed, clientProgramId ) return { diff --git a/utils/plugin/gateway.ts b/utils/plugin/gateway.ts deleted file mode 100644 index ab9184b325..0000000000 --- a/utils/plugin/gateway.ts +++ /dev/null @@ -1,84 +0,0 @@ -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/sendTransactions.tsx b/utils/sendTransactions.tsx index 1a6bd4bba6..6f632bf2dc 100644 --- a/utils/sendTransactions.tsx +++ b/utils/sendTransactions.tsx @@ -11,7 +11,12 @@ 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' +import { BACKUP_CONNECTIONS } from './connection' export type WalletSigner = Pick< SignerWalletAdapter, @@ -32,7 +37,7 @@ export enum SequenceType { StopOnFailure, } -export const sendTransactionsV3 = ({ +export const sendTransactionsV3 = async ({ connection, wallet, transactionInstructions, @@ -41,7 +46,28 @@ export const sendTransactionsV3 = ({ config, // eslint-disable-next-line @typescript-eslint/no-unused-vars lookupTableAccounts, -}: sendSignAndConfirmTransactionsProps & { lookupTableAccounts?: any }) => { + autoFee = true, +}: sendSignAndConfirmTransactionsProps & { + lookupTableAccounts?: any + autoFee?: boolean +}) => { + const transactionInstructionsWithFee: TransactionInstructionWithType[] = [] + const fee = await getFeeEstimate(connection) + for (const tx of transactionInstructions) { + if (tx.instructionsSet.length) { + const txObjWithFee = { + ...tx, + instructionsSet: autoFee + ? [ + new TransactionInstructionWithSigners(createComputeBudgetIx(fee)), + ...tx.instructionsSet, + ] + : [...tx.instructionsSet], + } + transactionInstructionsWithFee.push(txObjWithFee) + } + } + const callbacksWithUiComponent = { afterBatchSign: (signedTxnsCount) => { if (callbacks?.afterBatchSign) { @@ -54,7 +80,7 @@ export const sendTransactionsV3 = ({ callbacks?.afterAllTxConfirmed() } closeTransactionProcessUi() - transactionInstructions.forEach((x) => + transactionInstructionsWithFee.forEach((x) => x.instructionsSet.forEach((x) => invalidateInstructionAccounts(x.transactionInstruction) ) @@ -75,11 +101,12 @@ export const sendTransactionsV3 = ({ sendTransactionsV3({ ...originalProps, transactionInstructions: notProcessedTransactions, + autoFee: false, }), getErrorMsg(e), e.txid ) - transactionInstructions.forEach((x) => + transactionInstructionsWithFee.forEach((x) => x.instructionsSet.forEach((x) => invalidateInstructionAccounts(x.transactionInstruction) ) @@ -89,7 +116,7 @@ export const sendTransactionsV3 = ({ const cfg = { maxTxesInBatch: - transactionInstructions.filter( + transactionInstructionsWithFee.filter( (x) => x.sequenceType === SequenceType.Sequential ).length > 0 ? 20 @@ -103,11 +130,12 @@ export const sendTransactionsV3 = ({ return sendSignAndConfirmTransactions({ connection, wallet, - transactionInstructions, + transactionInstructions: transactionInstructionsWithFee, timeoutStrategy, callbacks: callbacksWithUiComponent, config: cfg, - confirmLevel: 'confirmed', //TODO base this on connection confirmation level + confirmLevel: 'confirmed', + backupConnections: BACKUP_CONNECTIONS, //TODO base this on connection confirmation level //lookupTableAccounts, }) } @@ -139,15 +167,19 @@ export const txBatchesToInstructionSetWithSigners = ( batchIdx?: number ): { transactionInstruction: TransactionInstruction; signers: Keypair[] }[] => { return txBatch.map((tx, txIdx) => { - let signers: Keypair[] = []; + let signers: Keypair[] = [] - if (typeof batchIdx !== 'undefined' && signerBatches?.length && signerBatches?.[batchIdx]?.[txIdx]) { - signers = [signerBatches[batchIdx][txIdx]]; + if ( + typeof batchIdx !== 'undefined' && + signerBatches?.length && + signerBatches?.[batchIdx]?.[txIdx] + ) { + signers = [signerBatches[batchIdx][txIdx]] } return { transactionInstruction: tx, signers, - }; - }); -}; + } + }) +} diff --git a/utils/services/tokenPrice.tsx b/utils/services/tokenPrice.tsx index f5eca91a93..1cc3bf6f09 100644 --- a/utils/services/tokenPrice.tsx +++ b/utils/services/tokenPrice.tsx @@ -4,9 +4,9 @@ import { mergeDeepRight } from 'ramda' import { notify } from '@utils/notifications' import { WSOL_MINT } from '@components/instructions/tools' import overrides from 'public/realms/token-overrides.json' -import { MAINNET_USDC_MINT } from '@foresight-tmp/foresight-sdk/dist/consts' import { Price, TokenInfo } from './types' import { chunks } from '@utils/helpers' +import { USDC_MINT } from '@blockworks-foundation/mango-v4' //this service provide prices it is not recommended to get anything more from here besides token name or price. //decimals from metadata can be different from the realm on chain one @@ -75,16 +75,27 @@ class TokenPriceService { }) } } - const USDC_MINT = MAINNET_USDC_MINT.toBase58() - if (!this._tokenPriceToUSDlist[USDC_MINT]) { - this._tokenPriceToUSDlist[USDC_MINT] = { - id: USDC_MINT, + const USDC_MINT_BASE = USDC_MINT.toBase58() + if (!this._tokenPriceToUSDlist[USDC_MINT_BASE]) { + this._tokenPriceToUSDlist[USDC_MINT_BASE] = { + id: USDC_MINT_BASE, mintSymbol: 'USDC', price: 1, - vsToken: USDC_MINT, + vsToken: USDC_MINT_BASE, 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/tokens.tsx b/utils/tokens.tsx index 4504838017..4faf2b21b7 100644 --- a/utils/tokens.tsx +++ b/utils/tokens.tsx @@ -7,7 +7,6 @@ import { } from '@solana/web3.js' import { AccountInfo, - AccountLayout, MintInfo, MintLayout, Token, @@ -25,6 +24,7 @@ import { BN } from '@coral-xyz/anchor' import { abbreviateAddress } from './formatting' import BigNumber from 'bignumber.js' import { AssetAccount } from '@utils/uiTypes/assets' +import { parseTokenAccountData } from './parseTokenAccountData' export type TokenAccount = AccountInfo export type MintAccount = MintInfo @@ -140,45 +140,6 @@ export const BPF_UPGRADE_LOADER_ID = new PublicKey( 'BPFLoaderUpgradeab1e11111111111111111111111' ) -/** @asktree its very unclear why this must exist, like... why doesn't spl-token do this? */ -export function parseTokenAccountData( - account: PublicKey, - data: Buffer -): TokenAccount { - const accountInfo = AccountLayout.decode(data) - accountInfo.address = account - accountInfo.mint = new PublicKey(accountInfo.mint) - accountInfo.owner = new PublicKey(accountInfo.owner) - accountInfo.amount = u64.fromBuffer(accountInfo.amount) - - if (accountInfo.delegateOption === 0) { - accountInfo.delegate = null - accountInfo.delegatedAmount = new u64(0) - } else { - accountInfo.delegate = new PublicKey(accountInfo.delegate) - accountInfo.delegatedAmount = u64.fromBuffer(accountInfo.delegatedAmount) - } - - accountInfo.isInitialized = accountInfo.state !== 0 - accountInfo.isFrozen = accountInfo.state === 2 - - if (accountInfo.isNativeOption === 1) { - accountInfo.rentExemptReserve = u64.fromBuffer(accountInfo.isNative) - accountInfo.isNative = true - } else { - accountInfo.rentExemptReserve = null - accountInfo.isNative = false - } - - if (accountInfo.closeAuthorityOption === 0) { - accountInfo.closeAuthority = null - } else { - accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority) - } - - return accountInfo -} - /** @deprecated -- why not just use the normal mint layout? */ export function parseMintAccountData(data: Buffer): MintAccount { const mintInfo = MintLayout.decode(data) diff --git a/utils/uiTypes/NftVoterClient.ts b/utils/uiTypes/NftVoterClient.ts index c9b5369e88..1d0577d47f 100644 --- a/utils/uiTypes/NftVoterClient.ts +++ b/utils/uiTypes/NftVoterClient.ts @@ -1,73 +1,215 @@ -import { Program, Provider } from '@project-serum/anchor' -import { PublicKey } from '@solana/web3.js' -import { NftVoter, IDL } from '../../idls/nft_voter' -import { NftVoterV2, IDLV2 } from '../../idls/nft_voter_v2' +import {IdlAccounts, Program, Provider} from '@coral-xyz/anchor' +import {PublicKey, TransactionInstruction} from '@solana/web3.js' +import {IDL, NftVoter} from '../../idls/nft_voter' +import {IDLV2, NftVoterV2} from '../../idls/nft_voter_v2' +import {DEFAULT_NFT_VOTER_PLUGIN, DEFAULT_NFT_VOTER_PLUGIN_V2,} from '@tools/constants' +import {ON_NFT_VOTER_V2} from '@constants/flags' +import {Client, DEFAULT_GOVERNANCE_PROGRAM_ID} from "@solana/governance-program-library"; +import {SYSTEM_PROGRAM_ID, VoterWeightAction} from "@solana/spl-governance"; +import {getVotingNfts} from "@hooks/queries/plugins/nftVoter"; import { - DEFAULT_NFT_VOTER_PLUGIN, - DEFAULT_NFT_VOTER_PLUGIN_V2, -} from '@tools/constants' -import { ON_NFT_VOTER_V2 } from '@constants/flags' + getUpdateVoterWeightRecordInstruction, + getUpdateVoterWeightRecordInstructionV2 +} from "@utils/instructions/NftVoter/updateVoterWeight"; +import {convertVoterWeightActionToType} from "../../VoterWeightPlugins/lib/utils"; +import BN from "bn.js"; +import { getNftGovpowerForOwnerAndRegistrar} from "@hooks/queries/governancePower"; // const programVersion = (ON_NFT_VOTER_V2 ? Program : Program) // const idl = ON_NFT_VOTER_V2 ? IDLV2 : IDL const DEFAULT_NFT_VOTER_PLUGIN_VERSION = ON_NFT_VOTER_V2 - ? DEFAULT_NFT_VOTER_PLUGIN_V2 - : DEFAULT_NFT_VOTER_PLUGIN - -export class NftVoterClientV1 { - constructor(public program: Program, public devnet?: boolean) {} - - static connect( - provider: Provider, - devnet?: boolean, - programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION) - ): NftVoterClient { - return new NftVoterClient( - new Program(IDL, programId, provider), - devnet + ? DEFAULT_NFT_VOTER_PLUGIN_V2 + : DEFAULT_NFT_VOTER_PLUGIN + +export abstract class NftVoterClient extends Client { + readonly requiresInputVoterWeight = false; + + async getMaxVoterWeightRecordPDA(realm: PublicKey, mint: PublicKey) { + const [ + maxVoterWeightPk, + maxVoterWeightRecordBump, + ] = PublicKey.findProgramAddressSync( + [ + Buffer.from('max-voter-weight-record'), + realm.toBuffer(), + mint.toBuffer(), + ], + this.program.programId ) + return { + maxVoterWeightPk, + maxVoterWeightRecordBump, + } + } + + async createVoterWeightRecord(voter: PublicKey, realm: PublicKey, mint: PublicKey): Promise { + const { voterWeightPk } = await this.getVoterWeightRecordPDA(realm, mint, voter) + return this.program.methods + .createVoterWeightRecord(voter) + .accounts({ + voterWeightRecord: voterWeightPk, + governanceProgramId: this.governanceProgramId, + realm, + realmGoverningTokenMint: mint, + payer: voter, + systemProgram: SYSTEM_PROGRAM_ID, + }) + .instruction(); + } + + // NO-OP + async createMaxVoterWeightRecord(): Promise { + return null; + } + + // NO-OP + async updateMaxVoterWeightRecord(): Promise { + return null; + } + async calculateVoterWeight(voter: PublicKey, realm: PublicKey, mint:PublicKey): Promise { + const registrar = await this.getRegistrarAccount(realm, mint); + return getNftGovpowerForOwnerAndRegistrar(this.program.provider.connection, voter, registrar as any); } -} -export class NftVoterClientV2 { - constructor(public program: Program, public devnet?: boolean) {} - - static connect( - provider: Provider, - devnet?: boolean, - programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION) - ): NftVoterClient { - console.log(programId.toBase58()) - return new NftVoterClient( - new Program(IDLV2, programId, provider), - devnet + async calculateMaxVoterWeight(realm: PublicKey, mint: PublicKey): Promise { + const registrar = (await this.getRegistrarAccount(realm, mint)) as unknown as IdlAccounts['registrar'] | undefined; + const nftVoterPluginTotalWeight = registrar?.collectionConfigs.reduce( + (prev, curr) => { + const size = curr.size + const weight = curr.weight.toNumber() + if (typeof size === 'undefined' || typeof weight === 'undefined') + return prev + return prev + size * weight + }, + 0 ) + + return nftVoterPluginTotalWeight !== undefined ? new BN(nftVoterPluginTotalWeight) : null; } -} -export class NftVoterClient { constructor( - public program: Program | Program, - public devnet?: boolean - ) {} - - static connect( - provider: Provider, - devnet?: boolean, - programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION) - ): NftVoterClient { + public program: Program | Program, + public devnet: boolean, + readonly governanceProgramId: PublicKey + ) { + super(program, devnet) + } + + static async connect( + provider: Provider, + programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION), + devnet = false, + governanceProgramId = DEFAULT_GOVERNANCE_PROGRAM_ID + ): Promise { if (ON_NFT_VOTER_V2) { return NftVoterClientV2.connect( - provider, - devnet, - programId - ) as NftVoterClient + provider, + programId, + devnet, + governanceProgramId + ) } else { return NftVoterClientV1.connect( - provider, + provider, + programId, + devnet, + governanceProgramId + ) + } + } +} + +export class NftVoterClientV1 extends NftVoterClient { + constructor(public program: Program, public devnet: boolean, readonly governanceProgramId) { + super(program, devnet, governanceProgramId) + } + + async updateVoterWeightRecord(voter: PublicKey, realm: PublicKey, mint: PublicKey, action: VoterWeightAction) { + // Not clear why, but it seems like updateVoterWeightRecord is not called during cast vote + // for the nft plugin + if (action === VoterWeightAction.CastVote) { + return {pre: []} + } + + const {registrar} = this.getRegistrarPDA(realm, mint); + const {voterWeightPk} = await this.getVoterWeightRecordPDA(realm, mint, voter); + const votingNfts = await getVotingNfts( + this.program.provider.connection, + realm, + voter + ) + + console.log('on nft voter v1') + const ix = await getUpdateVoterWeightRecordInstruction( + this.program, + voter, + registrar, + voterWeightPk, + votingNfts, + convertVoterWeightActionToType(action) + ) + return {pre: [ix]} + } + + static async connect( + provider: Provider, + programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION), + devnet = false, + governanceProgramId = DEFAULT_GOVERNANCE_PROGRAM_ID + ): Promise { + return new NftVoterClientV1( + new Program(IDL, programId, provider), devnet, - programId - ) as NftVoterClient + governanceProgramId + ) + } +} + +export class NftVoterClientV2 extends NftVoterClient { + constructor(public program: Program, public devnet: boolean, readonly governanceProgramId) { + super(program, devnet, governanceProgramId) + } + + async updateVoterWeightRecord(voter: PublicKey, realm: PublicKey, mint: PublicKey, action: VoterWeightAction) { + // Not clear why, but it seems like updateVoterWeightRecord is not called during cast vote + // for the nft plugin + if (action === VoterWeightAction.CastVote) { + return {pre: []} } + + const {registrar} = this.getRegistrarPDA(realm, mint); + const { voterWeightPk } = await this.getVoterWeightRecordPDA(realm, mint, voter); + const votingNfts = await getVotingNfts( + this.program.provider.connection, + realm, + voter + ) + + console.log('on nft voter v2') + const { + createNftTicketIxs, + updateVoterWeightRecordIx, + } = await getUpdateVoterWeightRecordInstructionV2( + this.program, + voter, + registrar, + voterWeightPk, + votingNfts, + convertVoterWeightActionToType(action) + ) + return { pre: [updateVoterWeightRecordIx] , post: createNftTicketIxs } + } + + static async connect( + provider: Provider, + programId = new PublicKey(DEFAULT_NFT_VOTER_PLUGIN_VERSION), + devnet = false, + governanceProgramId = DEFAULT_GOVERNANCE_PROGRAM_ID + ): Promise { + return new NftVoterClientV2( + new Program(IDLV2, programId, provider), + devnet, + governanceProgramId + ) } } diff --git a/utils/uiTypes/VotePlugin.ts b/utils/uiTypes/VotePlugin.ts index 22da4901e2..0282084276 100644 --- a/utils/uiTypes/VotePlugin.ts +++ b/utils/uiTypes/VotePlugin.ts @@ -1,59 +1,31 @@ -import { GatewayClient } from '@solana/governance-program-library' - -import { - ProgramAccount, - Realm, - SYSTEM_PROGRAM_ID, - Proposal, -} from '@solana/spl-governance' -import { PublicKey, TransactionInstruction } from '@solana/web3.js' -import { chunks } from '@utils/helpers' -import { - getRegistrarPDA, - getVoterPDA, - getVoterWeightPDA, -} from 'VoteStakeRegistry/sdk/accounts' -import { NFTWithMint } from './nfts' +import {ProgramAccount, Proposal, Realm, VoterWeightAction,} from '@solana/spl-governance' +import {PublicKey, TransactionInstruction} from '@solana/web3.js' +import {chunks} from '@utils/helpers' import { - getPreviousVotingWeightRecord, - getVoteInstruction, -} from '../../GatewayPlugin/sdk/accounts' -import { - getVoterWeightRecord as getPluginVoterWeightRecord, getRegistrarPDA as getPluginRegistrarPDA, - getMaxVoterWeightRecord as getPluginMaxVoterWeightRecord, } from '@utils/plugin/accounts' -import { VsrClient } from 'VoteStakeRegistry/sdk/client' -import { getUsedNftsForProposal } from 'NftVotePlugin/accounts' -import { PositionWithMeta } from 'HeliumVotePlugin/sdk/types' -import { HeliumVsrClient } from 'HeliumVotePlugin/sdk/client' +import {getUsedNftsForProposal} from 'NftVotePlugin/accounts' +import {PositionWithMeta} from 'HeliumVotePlugin/sdk/types' import { nftVoteRecordKey, registrarKey, - voterWeightRecordKey, - maxVoterWeightRecordKey, } from '@helium/voter-stake-registry-sdk' -import { getUnusedPositionsForProposal } from 'HeliumVotePlugin/utils/getUnusedPositionsForProposal' -import { getUsedPositionsForProposal } from 'HeliumVotePlugin/utils/getUsedPositionsForProposal' -import { getAssociatedTokenAddress } from '@blockworks-foundation/mango-v4' -import { NftVoterClient } from './NftVoterClient' +import {getUnusedPositionsForProposal} from 'HeliumVotePlugin/utils/getUnusedPositionsForProposal' +import {getUsedPositionsForProposal} from 'HeliumVotePlugin/utils/getUsedPositionsForProposal' +import {getAssociatedTokenAddress} from '@blockworks-foundation/mango-v4' import queryClient from '@hooks/queries/queryClient' import asFindable from '@utils/queries/asFindable' -import { ON_NFT_VOTER_V2 } from '@constants/flags' -import { - getUpdateVoterWeightRecordInstruction, - getUpdateVoterWeightRecordInstructionV2, -} from '@utils/instructions/NftVoter/updateVoterWeight' -import { - getCastNftVoteInstruction, - getCastNftVoteInstructionV2, -} 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 { fetchTokenOwnerRecordByPubkey } from '@hooks/queries/tokenOwnerRecord' -import { StakeConnection as PythClient } from '@pythnetwork/staking' -import { getVotingNfts } from '@hooks/queries/plugins/nftVoter' +import {convertTypeToVoterWeightAction} from "../../VoterWeightPlugins"; +import {Client} from "@solana/governance-program-library"; +import {NftVoterClient} from "@utils/uiTypes/NftVoterClient"; +import {HeliumVsrClient} from "../../HeliumVotePlugin/sdk/client"; +import {getVotingNfts} from "@hooks/queries/plugins/nftVoter"; +import {ON_NFT_VOTER_V2} from "@constants/flags"; +import {getCastNftVoteInstruction, getCastNftVoteInstructionV2} from "@utils/instructions/NftVoter/castNftVote"; +import {Program} from "@coral-xyz/anchor"; +import {NftVoter} from "../../idls/nft_voter"; +import {NftVoterV2} from "../../idls/nft_voter_v2"; +import {UseRealmVoterWeightPluginsReturnType} from "@hooks/useRealmVoterWeightPlugins"; export type UpdateVoterWeightRecordTypes = | 'castVote' @@ -63,13 +35,10 @@ export type UpdateVoterWeightRecordTypes = | 'signOffProposal' export interface VotingClientProps { - client: Client | undefined + client: Client | undefined realm: ProgramAccount | undefined walletPk: PublicKey | null | undefined -} - -export interface NFTWithMeta extends NFTWithMint { - getAssociatedTokenAccount(): Promise + voterWeightPluginDetails: UseRealmVoterWeightPluginsReturnType } export enum VotingClientType { @@ -77,8 +46,6 @@ export enum VotingClientType { VsrClient, HeliumVsrClient, NftVoterClient, - GatewayClient, - PythClient, } export class AccountData { @@ -101,25 +68,18 @@ interface ProgramAddresses { maxVoterWeightRecord: PublicKey | undefined } -export type Client = - | VsrClient - | HeliumVsrClient - | NftVoterClient - | GatewayClient - | PythClient - //Abstract for common functions that plugins will implement export class VotingClient { - client: Client | undefined + client: Client | undefined realm: ProgramAccount | undefined walletPk: PublicKey | null | undefined heliumVsrVotingPositions: PositionWithMeta[] - gatewayToken: PublicKey oracles: PublicKey[] instructions: TransactionInstruction[] clientType: VotingClientType noClient: boolean - constructor({ client, realm, walletPk }: VotingClientProps) { + voterWeightPluginDetails: UseRealmVoterWeightPluginsReturnType + constructor({ client, realm, walletPk, voterWeightPluginDetails }: VotingClientProps) { this.client = client this.realm = realm this.walletPk = walletPk @@ -128,10 +88,7 @@ export class VotingClient { this.instructions = [] this.noClient = true this.clientType = VotingClientType.NoClient - if (this.client instanceof VsrClient) { - this.clientType = VotingClientType.VsrClient - this.noClient = false - } + this.voterWeightPluginDetails = voterWeightPluginDetails if (this.client instanceof HeliumVsrClient) { this.clientType = VotingClientType.HeliumVsrClient this.noClient = false @@ -140,273 +97,78 @@ export class VotingClient { this.clientType = VotingClientType.NftVoterClient this.noClient = false } + } - if (this.client instanceof GatewayClient) { - this.clientType = VotingClientType.GatewayClient - this.noClient = false - } - if (this.client instanceof GatewayClient) { - this.clientType = VotingClientType.GatewayClient - this.noClient = false - } - if (this.client instanceof PythClient) { - this.clientType = VotingClientType.PythClient - this.noClient = false - } + // Take this exact voting client, but set a different voter wallet - useful for combining delegate and delegator votes + public for(wallet: PublicKey): VotingClient { + return new VotingClient({ + client: this.client, + realm: this.realm, + walletPk: wallet, + voterWeightPluginDetails: this.voterWeightPluginDetails, + }) } + + private get voterWeightPk() { + return this.walletPk ? this.voterWeightPluginDetails.voterWeightPkForWallet(this.walletPk) : undefined + } + + private get maxVoterWeightPk() { + return this.voterWeightPluginDetails.maxVoterWeightPk + } + withUpdateVoterWeightRecord = async ( instructions: TransactionInstruction[], - tokenOwnerRecord: PublicKey, type: UpdateVoterWeightRecordTypes, createNftActionTicketIxs?: TransactionInstruction[], - pythVoterWeightTarget?: PublicKey + target? : PublicKey ): Promise => { - if (this.noClient) return - - const realm = this.realm! - const torAccount = await fetchTokenOwnerRecordByPubkey( - this.client!.program.provider.connection, - tokenOwnerRecord - ) - console.log(this.client) - if (!torAccount.result) return + // nothing to do if no wallet is connected, or no plugins are attached to this realm if ( - !realm.account.communityMint.equals( - torAccount.result.account.governingTokenMint - ) - ) { - return - } - const clientProgramId = this.client!.program.programId - const walletPk = torAccount.result.account.governingTokenOwner - - if (this.client instanceof VsrClient) { - const { registrar } = await getRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - const { voter } = await getVoterPDA(registrar, walletPk, clientProgramId) - const { voterWeightPk } = await getVoterWeightPDA( - registrar, - walletPk, - clientProgramId - ) - const updateVoterWeightRecordIx = await this.client!.program.methods.updateVoterWeightRecord() - .accounts({ - registrar, - voter, - voterWeightRecord: voterWeightPk, - systemProgram: SYSTEM_PROGRAM_ID, - }) - .instruction() - instructions.push(updateVoterWeightRecordIx) - return { voterWeightPk, maxVoterWeightRecord: undefined } - } - - if (this.client instanceof HeliumVsrClient) { - const remainingAccounts: AccountData[] = [] - const [registrar] = registrarKey( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - - for (const pos of this.heliumVsrVotingPositions) { - const tokenAccount = await getAssociatedTokenAddress( - pos.mint, - walletPk, - true - ) - - remainingAccounts.push( - new AccountData(tokenAccount), - new AccountData(pos.pubkey) - ) - } + !this.walletPk || + !this.voterWeightPluginDetails.plugins || + (this.voterWeightPluginDetails.plugins.voterWeight.length === 0 + && this.voterWeightPluginDetails.plugins.maxVoterWeight.length === 0) + ) return undefined; - const [voterWeightPk] = voterWeightRecordKey( - registrar, - walletPk, - clientProgramId - ) + const {pre: preIxes, post: postIxes} = await this.voterWeightPluginDetails.updateVoterWeightRecords(this.walletPk, convertTypeToVoterWeightAction(type), target) + instructions.push(...preIxes); + createNftActionTicketIxs?.push(...postIxes); - const [maxVoterWeightPk] = maxVoterWeightRecordKey( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - - instructions.push( - await (this.client as HeliumVsrClient).program.methods - .updateVoterWeightRecordV0({ - owner: walletPk, - voterWeightAction: { - [type]: {}, - }, - } as any) - .accounts({ - registrar, - voterWeightRecord: voterWeightPk, - voterTokenOwnerRecord: tokenOwnerRecord, - }) - .remainingAccounts(remainingAccounts.slice(0, 10)) - .instruction() - ) - - return { - voterWeightPk, - maxVoterWeightRecord: maxVoterWeightPk, - } - } - - if (this.client instanceof NftVoterClient) { - const { registrar } = await getPluginRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - const { - voterWeightPk, - maxVoterWeightRecord, - } = await this._withHandleNftVoterWeight( - realm, - walletPk, - clientProgramId, - instructions - ) - - const votingNfts = await getVotingNfts( - this.client.program.provider.connection, - realm.pubkey, - walletPk - ) - - if (!ON_NFT_VOTER_V2) { - console.log('on nft voter v1') - const updateVoterWeightRecordIx = await getUpdateVoterWeightRecordInstruction( - this.client.program as Program, - walletPk, - registrar, - voterWeightPk, - votingNfts, - type - ) - instructions.push(updateVoterWeightRecordIx) - } else { - console.log('on nft voter v2') - const { - createNftTicketIxs, - updateVoterWeightRecordIx, - } = await getUpdateVoterWeightRecordInstructionV2( - this.client.program as Program, - walletPk, - registrar, - voterWeightPk, - votingNfts, - type - ) - createNftActionTicketIxs?.push(...createNftTicketIxs) - instructions.push(updateVoterWeightRecordIx) - } - - return { voterWeightPk, maxVoterWeightRecord } - } - if (this.client instanceof GatewayClient) { - const { voterWeightPk } = await this._withHandleGatewayVoterWeight( - realm, - walletPk, - clientProgramId, - instructions - ) - - if (!this.gatewayToken) - throw new Error(`Unable to execute transaction: No Civic Pass found`) - - const updateVoterWeightRecordIx = await getVoteInstruction( - this.client, - this.gatewayToken, - realm, - walletPk - ) - instructions.push(updateVoterWeightRecordIx) - return { voterWeightPk, maxVoterWeightRecord: undefined } - } - if (this.client instanceof PythClient) { - const stakeAccount = await this.client!.getMainAccount(walletPk) - - const { - voterWeightAccount, - maxVoterWeightRecord, - } = await this.client.withUpdateVoterWeight( - instructions, - stakeAccount!, - { [type]: {} }, - pythVoterWeightTarget - ) - - return { - voterWeightPk: voterWeightAccount, - maxVoterWeightRecord, - } - } + return { voterWeightPk: this.voterWeightPk, maxVoterWeightRecord: this.maxVoterWeightPk } } + withCastPluginVote = async ( instructions: TransactionInstruction[], proposal: ProgramAccount, tokenOwnerRecord: PublicKey, createNftActionTicketIxs?: TransactionInstruction[] ): Promise => { - if (this.noClient) { - return - } - const clientProgramId = this.client!.program.programId - const realm = this.realm! - const walletPk = this.walletPk! + const clientProgramId = this.client?.program.programId + const realm = this.realm + const walletPk = this.walletPk + if ( + !realm || !walletPk || realm.account.communityMint.toBase58() !== proposal.account.governingTokenMint.toBase58() ) { return } - if (this.client instanceof VsrClient) { - const props = await this.withUpdateVoterWeightRecord( - instructions, - tokenOwnerRecord, - 'castVote' - ) - return props - } - - if (this.client instanceof GatewayClient) { - // get the gateway plugin vote instruction - const instruction = await getVoteInstruction( - this.client, - this.gatewayToken, - realm, - walletPk - ) - - instructions.push(instruction) - - const { voterWeightPk } = await this._withHandleGatewayVoterWeight( - realm, - walletPk, - clientProgramId, - instructions - ) - - return { voterWeightPk, maxVoterWeightRecord: undefined } - } + const updateVoterWeightRecordIxes = await this.voterWeightPluginDetails.updateVoterWeightRecords(walletPk, VoterWeightAction.CastVote, proposal.pubkey); + const updateMaxVoterWeightRecordIxes = await this.voterWeightPluginDetails.updateMaxVoterWeightRecords(); + instructions.push(...updateMaxVoterWeightRecordIxes, ...updateVoterWeightRecordIxes.pre); + createNftActionTicketIxs?.push(...updateVoterWeightRecordIxes.post || []); + // the helium client needs to add some additional accounts to the transaction if (this.client instanceof HeliumVsrClient) { const remainingAccounts: AccountData[] = [] const [registrar] = registrarKey( - realm.pubkey, - realm.account.communityMint, - clientProgramId + realm.pubkey, + realm.account.communityMint, + clientProgramId ) const unusedPositions = await getUnusedPositionsForProposal({ @@ -416,35 +178,23 @@ export class VotingClient { proposalPk: proposal.pubkey, }) - const [voterWeightPk] = voterWeightRecordKey( - registrar, - walletPk, - clientProgramId - ) - - const [maxVoterWeightPk] = maxVoterWeightRecordKey( - realm.pubkey, - realm.account.communityMint, - clientProgramId - ) - for (let i = 0; i < unusedPositions.length; i++) { const pos = unusedPositions[i] const tokenAccount = await getAssociatedTokenAddress( - pos.mint, - walletPk, - true + pos.mint, + walletPk, + true ) const [nftVoteRecord] = nftVoteRecordKey( - proposal.pubkey, - pos.mint, - clientProgramId + proposal.pubkey, + pos.mint, + clientProgramId ) remainingAccounts.push( - new AccountData(tokenAccount), - new AccountData(pos.pubkey, false, true), - new AccountData(nftVoteRecord, false, true) + new AccountData(tokenAccount), + new AccountData(pos.pubkey, false, true), + new AccountData(nftVoteRecord, false, true) ) } @@ -452,83 +202,49 @@ export class VotingClient { const positionChunks = chunks(remainingAccounts, 9) for (const chunk of positionChunks) { instructions.push( - await this.client.program.methods - .castVoteV0({ - proposal: proposal.pubkey, - owner: walletPk, - }) - .accounts({ - registrar, - voterTokenOwnerRecord: tokenOwnerRecord, - }) - .remainingAccounts(chunk) - .instruction() + await this.client.program.methods + .castVoteV0({ + proposal: proposal.pubkey, + owner: walletPk, + }) + .accounts({ + registrar, + voterTokenOwnerRecord: tokenOwnerRecord, + }) + .remainingAccounts(chunk) + .instruction() ) } - - return { - voterWeightPk, - maxVoterWeightRecord: maxVoterWeightPk, - } } - if (this.client instanceof PythClient) { - const stakeAccount = await this.client!.getMainAccount(walletPk) - - const { - voterWeightAccount, - maxVoterWeightRecord, - } = await this.client.withUpdateVoterWeight( - instructions, - stakeAccount!, - { ['castVote']: {} }, - proposal.pubkey - ) - - return { - voterWeightPk: voterWeightAccount, - maxVoterWeightRecord, - } - } - - if (this.client instanceof NftVoterClient) { - const { registrar } = await getPluginRegistrarPDA( - realm.pubkey, - realm.account.communityMint, - this.client.program.programId - ) - - const { - voterWeightPk, - maxVoterWeightRecord, - } = await this._withHandleNftVoterWeight( - realm, - walletPk, - clientProgramId, - instructions + if (this.client instanceof NftVoterClient && this.voterWeightPk) { + const {registrar} = await getPluginRegistrarPDA( + realm.pubkey, + realm.account.communityMint, + this.client.program.programId ) const nftVoteRecordsFiltered = await getUsedNftsForProposal( - this.client, - proposal.pubkey + this.client, + proposal.pubkey ) const votingNfts = await getVotingNfts( - this.client.program.provider.connection, - realm.pubkey, - walletPk + this.client.program.provider.connection, + realm.pubkey, + walletPk ) if (!ON_NFT_VOTER_V2) { const castNftVoteIxs = await getCastNftVoteInstruction( - this.client.program as Program, - walletPk, - registrar, - proposal.pubkey, - tokenOwnerRecord, - voterWeightPk, - votingNfts, - nftVoteRecordsFiltered + this.client.program as Program, + walletPk, + registrar, + proposal.pubkey, + tokenOwnerRecord, + this.voterWeightPk, + votingNfts, + nftVoteRecordsFiltered ) instructions.push(...castNftVoteIxs) } else { @@ -536,24 +252,27 @@ export class VotingClient { castNftVoteTicketIxs, castNftVoteIxs, } = await getCastNftVoteInstructionV2( - this.client.program as Program, - walletPk, - registrar, - proposal.pubkey, - tokenOwnerRecord, - voterWeightPk, - votingNfts, - nftVoteRecordsFiltered + this.client.program as Program, + walletPk, + registrar, + proposal.pubkey, + tokenOwnerRecord, + this.voterWeightPk, + votingNfts, + nftVoteRecordsFiltered ) createNftActionTicketIxs?.push(...castNftVoteTicketIxs) instructions.push(...castNftVoteIxs) } + } - return { voterWeightPk, maxVoterWeightRecord } + return { + voterWeightPk: this.voterWeightPk, + maxVoterWeightRecord: this.maxVoterWeightPk, } } withRelinquishVote = async ( - instructions, + instructions: TransactionInstruction[], proposal: ProgramAccount, voteRecordPk: PublicKey, tokenOwnerRecord: PublicKey @@ -561,10 +280,12 @@ export class VotingClient { if (this.noClient) { return } - const clientProgramId = this.client!.program.programId - const realm = this.realm! - const walletPk = this.walletPk! + const clientProgramId = this.client?.program.programId + const realm = this.realm + const walletPk = this.walletPk + if ( + !realm || !walletPk || !this.voterWeightPk || !clientProgramId || realm.account.communityMint.toBase58() !== proposal.account.governingTokenMint.toBase58() ) { @@ -579,12 +300,6 @@ export class VotingClient { clientProgramId ) - const [voterWeightPk] = voterWeightRecordKey( - registrar, - walletPk, - clientProgramId - ) - const usedPositions = await getUsedPositionsForProposal({ connection: this.client.program.provider.connection, client: this.client, @@ -621,7 +336,7 @@ export class VotingClient { voterTokenOwnerRecord: tokenOwnerRecord, proposal: proposal.pubkey, governance: proposal.account.governance, - voterWeightRecord: voterWeightPk, + voterWeightRecord: this.voterWeightPk, voteRecord: voteRecordPk, beneficiary: walletPk, }) @@ -631,27 +346,19 @@ export class VotingClient { } return { - voterWeightPk, - maxVoterWeightRecord: undefined, + voterWeightPk: this.voterWeightPk, + maxVoterWeightRecord: this.maxVoterWeightPk, } } if (this.client instanceof NftVoterClient) { const remainingAccounts: AccountData[] = [] - const { registrar } = await getPluginRegistrarPDA( + const { registrar } = getPluginRegistrarPDA( realm.pubkey, realm.account.communityMint, - this.client!.program.programId - ) - const { - voterWeightPk, - maxVoterWeightRecord, - } = await this._withHandleNftVoterWeight( - realm!, - walletPk, - clientProgramId, - instructions + this.client.program.programId ) + const nftVoteRecordsFiltered = ( await getUsedNftsForProposal(this.client, proposal.pubkey) ).filter( @@ -667,9 +374,11 @@ export class VotingClient { // if this was good code, this would appear outside of this fn. // But we're not writing good code, there's no good place for it, I'm not bothering. const voterWeightRecord = await queryClient.fetchQuery({ - queryKey: [voterWeightPk], - queryFn: () => - asFindable(connection.getAccountInfo, connection)(voterWeightPk), + queryKey: [this.voterWeightPk], + queryFn: () => { + if (!this.voterWeightPk) throw new Error("No voter weight pk for the current wallet") + return asFindable(connection.getAccountInfo, connection)(this.voterWeightPk); + }, }) if (voterWeightRecord.result) { @@ -685,7 +394,7 @@ export class VotingClient { .relinquishNftVote() .accounts({ registrar, - voterWeightRecord: voterWeightPk, + voterWeightRecord: this.voterWeightPk, governance: proposal.account.governance, proposal: proposal.pubkey, voterTokenOwnerRecord: tokenOwnerRecord, @@ -699,85 +408,15 @@ export class VotingClient { } } - return { voterWeightPk, maxVoterWeightRecord } - } - } - - _withHandleNftVoterWeight = async ( - realm: ProgramAccount, - walletPk: PublicKey, - clientProgramId: PublicKey, - _instructions - ) => { - if (this.client instanceof NftVoterClient === false) { - throw 'Method only allowed for nft voter client' - } - const { - voterWeightPk, - voterWeightRecordBump, - } = await getPluginVoterWeightRecord( - realm!.pubkey, - realm!.account.communityMint, - walletPk!, - clientProgramId - ) - - const { - maxVoterWeightRecord, - maxVoterWeightRecordBump, - } = await getPluginMaxVoterWeightRecord( - realm!.pubkey, - realm!.account.communityMint, - clientProgramId - ) - - return { - voterWeightPk, - voterWeightRecordBump, - maxVoterWeightRecord, - maxVoterWeightRecordBump, + return { + voterWeightPk: this.voterWeightPk, + maxVoterWeightRecord: this.maxVoterWeightPk + } } } - // TODO: this can probably be merged with the nft voter plugin implementation - _withHandleGatewayVoterWeight = async ( - realm: ProgramAccount, - walletPk: PublicKey, - clientProgramId: PublicKey, - _instructions - ) => { - if (!(this.client instanceof GatewayClient)) { - throw 'Method only allowed for gateway client' - } - const { - voterWeightPk, - voterWeightRecordBump, - } = await getPluginVoterWeightRecord( - realm.pubkey, - realm.account.communityMint, - walletPk, - clientProgramId - ) - - const previousVoterWeightPk = await getPreviousVotingWeightRecord( - this.client, - realm, - walletPk - ) - return { - previousVoterWeightPk, - voterWeightPk, - voterWeightRecordBump, - } - } _setCurrentHeliumVsrPositions = (positions: PositionWithMeta[]) => { this.heliumVsrVotingPositions = positions } - _setCurrentVoterGatewayToken = (gatewayToken: PublicKey) => { - this.gatewayToken = gatewayToken - } - _setInstructions = (instructions: TransactionInstruction[]) => { - this.instructions = instructions - } } diff --git a/utils/uiTypes/proposalCreationTypes.ts b/utils/uiTypes/proposalCreationTypes.ts index 3880d37716..d0aaa9eaa9 100644 --- a/utils/uiTypes/proposalCreationTypes.ts +++ b/utils/uiTypes/proposalCreationTypes.ts @@ -6,7 +6,6 @@ import { getNameOf } from '@tools/core/script' import { SupportedMintName } from '@tools/sdk/solend/configuration' import { DepositWithMintAccount, Voter } from 'VoteStakeRegistry/sdk/accounts' import { LockupKind } from 'VoteStakeRegistry/tools/types' -import { consts as foresightConsts } from '@foresight-tmp/foresight-sdk' import { AssetAccount, StakeAccount } from '@utils/uiTypes/assets' import { RealmInfo } from '@models/registry/api' import * as PaymentStreaming from '@mean-dao/payment-streaming' @@ -14,19 +13,21 @@ import * as PaymentStreaming from '@mean-dao/payment-streaming' // Alphabetical order export enum PackageEnum { Common, + Distribution, Dual, - Foresight, GatewayPlugin, Identity, - NftPlugin, MangoMarketV4, MeanFinance, + NftPlugin, PsyFinance, + Pyth, Serum, Solend, + Symmetry, + Squads, Switchboard, VsrPlugin, - Distribution, } export interface UiInstruction { @@ -49,6 +50,12 @@ export interface SplTokenTransferForm { mintInfo: MintInfo | undefined } +export interface BurnTokensForm { + amount: number | undefined + governedTokenAccount: AssetAccount | undefined + mintInfo: MintInfo | undefined +} + export interface DomainNameTransferForm { destinationAccount: string governedAccount: AssetAccount | undefined @@ -114,7 +121,10 @@ export interface ClawbackForm { holdupTime: number } -export interface SendTokenCompactViewForm extends SplTokenTransferForm { +export interface SendTokenCompactViewForm extends Omit { + destinationAccount: string[] + amount: (number | undefined)[] + txDollarAmount: (string | undefined)[] description: string title: string } @@ -188,35 +198,6 @@ export interface PsyFinanceExerciseOption { /* End PsyOptions American options */ -export interface ForesightHasGovernedAccount { - governedAccount: AssetAccount -} - -export interface ForesightHasMarketListId extends ForesightHasGovernedAccount { - marketListId: string -} - -export interface ForesightHasMarketId extends ForesightHasMarketListId { - marketId: number -} - -export interface ForesightHasCategoryId extends ForesightHasGovernedAccount { - categoryId: string -} - -export interface ForesightMakeAddMarketListToCategoryParams - extends ForesightHasCategoryId, - ForesightHasMarketListId {} - -export interface ForesightMakeResolveMarketParams extends ForesightHasMarketId { - winner: number -} - -export interface ForesightMakeSetMarketMetadataParams - extends ForesightHasMarketId { - content: string - field: foresightConsts.MarketMetadataFieldName -} export interface Base64InstructionForm { governedAccount: AssetAccount | undefined base64: string @@ -315,6 +296,7 @@ export interface JoinDAOForm { export enum Instructions { Base64, + Burn, ChangeMakeDonation, Clawback, CloseTokenAccount, @@ -342,16 +324,11 @@ export enum Instructions { DualFinanceDelegate, DualFinanceDelegateWithdraw, DualFinanceVoteDeposit, - DualFinanceVote, + DaoVote, DistributionCloseVaults, DistributionFillVaults, DelegateStake, - ForesightAddMarketListToCategory, - ForesightInitCategory, - ForesightInitMarket, - ForesightInitMarketList, - ForesightResolveMarket, - ForesightSetMarketMetadata, + RemoveStakeLock, Grant, InitSolendObligationAccount, JoinDAO, @@ -394,6 +371,11 @@ export enum Instructions { SerumInitUser, SerumUpdateGovConfigAuthority, SerumUpdateGovConfigParams, + SquadsMeshAddMember, + SquadsMeshChangeThresholdMember, + SquadsMeshRemoveMember, + PythRecoverAccount, + PythUpdatePoolAuthority, StakeValidator, SwitchboardFundOracle, WithdrawFromOracle, @@ -410,6 +392,12 @@ export enum Instructions { RemoveServiceFromDID, RevokeGoverningTokens, SetMintAuthority, + SanctumDepositStake, + SanctumWithdrawStake, + SymmetryCreateBasket, + SymmetryEditBasket, + SymmetryDeposit, + SymmetryWithdraw } export interface ComponentInstructionData { @@ -469,6 +457,11 @@ export interface ValidatorWithdrawStakeForm { amount: number } +export interface ValidatorRemoveLockup { + governedTokenAccount: AssetAccount | undefined + stakeAccount: string +} + export interface DelegateStakeForm { governedTokenAccount: AssetAccount | undefined stakingAccount: StakeAccount | undefined @@ -488,7 +481,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 +497,7 @@ export interface DualFinanceGsoForm { lotSize: number subscriptionPeriodEnd: number lockupRatio: number + lockupMint: string baseTreasury: AssetAccount | undefined quoteTreasury: AssetAccount | undefined payer: AssetAccount | undefined @@ -560,3 +554,59 @@ export interface DualFinanceVoteDepositForm { realm: string | undefined delegateToken: AssetAccount | undefined } + +export interface SymmetryCreateBasketForm { + governedAccount?: AssetAccount, + basketType: number, + basketName: string, + basketSymbol: string, + basketMetadataUrl: string, + basketComposition: { + name: string, + symbol: string, + token: PublicKey; + weight: number; + }[], + rebalanceThreshold: number, + rebalanceSlippageTolerance: number, + depositFee: number, + feeCollectorAddress:string, + liquidityProvision: boolean, + liquidityProvisionRange: number, +} + + +export interface SymmetryEditBasketForm { + governedAccount?: AssetAccount, + basketAddress?: PublicKey, + basketType: number, + basketName: string, + basketSymbol: string, + basketMetadataUrl: string, + basketComposition: { + name: string, + symbol: string, + token: PublicKey; + weight: number; + }[], + rebalanceThreshold: number, + rebalanceSlippageTolerance: number, + depositFee: number, + feeCollectorAddress:string, + liquidityProvision: boolean, + liquidityProvisionRange: number, +} + +export interface SymmetryDepositForm { + governedAccount?: AssetAccount, + basketAddress?: PublicKey, + depositToken?: PublicKey, + depositAmount: number, +} + +export interface SymmetryWithdrawForm { + governedAccount?: AssetAccount, + basketAddress?: PublicKey, + withdrawAmount: number, + withdrawType: number +} diff --git a/utils/validations.tsx b/utils/validations.tsx index 4a8bb1f2af..7f9c818178 100644 --- a/utils/validations.tsx +++ b/utils/validations.tsx @@ -24,6 +24,7 @@ import { VSR_PLUGIN_PKS, HELIUM_VSR_PLUGINS_PKS, GATEWAY_PLUGINS_PKS, + QV_PLUGINS_PKS, } from '@constants/plugins' import { AssetAccount } from '@utils/uiTypes/assets' import { validatePubkey } from './formValidation' @@ -34,6 +35,7 @@ const supportedPlugins = [ ...VSR_PLUGIN_PKS, ...HELIUM_VSR_PLUGINS_PKS, ...GATEWAY_PLUGINS_PKS, + ...QV_PLUGINS_PKS ] const getValidateAccount = async ( @@ -510,9 +512,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 +522,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 +586,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 +596,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 +636,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 +646,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 +718,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 +728,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 +777,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 +787,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 +876,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'), }) } @@ -983,6 +981,172 @@ export const getTokenTransferSchema = ({ }) } +export const getBatchTokenTransferSchema = ({ + form, + connection, + tokenAmount, + mintDecimals, + nftMode, + ignoreAmount, +}: { + form: any + connection: ConnectionContext + tokenAmount?: BN + mintDecimals?: number + nftMode?: boolean + ignoreAmount?: boolean +}) => { + const governedTokenAccount = form.governedTokenAccount as AssetAccount + return yup.object().shape({ + governedTokenAccount: yup.object().required('Source account is required'), + amount: yup.array().of( + yup.number() + .typeError('Amount is required') + .test( + 'amount', + 'Transfer amount must be less than the source account available amount', + async function (val: number) { + const isNft = nftMode || governedTokenAccount?.isNft + if (isNft || ignoreAmount) { + return true + } + if (val && !form.governedTokenAccount) { + return this.createError({ + message: `Please select source account to validate the amount`, + }) + } + if ( + val && + governedTokenAccount && + governedTokenAccount?.extensions.mint + ) { + const mintValue = getMintNaturalAmountFromDecimalAsBN( + val, + typeof mintDecimals !== 'undefined' + ? mintDecimals + : governedTokenAccount?.extensions.mint.account.decimals + ) + if (tokenAmount) { + return tokenAmount.gte(mintValue) + } + return !!(governedTokenAccount?.extensions.token?.publicKey && + !governedTokenAccount.isSol + ? governedTokenAccount.extensions.token.account.amount.gte( + mintValue + ) + : new BN( + governedTokenAccount.extensions.solAccount!.lamports + ).gte(mintValue)) + } + return this.createError({ + message: `Amount is required`, + }) + } + )), + destinationAccount: yup + .array().of( + yup + .string() + .test( + 'accountTests', + 'Account validation error', + async function (val: string) { + if (val) { + try { + if ( + governedTokenAccount?.extensions?.transferAddress?.toBase58() == + val + ) { + return this.createError({ + message: `Destination account address can't be same as source account`, + }) + } + await validateDestinationAccAddress( + connection, + val, + governedTokenAccount?.extensions.transferAddress + ) + return true + } catch (e) { + console.log(e) + return this.createError({ + message: `${e}`, + }) + } + } else { + return this.createError({ + message: `Destination account is required`, + }) + } + } + ) + ), + }) +} + +export const getBurnTokensSchema = ({ + form, + tokenAmount, + mintDecimals, + nftMode, + ignoreAmount, +}: { + form: any + tokenAmount?: BN + mintDecimals?: number + nftMode?: boolean + ignoreAmount?: boolean +}) => { + const governedTokenAccount = form.governedTokenAccount as AssetAccount + return yup.object().shape({ + governedTokenAccount: yup.object().required('Token account is required'), + amount: yup + .number() + .typeError('Amount is required') + .test( + 'amount', + 'Transfer amount must be less than the source account available amount', + async function (val: number) { + const isNft = nftMode || governedTokenAccount?.isNft + if (isNft || ignoreAmount) { + return true + } + if (val && !form.governedTokenAccount) { + return this.createError({ + message: `Please select source account to validate the amount`, + }) + } + if ( + val && + governedTokenAccount && + governedTokenAccount?.extensions.mint + ) { + const mintValue = getMintNaturalAmountFromDecimalAsBN( + val, + typeof mintDecimals !== 'undefined' + ? mintDecimals + : governedTokenAccount?.extensions.mint.account.decimals + ) + if (tokenAmount) { + return tokenAmount.gte(mintValue) + } + return !!(governedTokenAccount?.extensions.token?.publicKey && + !governedTokenAccount.isSol + ? governedTokenAccount.extensions.token.account.amount.gte( + mintValue + ) + : new BN( + governedTokenAccount.extensions.solAccount!.lamports + ).gte(mintValue)) + } + return this.createError({ + message: `Amount is required`, + }) + } + ), + }) +} + export const getMintSchema = ({ form, connection }) => { return yup.object().shape({ amount: yup diff --git a/verify-wallet/components/footer.tsx b/verify-wallet/components/footer.tsx index d5265f6a12..19b89c6b26 100644 --- a/verify-wallet/components/footer.tsx +++ b/verify-wallet/components/footer.tsx @@ -33,7 +33,7 @@ export function GlobalFooter(props: Props) { 'sm:text-sm', )} > -
© {year} Solana Technology Services LLC
+
© {year} Realms Today Ltd
|
Terms diff --git a/yarn.lock b/yarn.lock index 9d689e99e0..100510001d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,11 @@ # yarn lockfile v1 +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== + "@ampproject/remapping@^2.1.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" @@ -280,14 +285,7 @@ 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== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.22.6": +"@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.6.2", "@babel/runtime@^7.7.2", "@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== @@ -333,10 +331,10 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@blockworks-foundation/mango-mints-redemption@0.0.10": - version "0.0.10" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-mints-redemption/-/mango-mints-redemption-0.0.10.tgz#51a9a3f8b9278e9686da96747b05b019087e3d37" - integrity sha512-8HR1xUzI1pOvbYqVV3afRm9YcSysI/9j/Rk6snw7IU1jTrIEpGgDJGGqwUjotFgKf4Nql2dGwAUrF/dO04W7bQ== +"@blockworks-foundation/mango-mints-redemption@0.0.11": + version "0.0.11" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-mints-redemption/-/mango-mints-redemption-0.0.11.tgz#5b33ec316007c34993a9be8f739af9cb94ebe322" + integrity sha512-kMY0e26xK5LxuLbdnCxexo2oHYT46nv+jNRMMzCDJn3z6JjiQpqYS2EpgvkSSSHa4MjJzonp377GxvYyIfeYxg== dependencies: "@coral-xyz/anchor" "^0.28.0" "@solana/spl-token" "^0.3.8" @@ -344,50 +342,55 @@ keccak256 "^1.0.6" merkletreejs "^0.3.11" -"@blockworks-foundation/mango-v4-settings@0.4.4": - version "0.4.4" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.4.4.tgz#e171020b1bbe21d68fde89169ba1b437a4a2f260" - integrity sha512-UQIzR2c3USt75oJVb/HkUr6UhqQXwyvv3hAgcxGvw6c6pO08cjP3YlbXegCJDSk0V2Fck3WtFU/25+A0N6e5hw== - dependencies: - bn.js "^5.2.1" - eslint-config-prettier "^9.0.0" - -"@blockworks-foundation/mango-v4-settings@^0.2.16": - version "0.2.17" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.2.17.tgz#ebc64eb037137bdd16df93cdb63badc7f178542b" - integrity sha512-k4Hi0Rjq3XbWnN4Hvdd2aDrm24Ob+8+WDCz7hzR+XKCQ0HcYQXVrZn2Yz7e9IA4M3zQEP9n5HHnQopLQb8UgMw== +"@blockworks-foundation/mango-v4-settings@0.14.24": + version "0.14.24" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4-settings/-/mango-v4-settings-0.14.24.tgz#646b0802fb6222654e247bea7966106af9b7a970" + integrity sha512-X3mY2x6XSZTySfB65b5DWuE7v/tffMlFGXQsgv+Zl+cgHdJn77vqdXvQFlR+544xsTjK+kWpWiHTHiSWRzG/4Q== dependencies: bn.js "^5.2.1" eslint-config-prettier "^9.0.0" -"@blockworks-foundation/mango-v4@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.21.5.tgz#5e3b3257de0a0efc98c1f9057982e434c1665120" - integrity sha512-tCBFb+eBltsJbFkcBPBgfk5Wzmwa+9MfNU7FTWX8vMycl+ck4svE8K05HEO25dWRSJmZbwx8osGxaqCsricAbQ== - dependencies: - "@blockworks-foundation/mango-v4-settings" "^0.2.16" - "@coral-xyz/anchor" "^0.28.1-beta.2" +"@blockworks-foundation/mango-v4@0.33.6": + version "0.33.6" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mango-v4/-/mango-v4-0.33.6.tgz#d7aac0f1d0d2a647364188840261a78dd0e785dd" + integrity sha512-QC2mTprJ7/zrl+C61BPTZXdnvZD9HhhAQpadBxQ3BMtj8seoKTSC9RqKr+rq8GpxWVgALJcwXuxzOngu/Lr5LA== + dependencies: + "@blockworks-foundation/mango-v4-settings" "0.14.24" + "@blockworks-foundation/mangolana" "0.1.2" + "@coral-xyz/anchor" "^0.29.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "^9.8.0" + "@iarna/toml" "2.2.5" "@project-serum/serum" "0.13.65" - "@pythnetwork/client" "~2.14.0" - "@solana/spl-token" "0.3.7" - "@solana/web3.js" "^1.78.2" + "@pythnetwork/client" "~2.21.1" + "@raydium-io/raydium-sdk" "^1.3.1-beta.57" + "@solana/spl-token" "0.4.8" + "@solana/web3.js" "^1.95.2" + "@switchboard-xyz/common" "^2.4.4" + "@switchboard-xyz/on-demand" "^1.2.38" "@switchboard-xyz/sbv2-lite" "^0.1.6" + "@switchboard-xyz/solana.js" "^3.2.5" big.js "^6.1.1" - binance-api-node "^0.12.0" + binance-api-node "^0.12.7" 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" + switchboard-anchor "npm:@coral-xyz/anchor@0.30.1" -"@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.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/mangolana/-/mangolana-0.1.2.tgz#3b7ec1cd8a21c2fedd559dabb1e2212278a08ad4" + integrity sha512-eU+z1K29M6zzpAqwHcHCoZA+O4g+QPNM4PXsDygueZarqgsG6FehLoqWBV43w3uSFCl8Cb5op+fE/HufQ9xKww== dependencies: - "@solana/web3.js" "^1.63.1" + "@solana/promises" "2.0.0-canary-20240812091942" + "@solana/web3.js" "^1.95.2" bs58 "^5.0.0" - node-fetch "^3.2.10" + isomorphic-ws "^5.0.0" + node-fetch "3.3.2" + ws "^8.18.0" "@blocto/sdk@^0.2.22": version "0.2.22" @@ -419,6 +422,13 @@ "@bonfida/name-offers" "^0.0.1" "@ethersproject/sha2" "^5.5.0" +"@brokerloop/ttlcache@^3.2.3": + version "3.2.3" + resolved "https://registry.yarnpkg.com/@brokerloop/ttlcache/-/ttlcache-3.2.3.tgz#bc3c79bb381f7b43f83745eb96e86673f75d3d11" + integrity sha512-kZWoyJGBYTv1cL5oHBYEixlJysJBf2RVnub3gbclD+dwaW9aKubbHzbZ9q1q6bONosxaOqMsoBorOrZKzBDiqg== + dependencies: + "@soncodi/signal" "~2.0.7" + "@bundlr-network/client@0.7.15", "@bundlr-network/client@^0.8.8": version "0.7.15" resolved "https://registry.yarnpkg.com/@bundlr-network/client/-/client-0.7.15.tgz#099c5edf287878465686bd01e29638958badabb1" @@ -619,16 +629,16 @@ eventemitter3 "^4.0.7" uuid "^8.3.2" -"@civic/common-gateway-react@0.11.0": - version "0.11.0" - resolved "https://registry.yarnpkg.com/@civic/common-gateway-react/-/common-gateway-react-0.11.0.tgz#255f4f03fc99cc899b734276ef1630dd93c61d68" - integrity sha512-DmFagjg5J39+dtUOMEWUneMSlaN++FjFVuAta8w026t/6zfXIwNWDnyxJw8FkfcqJFVFDaUDPaVNGNlolnm32A== +"@civic/common-gateway-react@0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@civic/common-gateway-react/-/common-gateway-react-0.11.10.tgz#90421d6c02077eadd495ddd24c0304acb86f5086" + integrity sha512-gwS2XfiEGdqqEyG6XHM1rG1Fi5lX4dNjm2Whg56sFDrQwwSJWhaio8LxMXYFOeE6NCqAgVNDtcbX8gV58//33w== dependencies: fetch-retry "^5.0.6" iframe-resizer-react "^1.1.0" - ramda "^0.27.1" + ramda "^0.28.0" styled-components "^5.3.1" - uuid "^9.0.0" + uuid "^9.0.1" "@civic/did-registry@0.0.6-alpha.2": version "0.0.6-alpha.2" @@ -670,15 +680,16 @@ did-resolver "^3.2.0" ramda "^0.29.0" -"@civic/solana-gateway-react@0.15.0": - version "0.15.0" - resolved "https://registry.yarnpkg.com/@civic/solana-gateway-react/-/solana-gateway-react-0.15.0.tgz#a6800647363f6ef1ae856d48010e65e28ec78d6e" - integrity sha512-MBfDvN94KuZd/YW3B4Koyf+Na9MrI14aj7D1Woh1LghRWhiDO1de4svd3hN2o/daogt+dPPfMhwLaM7kpmcOlw== +"@civic/solana-gateway-react@^0.16.10": + version "0.16.11" + resolved "https://registry.yarnpkg.com/@civic/solana-gateway-react/-/solana-gateway-react-0.16.11.tgz#1524fd87caa359c5d78c9fb84f85be4c08179b2c" + integrity sha512-N/5n1ozpLdWPTgzjC95AiCBJsiGpNqVwoXeDYNXAtJTXnxKpoIXtfMFjrGlWmSIVovRFDSaBu6d2UYcCKR1v/A== dependencies: - "@civic/common-gateway-react" "0.11.0" + "@civic/common-gateway-react" "0.11.10" "@identity.com/prove-solana-wallet" "0.4.2" - "@identity.com/solana-gateway-ts" "0.11.0-alpha.5" + "@identity.com/solana-gateway-ts" "^0.12.0" "@solana/web3.js" "^1.73.0" + prop-types "^15.8.1" ramda "^0.28.0" "@civic/storage-adapter@*": @@ -688,14 +699,15 @@ dependencies: ajv "^8.12.0" -"@coral-xyz/anchor@0.26.0", "@coral-xyz/anchor@^0.26.0": - version "0.26.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.26.0.tgz#c8e4f7177e93441afd030f22d777d54d0194d7d1" - integrity sha512-PxRl+wu5YyptWiR9F2MBHOLLibm87Z4IMUBPreX+DYBtPM+xggvcPi0KAN7+kIL4IrIhXI8ma5V0MCXxSN1pHg== +"@coral-xyz/anchor-30@npm:@coral-xyz/anchor@0.30.1", "@coral-xyz/anchor@0.30.1", "@coral-xyz/anchor@^0.30.1", "switchboard-anchor@npm:@coral-xyz/anchor@0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.1.tgz#17f3e9134c28cd0ea83574c6bab4e410bcecec5d" + integrity sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ== dependencies: - "@coral-xyz/borsh" "^0.26.0" + "@coral-xyz/anchor-errors" "^0.30.1" + "@coral-xyz/borsh" "^0.30.1" + "@noble/hashes" "^1.3.1" "@solana/web3.js" "^1.68.0" - base64-js "^1.5.1" bn.js "^5.1.2" bs58 "^4.0.1" buffer-layout "^1.2.2" @@ -703,42 +715,24 @@ 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" superstruct "^0.15.4" toml "^3.0.0" -"@coral-xyz/anchor@0.27.0": - version "0.27.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.27.0.tgz#621e5ef123d05811b97e49973b4ed7ede27c705c" - integrity sha512-+P/vPdORawvg3A9Wj02iquxb4T0C5m4P6aZBVYysKl4Amk+r6aMPZkUhilBkD6E4Nuxnoajv3CFykUfkGE0n5g== - dependencies: - "@coral-xyz/borsh" "^0.27.0" - "@solana/web3.js" "^1.68.0" - base64-js "^1.5.1" - 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" - js-sha256 "^0.9.0" - pako "^2.0.3" - snake-case "^3.0.4" - superstruct "^0.15.4" - toml "^3.0.0" +"@coral-xyz/anchor-errors@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" + integrity sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ== -"@coral-xyz/anchor@0.28.1-beta.2", "@coral-xyz/anchor@^0.28.1-beta.2": - version "0.28.1-beta.2" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.28.1-beta.2.tgz#4ddd4b2b66af04407be47cf9524147793ec514a0" - integrity sha512-xreUcOFF8+IQKWOBUrDKJbIw2ftpRVybFlEPVrbSlOBCbreCWrQ5754Gt9cHIcuBDAzearCDiBqzsGQdNgPJiw== +"@coral-xyz/anchor@0.26.0", "@coral-xyz/anchor@0.28.1-beta.2", "@coral-xyz/anchor@0.29.0", "@coral-xyz/anchor@^0.26.0", "@coral-xyz/anchor@^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.28.0" + "@coral-xyz/borsh" "^0.29.0" "@noble/hashes" "^1.3.1" "@solana/web3.js" "^1.68.0" - base64-js "^1.5.1" bn.js "^5.1.2" bs58 "^4.0.1" buffer-layout "^1.2.2" @@ -751,28 +745,7 @@ superstruct "^0.15.4" toml "^3.0.0" -"@coral-xyz/anchor@^0.28.0": - version "0.28.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.28.0.tgz#8345c3c9186a91f095f704d7b90cd256f7e8b2dc" - integrity sha512-kQ02Hv2ZqxtWP30WN1d4xxT4QqlOXYDxmEd3k/bbneqhV3X5QMO4LAtoUFs7otxyivOgoqam5Il5qx81FuI4vw== - dependencies: - "@coral-xyz/borsh" "^0.28.0" - "@solana/web3.js" "^1.68.0" - base64-js "^1.5.1" - 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" - js-sha256 "^0.9.0" - 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.27.0", "@coral-xyz/borsh@^0.26.0", "@coral-xyz/borsh@^0.28.0", "@coral-xyz/borsh@^0.29.0", "@coral-xyz/borsh@^0.30.1": 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== @@ -792,87 +765,64 @@ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== -"@dialectlabs/blockchain-sdk-solana@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@dialectlabs/blockchain-sdk-solana/-/blockchain-sdk-solana-1.0.1.tgz#da115357ec2aca34b55708c7a0f1c36f05770d9c" - integrity sha512-W/1qN89zAr5IU5V4zoiTlgeeWtDUCGBEaYMZ1hSnJAEs45lcMqvxcUEa9kNjPFVSbJf13QHHgE+EtmDCxA0SmQ== - dependencies: - "@dialectlabs/web3" "^0.3.2" - "@project-serum/anchor" "0.23.0" +"@dialectlabs/blockchain-sdk-solana@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@dialectlabs/blockchain-sdk-solana/-/blockchain-sdk-solana-1.2.0.tgz#9bc73519d0ba326b6e5dda90972e617f8d8e5265" + integrity sha512-gluOP6+xEWmL59BCvZBQhisn91+lrGRE8NJ5oRRjgbRjgsLOR0xYGzNe4LSfB6CYG26Yv1kLPIRGsqHZQf+pNg== -"@dialectlabs/react-sdk-blockchain-solana@1.0.0-beta.3": - version "1.0.0-beta.3" - resolved "https://registry.yarnpkg.com/@dialectlabs/react-sdk-blockchain-solana/-/react-sdk-blockchain-solana-1.0.0-beta.3.tgz#635c3cecc006de43c602c7d2c309dbe0cffc479d" - integrity sha512-8v/bNKxAmC6L/+iiC+mXb3o8JjpVkJ8F5g5aQ3WchQLpKs04GWSYYYTenrK9Wz2wMoqXWqVQbcQJkQ/KoN8rAg== +"@dialectlabs/react-sdk-blockchain-solana@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@dialectlabs/react-sdk-blockchain-solana/-/react-sdk-blockchain-solana-2.0.3.tgz#65da74f5f9004f504532fadc7181b8ae20dcb44f" + integrity sha512-yMPs3cMA0NkA9Gx91Gx2XspiaXs4TrP23XTuJj0mhlrW7srs0OyryzRdc+ZBtTqD/TGjICxAASBpZBXlljBA9Q== dependencies: - "@dialectlabs/blockchain-sdk-solana" "^1.0.0" + "@dialectlabs/blockchain-sdk-solana" "^1.2.0" + "@dialectlabs/react-sdk" "^2.0.2" -"@dialectlabs/react-sdk@1.1.0-beta.3": - version "1.1.0-beta.3" - resolved "https://registry.yarnpkg.com/@dialectlabs/react-sdk/-/react-sdk-1.1.0-beta.3.tgz#c50d7c7c1c5971a6e5307ad8bedb9052098be1f9" - integrity sha512-rxZpTuzS0yyDV1sYVaSt3qxFHJrQhZOM91oxBSu8cWMFyem4jBwAorofjTnO9gW/qL4Gj/2Ie62BjgD39ngitQ== +"@dialectlabs/react-sdk@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dialectlabs/react-sdk/-/react-sdk-2.0.2.tgz#84990b7776496f121c87f804295630d670fa78c1" + integrity sha512-01Jc1IqrdKSS9xxAVKqhT6lKr5KCMjXjonh36fh/F0ga+Zr+J2X0IsLiMgJ6NKPbnSkRX2HqwaPbZtnV2xknTA== dependencies: - "@dialectlabs/sdk" "1.1.0" - nanoid "^3.3.4" - swr "^1.3.0" + "@dialectlabs/sdk" "^1.8.0" + swr "^2.2.5" -"@dialectlabs/react-ui@1.1.0-beta.5": - version "1.1.0-beta.5" - resolved "https://registry.yarnpkg.com/@dialectlabs/react-ui/-/react-ui-1.1.0-beta.5.tgz#18bd7aadf12e666737f93ef947ab900f32206b49" - integrity sha512-3KTD64sZ6yRoTaquPA5G874j8Cs/UdWu9TLfoooNlSN0JrVkPMa/T5fnGs6f0QaWgAi2YtByAa4BzGJWLT5ZBA== +"@dialectlabs/react-ui@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@dialectlabs/react-ui/-/react-ui-2.0.7.tgz#b1f6a01f5bb731341bdd2f89d79018f53b835a2f" + integrity sha512-t2nuoG6+Ig1vETsyPI6rSN7xxObNy+lsSyFbqyaVODKhmcnxsGehqkFyGqWgzPDUVrpcxkgepe2SFwHHpDuDtA== dependencies: - "@dialectlabs/react-sdk" "1.1.0-beta.3" - "@headlessui/react" "^1.7.3" - clsx "^1.2.1" - focus-visible "^5.2.0" - immer "^9.0.14" - react-linkify "^1.0.0-alpha" - react-media-hook "^0.4.9" - react-transition-group "^4.4.2" - swr "^1.3.0" + "@dialectlabs/react-sdk" "^2.0.2" + clsx "^2.1.0" + react-tiny-linkify "^1.2.0" -"@dialectlabs/sdk@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@dialectlabs/sdk/-/sdk-1.1.0.tgz#db7a65fbf89274a5607314c36079566309ebd147" - integrity sha512-jMU1VCUi5H3RPt+cCzZcCCS7T+MG5duCuO2lR9/siEoZSmU9V3y7MjPBbdcMKRB96Nj/5oza0Ey1TyeUEo1e0g== +"@dialectlabs/sdk@^1.8.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@dialectlabs/sdk/-/sdk-1.9.0.tgz#13bdccf187767d1584ce74b3cd065cd25c06e047" + integrity sha512-vXAFRL6L/+vzJVFUR0JbOghzEabM1CMKKWcYZ28UHCBwedLloY6fBD02xtKXHlUq2bTJikblWHtBFtIcOIMoqQ== dependencies: "@stablelib/base64" "^1.0.1" axios "^0.27.2" bs58 "^5.0.0" ed2curve "^0.3.0" js-sha3 "^0.8.0" - luxon "^2.4.0" nanoid "^3.3.4" tweetnacl "^1.0.3" -"@dialectlabs/web3@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@dialectlabs/web3/-/web3-0.3.2.tgz#465409691053cfe98054e1113b47285993ca2ccf" - integrity sha512-pBay/M6aaMNyHvZgwjDZsta+aqTrmhJ0b+8qeVqkOzCrAgO/H5kCcz2tAoRypCnWi9U0BJaguwr4dHP8jFperA== - dependencies: - "@project-serum/anchor" "0.23.0" - "@solana/spl-token" "^0.1.8" - "@solana/web3.js" "^1.22.0" - bytebuffer "^5.0.1" - copy-to-clipboard "^3.3.1" - ed2curve "0.3.0" - js-sha256 "^0.9.0" - tweetnacl "1.0.3" - -"@dual-finance/airdrop@0.2.2": - version "0.2.2" - resolved "https://registry.yarnpkg.com/@dual-finance/airdrop/-/airdrop-0.2.2.tgz#cb0c0c1ccc15989f7cb94e68fb9282797a560912" - integrity sha512-z1b8XkTxJJGmaPDbjdQaoBIuWgCMHQmtDBdIDL0pEhW4VQol78zQw2IcFPS7JvDHSAsDvNZSoYcYe9gRNeHyXg== +"@dual-finance/airdrop@0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@dual-finance/airdrop/-/airdrop-0.3.1.tgz#64b697ee0e82da69d50ab5be517929a11fc2f138" + integrity sha512-V+6wcyyWZfLB6Yj1gUMlTO+DptsG21kumh+TF38e6Z/Z8Fu9I3c8mNY1Dh8KZNCZwlw2cF+PB2fO2kWUqvd/ZA== dependencies: "@coral-xyz/anchor" "^0.26.0" "@solana/spl-token" "^0.3.6" "@solana/web3.js" "^1.73.2" + bs58 "^5.0.0" 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" @@ -1057,21 +1007,172 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz#ea89004119dc42db2e1dba0f97d553f7372f6fcb" integrity sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg== -"@eslint/eslintrc@^1.3.0": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95" - integrity sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg== +"@esbuild/aix-ppc64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz#145b74d5e4a5223489cabdc238d8dad902df5259" + integrity sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ== + +"@esbuild/android-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz#453bbe079fc8d364d4c5545069e8260228559832" + integrity sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ== + +"@esbuild/android-arm@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.23.0.tgz#26c806853aa4a4f7e683e519cd9d68e201ebcf99" + integrity sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g== + +"@esbuild/android-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.23.0.tgz#1e51af9a6ac1f7143769f7ee58df5b274ed202e6" + integrity sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ== + +"@esbuild/darwin-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz#d996187a606c9534173ebd78c58098a44dd7ef9e" + integrity sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow== + +"@esbuild/darwin-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz#30c8f28a7ef4e32fe46501434ebe6b0912e9e86c" + integrity sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ== + +"@esbuild/freebsd-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz#30f4fcec8167c08a6e8af9fc14b66152232e7fb4" + integrity sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw== + +"@esbuild/freebsd-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz#1003a6668fe1f5d4439e6813e5b09a92981bc79d" + integrity sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ== + +"@esbuild/linux-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz#3b9a56abfb1410bb6c9138790f062587df3e6e3a" + integrity sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw== + +"@esbuild/linux-arm@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz#237a8548e3da2c48cd79ae339a588f03d1889aad" + integrity sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw== + +"@esbuild/linux-ia32@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz#4269cd19cb2de5de03a7ccfc8855dde3d284a238" + integrity sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA== + +"@esbuild/linux-loong64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz#82b568f5658a52580827cc891cb69d2cb4f86280" + integrity sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A== + +"@esbuild/linux-mips64el@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz#9a57386c926262ae9861c929a6023ed9d43f73e5" + integrity sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w== + +"@esbuild/linux-ppc64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz#f3a79fd636ba0c82285d227eb20ed8e31b4444f6" + integrity sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw== + +"@esbuild/linux-riscv64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz#f9d2ef8356ce6ce140f76029680558126b74c780" + integrity sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw== + +"@esbuild/linux-s390x@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz#45390f12e802201f38a0229e216a6aed4351dfe8" + integrity sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg== + +"@esbuild/linux-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz#c8409761996e3f6db29abcf9b05bee8d7d80e910" + integrity sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ== + +"@esbuild/netbsd-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz#ba70db0114380d5f6cfb9003f1d378ce989cd65c" + integrity sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw== + +"@esbuild/openbsd-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz#72fc55f0b189f7a882e3cf23f332370d69dfd5db" + integrity sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ== + +"@esbuild/openbsd-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz#b6ae7a0911c18fe30da3db1d6d17a497a550e5d8" + integrity sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg== + +"@esbuild/sunos-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz#58f0d5e55b9b21a086bfafaa29f62a3eb3470ad8" + integrity sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA== + +"@esbuild/win32-arm64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz#b858b2432edfad62e945d5c7c9e5ddd0f528ca6d" + integrity sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ== + +"@esbuild/win32-ia32@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz#167ef6ca22a476c6c0c014a58b4f43ae4b80dec7" + integrity sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA== + +"@esbuild/win32-x64@0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz#db44a6a08520b5f25bbe409f34a59f2d4bcc7ced" + integrity sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": + version "4.11.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae" + integrity sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A== + +"@eslint/config-array@^0.17.1": + version "0.17.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.17.1.tgz#d9b8b8b6b946f47388f32bedfd3adf29ca8f8910" + integrity sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.4.0" - globals "^13.15.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@9.9.0", "@eslint/js@^9.8.0": + version "9.9.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.0.tgz#d8437adda50b3ed4401964517b64b4f59b0e2638" + integrity sha512-hhetes6ZHP3BlXLxmd8K2SNgkhNSi+UcecbnwWKwpP7kyi/uC75DJ1lOOBO3xrC4jyojtGE3YxKZPHfk4yrgug== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" @@ -1434,20 +1535,6 @@ "@floating-ui/dom" "^0.5.3" use-isomorphic-layout-effect "^1.1.1" -"@foresight-tmp/foresight-sdk@0.1.46": - version "0.1.46" - resolved "https://registry.yarnpkg.com/@foresight-tmp/foresight-sdk/-/foresight-sdk-0.1.46.tgz#f928dde22f424cfd438f8c9116d5ce84f5b56864" - integrity sha512-fqYnT+OrRDe84OWoDGow4KB5KYX/sRP+jg0Ylz0ExdNqoewK8gLmmAg6AvPc+B9ItAhcDhEBf0H/cGG6HpIQdw== - dependencies: - "@project-serum/anchor" "^0.23.0" - "@project-serum/serum" "0.13.64" - "@solana/web3.js" "^1.37.1" - assert "^2.0.0" - axios "^0.24.0" - buffer-layout "^1.2.2" - lodash "^4.17.21" - process "^0.11.10" - "@fractalwagmi/popup-connection@^1.0.18": version "1.0.21" resolved "https://registry.yarnpkg.com/@fractalwagmi/popup-connection/-/popup-connection-1.0.21.tgz#a1d76c8e6f0efa2187795c7d9db648ffaffb25f2" @@ -1462,18 +1549,29 @@ "@solana/wallet-adapter-base" "^0.9.17" bs58 "^5.0.0" +"@grpc/grpc-js@^1.8.13": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.11.1.tgz#a92f33e98f1959feffcd1b25a33b113d2c977b70" + integrity sha512-gyt/WayZrVPH2w/UTLansS7F9Nwld472JxxaETamrM8HNlsa+jSLNyKAZmhxI2Me4c3mQHFiS1wWHDY1g1Kthw== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@headlessui/react@1.6.6": version "1.6.6" resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.6.6.tgz#3073c066b85535c9d28783da0a4d9288b5354d0c" integrity sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q== -"@headlessui/react@^1.7.3": - version "1.7.6" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.6.tgz#578fcd336955e4afcae8f223b26f8a121941c9ee" - integrity sha512-yM/IOGCRaS/DaQRchElrTiH0jOfYWbBX5wkZTAbPDu4OMYdQ1ateM/UgApOcv+7DNpeRaMjUz4bZ4xxNgTGNLA== - dependencies: - client-only "^0.0.1" - "@helium/address@^4.8.1": version "4.8.1" resolved "https://registry.yarnpkg.com/@helium/address/-/address-4.8.1.tgz#d8d7cefc6aa7791d79eb8759befb821aaccec3ff" @@ -1568,19 +1666,20 @@ resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.8.10.tgz#b66d7a7848b1b1dd5b976a73fff36bb366666e7d" integrity sha512-DDFtNlugsbwAhCJHYp3NcN5LvJrwSsCLPi41Wo5O8UAIbUFnBfY/jW+zKnlX57BZ4jE0j/g6R9rB3JlO89ad0g== -"@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.0.tgz#6d86b8cb322660f03d3f0aa94b99bdd8e172d570" + integrity sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew== + +"@iarna/toml@2.2.5": + version "2.2.5" + resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c" + integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg== "@identity.com/prove-solana-wallet@0.4.2": version "0.4.2" @@ -1622,10 +1721,10 @@ resolved "https://registry.yarnpkg.com/@identity.com/sol-did-idl/-/sol-did-idl-3.1.0.tgz#dfd00b0f80aeed25ff898a7bd95320df3abc337d" integrity sha512-umy6Adt9d7v50iduN02L5hzxK9742va0yZxFDsTopXcYAgTW/jQ/xsR5Q4VTuqJXtn6szhIO1q0hbNHScq22Cg== -"@identity.com/solana-gateway-ts@0.11.0-alpha.5": - version "0.11.0-alpha.5" - resolved "https://registry.yarnpkg.com/@identity.com/solana-gateway-ts/-/solana-gateway-ts-0.11.0-alpha.5.tgz#63bd8de3909eb5c190948657f6aef450adf7efdd" - integrity sha512-QF4haQ8rL9ipqlov7B9eCHNsdiyq9rSroJeM7e5JqrslW5684jlYjvKjcZhmYo37ameE8WEVaC7i8tVyx42dYw== +"@identity.com/solana-gateway-ts@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@identity.com/solana-gateway-ts/-/solana-gateway-ts-0.12.0.tgz#8954dfacd0c4f3b02437541d6ab15a8069a6814b" + integrity sha512-VF3sjYLu9mD2fvSyTfR07HYRz3LnEhZPtqZ53Jmm3+CnlabsVLLShSvCvPSz+4TQtD/4gNKMG1VAJenxBr8W5Q== dependencies: "@solana/web3.js" "^1.63.0" async-retry "^1.3.3" @@ -1634,6 +1733,23 @@ 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== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@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" @@ -1853,13 +1969,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" @@ -1880,22 +1996,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== @@ -1916,6 +2037,11 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@json-rpc-tools/provider@^1.5.5": version "1.7.6" resolved "https://registry.yarnpkg.com/@json-rpc-tools/provider/-/provider-1.7.6.tgz#8a17c34c493fa892632e278fd9331104e8491ec6" @@ -2550,28 +2676,35 @@ dependencies: "@react-spring/web" "9.3.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== +"@noble/curves@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" + integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw== dependencies: - "@noble/hashes" "1.3.3" + "@noble/hashes" "1.3.2" + +"@noble/curves@^1.1.0", "@noble/curves@^1.2.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" "@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.3.3", "@noble/hashes@^1.3.0": - 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== - -"@noble/hashes@^1.1.3", "@noble/hashes@^1.3.1": +"@noble/hashes@1.3.2": version "1.3.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== +"@noble/hashes@1.4.0", "@noble/hashes@^1.1.3", "@noble/hashes@^1.3.1": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2585,7 +2718,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -2593,35 +2726,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@notifi-network/notifi-axios-adapter@^0.18.2": - version "0.18.2" - resolved "https://registry.yarnpkg.com/@notifi-network/notifi-axios-adapter/-/notifi-axios-adapter-0.18.2.tgz#3ad4dd179a48aec1ce0030e5c0c67dd37c7d88ec" - integrity sha512-rxE1ScDPZj94Ww6mq/cxA86tA4P0751SDTWt+ANMzZPWgNQO0CmZiZTWfjoS+lwZUpDyh6EMrZaGxsZX28Sa1Q== - dependencies: - "@notifi-network/notifi-axios-utils" "^0.18.2" - -"@notifi-network/notifi-axios-utils@^0.18.2": - version "0.18.2" - resolved "https://registry.yarnpkg.com/@notifi-network/notifi-axios-utils/-/notifi-axios-utils-0.18.2.tgz#805e28554c5fd83bb66212b7ee42d777a4f5379d" - integrity sha512-tKeBB35XqB4nDGDtV+iZogNEt+wrwJ6w7Lw4tw1+SkhV65socs8gnXQgcDT/xtzXCNikaEr3Rfm4knw9XaGXOQ== - -"@notifi-network/notifi-core@0.18.2": - version "0.18.2" - resolved "https://registry.yarnpkg.com/@notifi-network/notifi-core/-/notifi-core-0.18.2.tgz#f2a5742efe2cf80b02539f2f95ee8469c1788639" - integrity sha512-CFU76YbYQ5ztvMtu2dPzPisOm1Wgm12g8R6wOgwQc9dNiBW+B/IL2uuT2k4uxgtRW1Bz03kxGVmaH0VjYUkF8A== - -"@notifi-network/notifi-react-hooks@0.18.2": - version "0.18.2" - resolved "https://registry.yarnpkg.com/@notifi-network/notifi-react-hooks/-/notifi-react-hooks-0.18.2.tgz#6c24744857480945071f6ab5cda25c46128a650b" - integrity sha512-TOwg0P8K15OjSgIJZNbmg9qor+eWSOdtJB0wvuP2DMjdi2ataOPJWvBJ7Y+sf33mOfPFjw9vn0SgZgxPPQBEvA== - dependencies: - "@notifi-network/notifi-axios-adapter" "^0.18.2" - "@notifi-network/notifi-axios-utils" "^0.18.2" - axios "^0.26.0" - localforage "^1.10.0" - typedoc-plugin-missing-exports "^0.22.6" - typescript "^4.5.5" - "@npmcli/node-gyp@^1.0.2": version "1.0.3" resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz#a912e637418ffc5f2db375e93b85837691a43a33" @@ -2644,6 +2748,119 @@ 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" + +"@parcl-oss/staking-wasm@*": + version "0.0.0" + resolved "https://registry.yarnpkg.com/@parcl-oss/staking-wasm/-/staking-wasm-0.0.0.tgz#1fd89d9372eb29968b69ba4f683dfd7953889623" + integrity sha512-SwlhhBjLf79R9ipi25324OljPQWssmkgwOo/h2XJ9sAy81mfwYzwHlzx6FbxdlfQgtxXjtOQKI9BjUssrYOSJg== + +"@parcl-oss/staking@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@parcl-oss/staking/-/staking-0.0.2.tgz#0e49fef441d0fcdb926820c01edb498354a5f445" + integrity sha512-vEY2IrKFCUVpc1Z2/h/wcojX/w1yhvsx+SyayW+1ZqJvoc1ngnet5sgqMPfXSL/FVsapdoeGxh87NznroZ/iOw== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@parcl-oss/staking-wasm" "*" + "@pythnetwork/solana-utils" "^0.4.1" + "@solana/spl-governance" "0.3.26" + "@solana/spl-token" "^0.1.8" + "@solana/web3.js" "^1.87.5" + encoding "^0.1.13" + ethers "^6.10.0" + ts-node "^10.7.0" + typescript "^4.3.5" + "@particle-network/auth@^0.5.5": version "0.5.6" resolved "https://registry.yarnpkg.com/@particle-network/auth/-/auth-0.5.6.tgz#058e00980511fdf72189b6d4a7576e67934a008a" @@ -2664,6 +2881,16 @@ resolved "https://registry.yarnpkg.com/@pedrouid/environment/-/environment-1.0.1.tgz#858f0f8a057340e0b250398b75ead77d6f4342ec" integrity sha512-HaW78NszGzRZd9SeoI3JD11JqY+lubnaOx7Pewj5pfjqWXOEATpeKIFb9Z4t2WBUK2iryiXX3lzWwmYWgUL0Ug== +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@polka/url@^1.0.0-next.20": version "1.0.0-next.21" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" @@ -2736,26 +2963,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" @@ -2838,6 +3045,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" @@ -2881,7 +3108,7 @@ bn.js "^5.1.2" superstruct "0.8.3" -"@project-serum/serum@0.13.64", "@project-serum/serum@0.13.65", "@project-serum/serum@^0.13.21", "@project-serum/serum@^0.13.61": +"@project-serum/serum@0.13.65", "@project-serum/serum@^0.13.21", "@project-serum/serum@^0.13.61": version "0.13.65" resolved "https://registry.yarnpkg.com/@project-serum/serum/-/serum-0.13.65.tgz#6d3cf07912f13985765237f053cca716fe84b0b0" integrity sha512-BHRqsTqPSfFB5p+MgI2pjvMBAQtO8ibTK2fYY96boIFkCI3TTwXDt2gUmspeChKO2pqHr5aKevmexzAcXxrSRA== @@ -2892,7 +3119,7 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" -"@project-serum/sol-wallet-adapter@0.2.0", "@project-serum/sol-wallet-adapter@0.2.6", "@project-serum/sol-wallet-adapter@^0.2.6": +"@project-serum/sol-wallet-adapter@0.2.6", "@project-serum/sol-wallet-adapter@^0.2.6": version "0.2.6" resolved "https://registry.yarnpkg.com/@project-serum/sol-wallet-adapter/-/sol-wallet-adapter-0.2.6.tgz#b4cd25a566294354427c97c26d716112b91a0107" integrity sha512-cpIb13aWPW8y4KzkZAPDgw+Kb+DXjCC6rZoH74MGm3I/6e/zKyGnfAuW5olb2zxonFqsYgnv7ev8MQnvSgJ3/g== @@ -2953,7 +3180,7 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== -"@pythnetwork/client@2.17.0", "@pythnetwork/client@^2.5.1": +"@pythnetwork/client@2.17.0": version "2.17.0" resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.17.0.tgz#b155af06958f4b729bfee1c07130c556598cf168" integrity sha512-hv285vehmLH6N762Z4jqvPTM+hCYnXQaUp6DMgLUpDHvE0mTbwW9PvlxYoUJZGtyeCDkgn9HrTWXPtnaXTRr+Q== @@ -2962,32 +3189,40 @@ "@coral-xyz/borsh" "^0.26.0" buffer "^6.0.1" -"@pythnetwork/client@~2.14.0": - version "2.14.0" - resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.14.0.tgz#0c12a7e1bcc66ff198fdb64c003b8d4a24431efc" - integrity sha512-tFLGnuIBjlzDa8TrJULzJIdykketGXDJZtO+8+i4XO9l2uOKXzxt+pjt05ng5B9iY63FzJqgAkawT/O3V0NAdQ== +"@pythnetwork/client@^2.5.1", "@pythnetwork/client@~2.21.1": + version "2.21.1" + resolved "https://registry.yarnpkg.com/@pythnetwork/client/-/client-2.21.1.tgz#524a278432dcec14fcf8ba67dfd4720df19b5cc3" + integrity sha512-nSpI1qjmbyrFTetfJSDqjzT+AAJYG3xUmDYFnExAFrnhiO5C8FPvMw1zkSYXWRvEwHFISKJLsn1sTIqU9ifaCA== dependencies: - "@coral-xyz/anchor" "^0.26.0" + "@coral-xyz/anchor" "^0.29.0" + "@coral-xyz/borsh" "^0.28.0" buffer "^6.0.1" -"@pythnetwork/staking-wasm@*": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@pythnetwork/staking-wasm/-/staking-wasm-0.3.4.tgz#29c0f47467249a4c66814a8aab9eadf2cc008add" - integrity sha512-0ZdaWmueVO5hucdVH4UDfHyBuxtW6UDcrpEFtD/3pq4naQjcgu1u6rK8iL2pgKi8W2UlsB4vwJqay2Sf1sA4mw== +"@pythnetwork/solana-utils@0.4.2", "@pythnetwork/solana-utils@^0.4.1": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@pythnetwork/solana-utils/-/solana-utils-0.4.2.tgz#3e220eed518c02ad702ebb023488afd7c5649a87" + integrity sha512-hKo7Bcs/kDWA5Fnqhg9zJSB94NMoUDIDjHjSi/uvZOzwizISUQI6oY3LWd2CXzNh4f8djjY2BS5iNHaM4cm8Bw== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@solana/web3.js" "^1.90.0" + bs58 "^5.0.0" + jito-ts "^3.0.1" -"@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-sdk@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@pythnetwork/staking-sdk/-/staking-sdk-0.0.2.tgz#38dfd6f8356c6544875c6d06aafa55886b7bc1a5" + integrity sha512-IfHJIJ5ZwF8x86/10/5Gs9SUAj4fgW013OiWekfzXhogI2MT27TFQqpaCGj8ndJ4XVlzMk3MDGRuOmujtGCVGA== dependencies: - "@project-serum/anchor" "0.24.2" - "@pythnetwork/staking-wasm" "*" - "@solana/spl-governance" "0.3.26" - "@solana/spl-token" "^0.1.8" - "@solana/web3.js" "^1.36.0" - encoding "^0.1.13" - ts-node "^10.7.0" - typescript "^4.3.5" + "@coral-xyz/anchor" "^0.30.1" + "@pythnetwork/solana-utils" "0.4.2" + "@solana/spl-governance" "^0.3.28" + "@solana/spl-token" "^0.3.7" + "@solana/web3.js" "^1.95.3" + +"@pythnetwork/staking-wasm@0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@pythnetwork/staking-wasm/-/staking-wasm-0.3.5.tgz#a5e524a721df9613a1f33a1a1c708de0bfcfe89f" + integrity sha512-iQpPPn6kPuc9Q1MO+PMAKAhkuv6AOUHiAZJizCbPm3aO7kS2YxRKsRSMsky9FY1GHHatSx13LX9epsJXi/MmKg== "@radix-ui/number@1.0.0": version "1.0.0" @@ -3669,6 +3904,23 @@ dependencies: "@randlabs/communication-bridge" "1.0.1" +"@raydium-io/raydium-sdk@^1.3.1-beta.57": + version "1.3.1-beta.58" + resolved "https://registry.yarnpkg.com/@raydium-io/raydium-sdk/-/raydium-sdk-1.3.1-beta.58.tgz#cd251bdf58a15b5aa231a0a6e16a86617c06abcc" + integrity sha512-9SMneQktR6CvxOJ6C3PxW8aMtBsg28+OViaSDwNHgZ/gJP47bvUgUTsFSmnut4Mv9blsnYFxyc5eVoIfPdXeJg== + dependencies: + "@solana/buffer-layout" "^4.0.1" + "@solana/spl-token" "^0.3.9" + axios "^1.6.2" + big.js "^6.2.1" + bn.js "^5.2.1" + decimal.js "^10.4.3" + decimal.js-light "^2.5.1" + fecha "^4.2.3" + lodash "^4.17.21" + toformat "^2.0.0" + tsup "^8.1.0" + "@reach/dialog@^0.16.2": version "0.16.2" resolved "https://registry.yarnpkg.com/@reach/dialog/-/dialog-0.16.2.tgz#567e6f59d0a6dabe84b2ba4c456404efa6cb7d03" @@ -3796,6 +4048,19 @@ "@react-spring/shared" "~9.6.0" "@react-spring/types" "~9.6.0" +"@realms-today/spl-governance@0.3.29": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@realms-today/spl-governance/-/spl-governance-0.3.29.tgz#147f70aff4fa4fbd515ebe3ebbec12b0705fc4c8" + integrity sha512-j25gdQIzSYC1MfUhRTd7O9WuBdpWzNWDHItffRt0xQCrpeIHV1jVb0zGn0rR/H5uAsmoY6PcLrJYn5aMtN+gPg== + dependencies: + "@solana/web3.js" "^1.22.0" + axios "^1.1.3" + bignumber.js "^9.0.1" + bn.js "^5.1.3" + borsh "^0.3.1" + bs58 "^4.0.1" + superstruct "^0.15.2" + "@rollup/plugin-commonjs@24.0.0": version "24.0.0" resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.0.tgz#fb7cf4a6029f07ec42b25daa535c75b05a43f75c" @@ -3817,6 +4082,86 @@ estree-walker "^2.0.2" picomatch "^2.3.1" +"@rollup/rollup-android-arm-eabi@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.1.tgz#7746deb85e4a8fb54fbfda8ac5c102692f102476" + integrity sha512-XzqSg714++M+FXhHfXpS1tDnNZNpgxxuGZWlRG/jSj+VEPmZ0yg6jV4E0AL3uyBKxO8mO3xtOsP5mQ+XLfrlww== + +"@rollup/rollup-android-arm64@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.19.1.tgz#93de4d867709d3313794723b5afd91e1e174f906" + integrity sha512-thFUbkHteM20BGShD6P08aungq4irbIZKUNbG70LN8RkO7YztcGPiKTTGZS7Kw+x5h8hOXs0i4OaHwFxlpQN6A== + +"@rollup/rollup-darwin-arm64@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.19.1.tgz#e41e6a81673260ab196e0f59462b9940a6ac03cd" + integrity sha512-8o6eqeFZzVLia2hKPUZk4jdE3zW7LCcZr+MD18tXkgBBid3lssGVAYuox8x6YHoEPDdDa9ixTaStcmx88lio5Q== + +"@rollup/rollup-darwin-x64@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.19.1.tgz#2b0a0aef6e8c5317d494cfc9076d7a16b099bdcb" + integrity sha512-4T42heKsnbjkn7ovYiAdDVRRWZLU9Kmhdt6HafZxFcUdpjlBlxj4wDrt1yFWLk7G4+E+8p2C9tcmSu0KA6auGA== + +"@rollup/rollup-linux-arm-gnueabihf@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.19.1.tgz#e22319deb5367384ef315e66bc6de80d2bf2b3ae" + integrity sha512-MXg1xp+e5GhZ3Vit1gGEyoC+dyQUBy2JgVQ+3hUrD9wZMkUw/ywgkpK7oZgnB6kPpGrxJ41clkPPnsknuD6M2Q== + +"@rollup/rollup-linux-arm-musleabihf@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.19.1.tgz#d5dd68f5d7ae21b345a5c87208c94e5c813f54b8" + integrity sha512-DZNLwIY4ftPSRVkJEaxYkq7u2zel7aah57HESuNkUnz+3bZHxwkCUkrfS2IWC1sxK6F2QNIR0Qr/YXw7nkF3Pw== + +"@rollup/rollup-linux-arm64-gnu@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.19.1.tgz#1703d3a418d33f8f025acaf93f39ca1efcd5b645" + integrity sha512-C7evongnjyxdngSDRRSQv5GvyfISizgtk9RM+z2biV5kY6S/NF/wta7K+DanmktC5DkuaJQgoKGf7KUDmA7RUw== + +"@rollup/rollup-linux-arm64-musl@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.19.1.tgz#3f59c2c6e60f75ce8b1090bd841c555e3bb01f0e" + integrity sha512-89tFWqxfxLLHkAthAcrTs9etAoBFRduNfWdl2xUs/yLV+7XDrJ5yuXMHptNqf1Zw0UCA3cAutkAiAokYCkaPtw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.19.1.tgz#3f99a0921596a6f539121a312df29af52a205f15" + integrity sha512-PromGeV50sq+YfaisG8W3fd+Cl6mnOOiNv2qKKqKCpiiEke2KiKVyDqG/Mb9GWKbYMHj5a01fq/qlUR28PFhCQ== + +"@rollup/rollup-linux-riscv64-gnu@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.19.1.tgz#c08fb3e629d50d2eac31329347cfc559a1cf81d1" + integrity sha512-/1BmHYh+iz0cNCP0oHCuF8CSiNj0JOGf0jRlSo3L/FAyZyG2rGBuKpkZVH9YF+x58r1jgWxvm1aRg3DHrLDt6A== + +"@rollup/rollup-linux-s390x-gnu@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.19.1.tgz#173722cd745779d730d4b24d21386185e0e12de8" + integrity sha512-0cYP5rGkQWRZKy9/HtsWVStLXzCF3cCBTRI+qRL8Z+wkYlqN7zrSYm6FuY5Kd5ysS5aH0q5lVgb/WbG4jqXN1Q== + +"@rollup/rollup-linux-x64-gnu@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.19.1.tgz#0af2b6541ab0f4954d2c4f96bcdc7947420dd28c" + integrity sha512-XUXeI9eM8rMP8aGvii/aOOiMvTs7xlCosq9xCjcqI9+5hBxtjDpD+7Abm1ZhVIFE1J2h2VIg0t2DX/gjespC2Q== + +"@rollup/rollup-linux-x64-musl@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.19.1.tgz#f973f9552744764b221128f7c3629222216ace69" + integrity sha512-V7cBw/cKXMfEVhpSvVZhC+iGifD6U1zJ4tbibjjN+Xi3blSXaj/rJynAkCFFQfoG6VZrAiP7uGVzL440Q6Me2Q== + +"@rollup/rollup-win32-arm64-msvc@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.19.1.tgz#21ac5ed84d914bc31821fec3dd909f7257cfb17b" + integrity sha512-88brja2vldW/76jWATlBqHEoGjJLRnP0WOEKAUbMcXaAZnemNhlAHSyj4jIwMoP2T750LE9lblvD4e2jXleZsA== + +"@rollup/rollup-win32-ia32-msvc@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.19.1.tgz#0cfe740063b35dcd5a62c4e243226631a846ce11" + integrity sha512-LdxxcqRVSXi6k6JUrTah1rHuaupoeuiv38du8Mt4r4IPer3kwlTo+RuvfE8KzZ/tL6BhaPlzJ3835i6CxrFIRQ== + +"@rollup/rollup-win32-x64-msvc@4.19.1": + version "4.19.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.19.1.tgz#5f2c40d3f1b53ede80fb4e6964f840c0f8936832" + integrity sha512-2bIrL28PcK3YCqD9anGxDxamxdiJAxA+l7fWIwM5o8UqNy1t3d1NdAweO2XhA0KTDJ5aH1FsuiT5+7VhtHliXg== + "@saberhq/anchor-contrib@^1.12.47", "@saberhq/anchor-contrib@^1.12.48", "@saberhq/anchor-contrib@^1.14.1", "@saberhq/anchor-contrib@^1.14.11", "@saberhq/anchor-contrib@^1.14.9": version "1.14.11" resolved "https://registry.yarnpkg.com/@saberhq/anchor-contrib/-/anchor-contrib-1.14.11.tgz#cebaac040faea643ade8ecb6afeeb2dcdf5a33a2" @@ -4090,33 +4435,24 @@ resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== -"@solana-mobile/mobile-wallet-adapter-protocol-web3js@^0.9.9": - version "0.9.9" - resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol-web3js/-/mobile-wallet-adapter-protocol-web3js-0.9.9.tgz#ef4040abef66e4c080ebf2a0db109f31ef95652d" - integrity sha512-JzlNjZ/Uog56iP/z8QtNrIOgQwmaoicpr9768s0QVF4xuvNbyWHOaDtsngzNneNTMfLSgd0tueboKUrkvto/Wg== +"@solana-mobile/mobile-wallet-adapter-protocol-web3js@^2.0.0", "@solana-mobile/mobile-wallet-adapter-protocol-web3js@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol-web3js/-/mobile-wallet-adapter-protocol-web3js-2.1.2.tgz#a64b96f99540192e0b7343f30c9d58db7d8a38cd" + integrity sha512-uA6tbP/JvBCdGSwty3rNM8a0qpoHPEV+Qj234aw4XMisS++TSN8R79bclT4hLvOsg+m04on1MOkMM3oPXlQo9A== dependencies: - "@solana-mobile/mobile-wallet-adapter-protocol" "^0.9.9" + "@solana-mobile/mobile-wallet-adapter-protocol" "^2.1.2" bs58 "^5.0.0" - js-base64 "^3.7.2" + js-base64 "^3.7.5" -"@solana-mobile/mobile-wallet-adapter-protocol-web3js@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol-web3js/-/mobile-wallet-adapter-protocol-web3js-2.0.0.tgz#5433705c174f59a177280f85396df051711be09d" - integrity sha512-cMADp/UIAN42QJVCM1oyj1wFM/9DTZNIa5z5eHXUXBksw/bNv2fWkiO+4ZUoQj1P4UoMoZJUBx9+qMVl18sPOA== +"@solana-mobile/mobile-wallet-adapter-protocol@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol/-/mobile-wallet-adapter-protocol-2.1.2.tgz#e812c6bc07e7552902225ea62bc0f829ddf2acdf" + integrity sha512-z7LPeWzdEUoavU5P1PSbtxLTNE/MB6ACgaIPPAMjRdEk/jUvunquWKmbOX4vkFD6QbD98ykc4NZOt5iki7Z6hw== dependencies: - "@solana-mobile/mobile-wallet-adapter-protocol" "^2.0.0" - bs58 "^5.0.0" - js-base64 "^3.7.2" - -"@solana-mobile/mobile-wallet-adapter-protocol@^0.9.9": - version "0.9.9" - resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol/-/mobile-wallet-adapter-protocol-0.9.9.tgz#8b8e3f94f609e0e8c1149c0dbf1548adf18bfd4b" - integrity sha512-Jxd3O3txeUiAXLIo6YfWhTs7UTVMlnIgz/xgdYmf99TSE4IaUhWGEVC2/OcOA7eAA85y0/XItU5OhHhXSPva8g== - -"@solana-mobile/mobile-wallet-adapter-protocol@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@solana-mobile/mobile-wallet-adapter-protocol/-/mobile-wallet-adapter-protocol-2.0.0.tgz#75a3e8163544f659803260cb1dd7aede6da96b36" - integrity sha512-mLK9B/AQgOxzbdRoOMH3G5wB5akWgGSBoVqIZ/6iDWY37uu/CuyX4lTwRyoRlOb8Cxs/tDwiovIGobkti2qF/w== + "@solana/wallet-standard" "^1.1.2" + "@solana/wallet-standard-util" "^1.1.1" + "@wallet-standard/core" "^1.0.3" + js-base64 "^3.7.5" "@solana-mobile/wallet-adapter-mobile@2.0.0": version "2.0.0" @@ -4128,15 +4464,17 @@ "@solana/wallet-adapter-base" "^0.9.17" js-base64 "^3.7.2" -"@solana-mobile/wallet-adapter-mobile@^0.9.9": - version "0.9.9" - resolved "https://registry.yarnpkg.com/@solana-mobile/wallet-adapter-mobile/-/wallet-adapter-mobile-0.9.9.tgz#5d65a1983a422ad56ff95fe9efaedef4c87d6436" - integrity sha512-nmxTEbKgkuI37zMpI3GWWn6DvAd/lgl6GF1lGbYSObXyZDun0bfCIQ8rBVEcvwZLyekp+i/nLW8JdSccN4i3zw== +"@solana-mobile/wallet-adapter-mobile@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@solana-mobile/wallet-adapter-mobile/-/wallet-adapter-mobile-2.1.2.tgz#dcf289280a8baa84ea76056d48ee427ac17893f5" + integrity sha512-m7UW+vS0qB7j+FYvzBbXQx9carDW+x4Ndmdf5nbSsfZ+gr3yVAAQBkW1Cj+wgC2DFINpTr6Nt0qbuaQjRS53AA== dependencies: + "@solana-mobile/mobile-wallet-adapter-protocol-web3js" "^2.1.2" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/wallet-standard-features" "^1.2.0" + js-base64 "^3.7.5" + optionalDependencies: "@react-native-async-storage/async-storage" "^1.17.7" - "@solana-mobile/mobile-wallet-adapter-protocol-web3js" "^0.9.9" - "@solana/wallet-adapter-base" "^0.9.17" - js-base64 "^3.7.2" "@solana/buffer-layout-utils@^0.2.0": version "0.2.0" @@ -4148,20 +4486,212 @@ bigint-buffer "^1.1.5" bignumber.js "^9.0.1" -"@solana/buffer-layout@4.0.0", "@solana/buffer-layout@^3.0.0", "@solana/buffer-layout@^4.0.0": +"@solana/buffer-layout@4.0.0", "@solana/buffer-layout@^3.0.0", "@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": version "4.0.0" resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== dependencies: buffer "~6.0.3" -"@solana/governance-program-library@npm:@civic/governance-program-library@0.16.9-beta.2": - version "0.16.9-beta.2" - resolved "https://registry.yarnpkg.com/@civic/governance-program-library/-/governance-program-library-0.16.9-beta.2.tgz#2e80c39a39bc3fc7b05ee961112a8daf25f7cf45" - integrity sha512-9xjdu5ifXJGVZonQ9tmxREyKChVW0c1TMU2tIT6p8Kb6RqVXcoHNjr8aFaH4Z74LshF8rOiQLSnguVGBLu3atw== +"@solana/codecs-core@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz#689784d032fbc1fedbde40bb25d76cdcecf6553b" + integrity sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg== dependencies: - "@project-serum/anchor" "^0.25.0" - "@project-serum/serum" "^0.13.61" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-core@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.4.tgz#770826105f2f884110a21662573e7a2014654324" + integrity sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw== + dependencies: + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-core@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz#1a2d76b9c7b9e7b7aeb3bd78be81c2ba21e3ce22" + integrity sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ== + dependencies: + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-data-structures@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz#e82cb1b6d154fa636cd5c8953ff3f32959cc0370" + integrity sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-data-structures@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.4.tgz#f8a2470982a9792334737ea64000ccbdff287247" + integrity sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-data-structures@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz#d47b2363d99fb3d643f5677c97d64a812982b888" + integrity sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-numbers@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz#56995c27396cd8ee3bae8bd055363891b630bbd0" + integrity sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-numbers@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.4.tgz#6a53b456bb7866f252d8c032c81a92651e150f66" + integrity sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-numbers@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz#f34978ddf7ea4016af3aaed5f7577c1d9869a614" + integrity sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-strings@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz#8bd01a4e48614d5289d72d743c3e81305d445c46" + integrity sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-strings@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.4.tgz#4d06bb722a55a5d04598d362021bfab4bd446760" + integrity sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs-strings@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz#e1d9167075b8c5b0b60849f8add69c0f24307018" + integrity sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.2.tgz#d6615fec98f423166fb89409f9a4ad5b74c10935" + integrity sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-data-structures" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/codecs-strings" "2.0.0-preview.2" + "@solana/options" "2.0.0-preview.2" + +"@solana/codecs@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.4.tgz#a1923cc78a6f64ebe656c7ec6335eb6b70405b22" + integrity sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/options" "2.0.0-preview.4" + +"@solana/codecs@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-rc.1.tgz#146dc5db58bd3c28e04b4c805e6096c2d2a0a875" + integrity sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/options" "2.0.0-rc.1" + +"@solana/errors@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.2.tgz#e0ea8b008c5c02528d5855bc1903e5e9bbec322e" + integrity sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA== + dependencies: + chalk "^5.3.0" + commander "^12.0.0" + +"@solana/errors@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.4.tgz#056ba76b6dd900dafa70117311bec3aef0f5250b" + integrity sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + +"@solana/errors@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-rc.1.tgz#3882120886eab98a37a595b85f81558861b29d62" + integrity sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + +"@solana/governance-program-library@npm:@civic/governance-program-library@0.18.2-beta.24": + version "0.18.2-beta.24" + resolved "https://registry.yarnpkg.com/@civic/governance-program-library/-/governance-program-library-0.18.2-beta.24.tgz#68688efd4679b125a47d03b935a9504e29cb97d0" + integrity sha512-Z+IiNKPbp7E7oFSoTZbTS6qZ6h66fE+r5gttnnhKfGuVPpj+95aALerAQpOYSGl0oQ7DkKaUO2N+lBTgLaEQCA== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@identity.com/solana-gateway-ts" "^0.12.0" + "@solana/spl-governance" "^0.3.28" + +"@solana/options@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.2.tgz#13ff008bf43a5056ef9a091dc7bb3f39321e867e" + integrity sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + +"@solana/options@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.4.tgz#212d35d1da87c7efb13de4d3569ad9eb070f013d" + integrity sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/options@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-rc.1.tgz#06924ba316dc85791fc46726a51403144a85fc4d" + integrity sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/promises@2.0.0-canary-20240812091942": + version "2.0.0-canary-20240812091942" + resolved "https://registry.yarnpkg.com/@solana/promises/-/promises-2.0.0-canary-20240812091942.tgz#e0f1d0c200170a791f120e320b10c446d30644c9" + integrity sha512-HLYVZxrXnMatnBBtHCK1qY7T2AEnhI2AL4PY10iZZ98JIO9dE6igRwFlBulC3ts8qBBkivDf0rF6RahvkrHV0A== "@solana/spl-account-compression@^0.1.4", "@solana/spl-account-compression@^0.1.8": version "0.1.9" @@ -4200,7 +4730,7 @@ bs58 "^4.0.1" superstruct "^0.15.2" -"@solana/spl-governance@0.3.28": +"@solana/spl-governance@0.3.28", "@solana/spl-governance@^0.3.28": version "0.3.28" resolved "https://registry.yarnpkg.com/@solana/spl-governance/-/spl-governance-0.3.28.tgz#63ff71f235206f069f8ea1e66a40e7cdb6252d3f" integrity sha512-CUi1hMvzId2rAtMFTlxMwOy0EmFeT0VcmiC+iQnDhRBuM8LLLvRrbTYBWZo3xIvtPQW9HfhVBoL7P/XNFIqYVQ== @@ -4213,6 +4743,43 @@ bs58 "^4.0.1" superstruct "^0.15.2" +"@solana/spl-stake-pool@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@solana/spl-stake-pool/-/spl-stake-pool-1.1.5.tgz#a820f03195ff11c7206f3b5137789a82c322b029" + integrity sha512-fiZ7XRbtk4G4aDRdAFu+3rs0kNFv55dzfLd78HoADhrVNQT8B+vby7L02Zhp1f2DR8GPWqTQkBh5BdyAKrICBQ== + dependencies: + "@solana/buffer-layout" "^4.0.1" + "@solana/spl-token" "0.4.6" + "@solana/web3.js" "^1.91.8" + bn.js "^5.2.0" + buffer "^6.0.3" + buffer-layout "^1.2.2" + superstruct "^1.0.4" + +"@solana/spl-token-group@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.4.tgz#4f45d9526c96a33b9a1929a264d0aa21c7e38a2d" + integrity sha512-7+80nrEMdUKlK37V6kOe024+T7J4nNss0F8LQ9OOPYdWCCfJmsGUzVx2W3oeizZR4IHM6N4yC9v1Xqwc3BTPWw== + dependencies: + "@solana/codecs" "2.0.0-preview.2" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token-group@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.5.tgz#f955dcca782031c85e862b2b46878d1bb02db6c2" + integrity sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ== + dependencies: + "@solana/codecs" "2.0.0-preview.4" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token-metadata@^0.1.2", "@solana/spl-token-metadata@^0.1.3", "@solana/spl-token-metadata@^0.1.4": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.5.tgz#91616470d6862ec6b762e6cfcf882b8a8a24b1e8" + integrity sha512-DSBlo7vjuLe/xvNn75OKKndDBkFxlqjLdWlq6rf40StnrhRn7TDntHGLZpry1cf3uzQFShqeLROGNPAJwvkPnA== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + "@solana/spl-type-length-value" "0.1.0" + "@solana/spl-token-registry@0.2.3775": version "0.2.3775" resolved "https://registry.yarnpkg.com/@solana/spl-token-registry/-/spl-token-registry-0.2.3775.tgz#96abffc351fe156917aedb8bba7db94600abed6e" @@ -4232,22 +4799,52 @@ buffer-layout "^1.2.0" dotenv "10.0.0" -"@solana/spl-token@0.3.7": - version "0.3.7" - resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.3.7.tgz#6f027f9ad8e841f792c32e50920d9d2e714fc8da" - integrity sha512-bKGxWTtIw6VDdCBngjtsGlKGLSmiu/8ghSt/IOYJV24BsymRbgq7r12GToeetpxmPaZYLddKwAz7+EwprLfkfg== +"@solana/spl-token@0.3.8": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.3.8.tgz#8e9515ea876e40a4cc1040af865f61fc51d27edf" + integrity sha512-ogwGDcunP9Lkj+9CODOWMiVJEdRtqHAtX2rWF62KxnnSWtMZtV9rDhTrZFshiyJmxDnRL/1nKE1yJHg4jjs3gg== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + buffer "^6.0.3" + +"@solana/spl-token@0.4.6": + version "0.4.6" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.6.tgz#eb44e5080ea7b6fc976abcb39457223211bd9076" + integrity sha512-1nCnUqfHVtdguFciVWaY/RKcQz1IF4b31jnKgAmjU9QVN1q7dRUkTEWJZgTYIEtsULjVnC9jRqlhgGN39WbKKA== dependencies: "@solana/buffer-layout" "^4.0.0" "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.4" + "@solana/spl-token-metadata" "^0.1.4" buffer "^6.0.3" -"@solana/spl-token@0.3.8", "@solana/spl-token@^0.3.5", "@solana/spl-token@^0.3.6", "@solana/spl-token@^0.3.8": - version "0.3.8" - resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.3.8.tgz#8e9515ea876e40a4cc1040af865f61fc51d27edf" - integrity sha512-ogwGDcunP9Lkj+9CODOWMiVJEdRtqHAtX2rWF62KxnnSWtMZtV9rDhTrZFshiyJmxDnRL/1nKE1yJHg4jjs3gg== +"@solana/spl-token@0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.8.tgz#a84e4131af957fa9fbd2727e5fc45dfbf9083586" + integrity sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA== dependencies: "@solana/buffer-layout" "^4.0.0" "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.5" + "@solana/spl-token-metadata" "^0.1.3" + buffer "^6.0.3" + +"@solana/spl-token@^0.3.11", "@solana/spl-token@^0.3.4", "@solana/spl-token@^0.3.5", "@solana/spl-token@^0.3.6", "@solana/spl-token@^0.3.7", "@solana/spl-token@^0.3.8", "@solana/spl-token@^0.3.9": + version "0.3.11" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.3.11.tgz#cdc10f9472b29b39c8983c92592cadd06627fb9a" + integrity sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-metadata" "^0.1.2" + buffer "^6.0.3" + +"@solana/spl-type-length-value@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b" + integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== + dependencies: buffer "^6.0.3" "@solana/wallet-adapter-alpha@^0.1.9": @@ -4271,7 +4868,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== @@ -4281,6 +4878,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" @@ -4437,19 +5044,19 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.22" -"@solana/wallet-adapter-nightly@^0.1.14", "@solana/wallet-adapter-nightly@^0.1.9": - version "0.1.14" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nightly/-/wallet-adapter-nightly-0.1.14.tgz#c72211ddc3ce9c48362baefd59ba815ee4ddf431" - integrity sha512-EnrSkduVi1ds/0zc2xORIkcBZCQESz+cllrTeX5RmeZCFKdIjHpUZfbKrvhtz/OpOZbOvRi7ojBLeyx63V2T/A== +"@solana/wallet-adapter-nightly@^0.1.15", "@solana/wallet-adapter-nightly@^0.1.9": + version "0.1.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nightly/-/wallet-adapter-nightly-0.1.16.tgz#51be8f39d8ccac609c59c96ea1f5df95d71274ca" + integrity sha512-JaPzT8R4HHUqGn/QdElx9iRW98h0NaANBt0j3CZZYWlqsdG0f8fFfy2xofILA+qnDL6NaRI9AzQ4NcQGuVZsVQ== dependencies: - "@solana/wallet-adapter-base" "^0.9.22" + "@solana/wallet-adapter-base" "^0.9.23" -"@solana/wallet-adapter-nufi@^0.1.15": - version "0.1.15" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nufi/-/wallet-adapter-nufi-0.1.15.tgz#37be8fe15e11454dfa700b27a6886f1da2bba3ff" - integrity sha512-KSZefEMiEZIGKDBzyK9CV/srCmPy4vZ9gdrmHTkZuzssZ9YfFwMR71zKpCyYvtJ9mfk+MxmSU6mizUkaB+AHCw== +"@solana/wallet-adapter-nufi@^0.1.16": + version "0.1.17" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-nufi/-/wallet-adapter-nufi-0.1.17.tgz#131a02453905aafdecaef12d251b0b0aaab08a44" + integrity sha512-ggTZKvYPJS3m/9hsMaGSH0F8kqumPqP0WdY7WNihWR6O4Pr401kDBdgXPXNSGorIahdPrRBzp5UrahnrlodvTQ== dependencies: - "@solana/wallet-adapter-base" "^0.9.22" + "@solana/wallet-adapter-base" "^0.9.23" "@solana/wallet-adapter-onto@^0.1.6": version "0.1.6" @@ -4473,12 +5080,12 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.22" -"@solana/wallet-adapter-react@0.15.30": - version "0.15.30" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-react/-/wallet-adapter-react-0.15.30.tgz#88ce539601ea296f7bb9a854c7bf044745eb0e1b" - integrity sha512-62fg46AIia0udRlQLjMxHPa/cQUE2Neur/s74r96gakyPPEEFbbAcVPHMkEX7r0DPjl5lWj834beIbUXBwHjlw== +"@solana/wallet-adapter-react@0.15.32": + version "0.15.32" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-react/-/wallet-adapter-react-0.15.32.tgz#3e8a949dbf183460d54fee707374f22799199c01" + integrity sha512-dnbMVQeO2WBvK13M4kiUo1TBONJpfpO1r9JA5FuXG/Zwdt4RbGT+h6HSOaplHPO6pzDVk2nT/bU8wjqI9GxTYQ== dependencies: - "@solana-mobile/wallet-adapter-mobile" "^0.9.9" + "@solana-mobile/wallet-adapter-mobile" "^2.0.0" "@solana/wallet-adapter-base" "^0.9.22" "@solana/wallet-standard-wallet-adapter-react" "^1.0.1" @@ -4519,13 +5126,16 @@ "@solana/wallet-adapter-base" "^0.9.22" bs58 "^4.0.1" -"@solana/wallet-adapter-solflare@0.6.24", "@solana/wallet-adapter-solflare@^0.6.16", "@solana/wallet-adapter-solflare@^0.6.24": - version "0.6.24" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solflare/-/wallet-adapter-solflare-0.6.24.tgz#f9bf980bda02eb82e58f40a030ffe44cbf791bf2" - integrity sha512-SQl5h6PgDQAgZxxItFcJ5jQApWbjXajSvZttN4uf23VlJg3vi4iu0JEUhVMkTr02zCR2q27xazDMOziJDS4EWw== +"@solana/wallet-adapter-solflare@0.6.28", "@solana/wallet-adapter-solflare@^0.6.16", "@solana/wallet-adapter-solflare@^0.6.24": + version "0.6.28" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-solflare/-/wallet-adapter-solflare-0.6.28.tgz#3de42a43220cca361050ebd1755078012a5b0fe2" + integrity sha512-iiUQtuXp8p4OdruDawsm1dRRnzUCcsu+lKo8OezESskHtbmZw2Ifej0P99AbJbBAcBw7q4GPI6987Vh05Si5rw== dependencies: - "@solana/wallet-adapter-base" "^0.9.22" - "@solflare-wallet/sdk" "^1.2.0" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/wallet-standard-chains" "^1.1.0" + "@solflare-wallet/metamask-sdk" "^1.0.2" + "@solflare-wallet/sdk" "^1.3.0" + "@wallet-standard/wallet" "^1.0.1" "@solana/wallet-adapter-sollet@0.11.16", "@solana/wallet-adapter-sollet@^0.11.11", "@solana/wallet-adapter-sollet@^0.11.16": version "0.11.16" @@ -4597,18 +5207,18 @@ 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" - resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-wallets/-/wallet-adapter-wallets-0.19.15.tgz#3d148a37a30a320aa172b1bfabfc2526fad107bf" - integrity sha512-HakQwKor5f5dbKlRPCBMu3E0gALX2mt0fp44qIKrmLDH7J/UpTIuIDu0z5eidaABJCSVMBNuEC+0uS1UYUXS8w== +"@solana/wallet-adapter-wallets@0.19.16": + version "0.19.16" + resolved "https://registry.yarnpkg.com/@solana/wallet-adapter-wallets/-/wallet-adapter-wallets-0.19.16.tgz#07bf9db5378c3f338b22aa6aae1774c5fd38d67e" + integrity sha512-Q+6Tv+oIkD+fhsUuPp+jLb+dyoB3hrX7XT+Xr5vMZvxQuB5bcUn7m0ZWGoAh0dw1FsfsOXMTGu1aNwS3XSqxtw== dependencies: "@solana/wallet-adapter-alpha" "^0.1.9" "@solana/wallet-adapter-avana" "^0.1.12" @@ -4633,8 +5243,8 @@ "@solana/wallet-adapter-magiceden" "^0.1.12" "@solana/wallet-adapter-mathwallet" "^0.9.17" "@solana/wallet-adapter-neko" "^0.2.11" - "@solana/wallet-adapter-nightly" "^0.1.14" - "@solana/wallet-adapter-nufi" "^0.1.15" + "@solana/wallet-adapter-nightly" "^0.1.15" + "@solana/wallet-adapter-nufi" "^0.1.16" "@solana/wallet-adapter-onto" "^0.1.6" "@solana/wallet-adapter-particle" "^0.1.9" "@solana/wallet-adapter-phantom" "^0.9.22" @@ -4663,62 +5273,88 @@ dependencies: "@solana/wallet-adapter-base" "^0.9.22" -"@solana/wallet-standard-chains@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@solana/wallet-standard-chains/-/wallet-standard-chains-1.0.0.tgz#4c291a2f79f0e105ce0a47b30d98dbd7f8ba69be" - integrity sha512-kr3+JAo7mEBhVCH9cYzjn/vXeUiZeYfB4BF6E8u3U2jq3KlZA/KB+YM976+zGumTfN0NmMXUm066pTTG9kJsNQ== +"@solana/wallet-standard-chains@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-chains/-/wallet-standard-chains-1.1.0.tgz#459b297e71b0d9c1196c11a0578b38c85998be7d" + integrity sha512-IRJHf94UZM8AaRRmY18d34xCJiVPJej1XVwXiTjihHnmwD0cxdQbc/CKjrawyqFyQAKJx7raE5g9mnJsAdspTg== dependencies: - "@wallet-standard/base" "^1.0.0" + "@wallet-standard/base" "^1.0.1" -"@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-core@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-core/-/wallet-standard-core-1.1.1.tgz#7187c085dcee38719902217a7ecdd1bf3f27afa3" + integrity sha512-DoQ5Ryly4GAZtxRUmW2rIWrgNvTYVCWrFCFFjZI5s4zu2QNsP7sHZUax3kc1GbmFLXNL1FWRZlPOXRs6e0ZEng== + dependencies: + "@solana/wallet-standard-chains" "^1.1.0" + "@solana/wallet-standard-features" "^1.2.0" + "@solana/wallet-standard-util" "^1.1.1" + +"@solana/wallet-standard-features@^1.0.1", "@solana/wallet-standard-features@^1.1.0", "@solana/wallet-standard-features@^1.2.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" -"@solana/wallet-standard-util@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@solana/wallet-standard-util/-/wallet-standard-util-1.0.0.tgz#597b3a240f1855d25d93c2cd7efe8631a1a241ac" - integrity sha512-qRAOBXnN7dwvtgzTtxIHsSeJAMbGNZdSWs57TT8pCyBrKL5dVxaK2u95Dm17SRSzwfKl/EByV1lTjOxXyKWS+g== +"@solana/wallet-standard-util@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-util/-/wallet-standard-util-1.1.1.tgz#f645fdd8b7d3c553a3b59aa19c25c51a1badce66" + integrity sha512-dPObl4ntmfOc0VAGGyyFvrqhL8UkHXmVsgbj0K9RcznKV4KB3MgjGwzo8CTSX5El5lkb0rDeEzFqvToJXRz3dw== dependencies: - "@solana/wallet-standard-chains" "^1.0.0" - "@solana/wallet-standard-features" "^1.0.0" + "@noble/curves" "^1.1.0" + "@solana/wallet-standard-chains" "^1.1.0" + "@solana/wallet-standard-features" "^1.2.0" -"@solana/wallet-standard-wallet-adapter-base@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-base/-/wallet-standard-wallet-adapter-base-1.0.1.tgz#4f44d1041856460ca9bb8b3aaaec0855e98d0bf2" - integrity sha512-no3NwFIfWN653g1I2i8bbfwMjASzBSau9De8tQgoE+CPyQXJxNYyb2B5uw6SsJImMCES7fT2k4J0mM2OlUmreQ== +"@solana/wallet-standard-wallet-adapter-base@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-base/-/wallet-standard-wallet-adapter-base-1.1.2.tgz#f030f412cd16b06e95c6da5548a03113319d3620" + integrity sha512-DqhzYbgh3disHMgcz6Du7fmpG29BYVapNEEiL+JoVMa+bU9d4P1wfwXUNyJyRpGGNXtwhyZjIk2umWbe5ZBNaQ== dependencies: - "@solana/wallet-adapter-base" "^0.9.21" - "@solana/wallet-standard-chains" "^1.0.0" - "@solana/wallet-standard-features" "^1.0.1" - "@solana/wallet-standard-util" "^1.0.0" + "@solana/wallet-adapter-base" "^0.9.23" + "@solana/wallet-standard-chains" "^1.1.0" + "@solana/wallet-standard-features" "^1.2.0" + "@solana/wallet-standard-util" "^1.1.1" "@wallet-standard/app" "^1.0.1" "@wallet-standard/base" "^1.0.1" "@wallet-standard/features" "^1.0.3" "@wallet-standard/wallet" "^1.0.1" -"@solana/wallet-standard-wallet-adapter-react@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-react/-/wallet-standard-wallet-adapter-react-1.0.1.tgz#fb391834f81e040619b4a23f4d1e31a7b818bbc9" - integrity sha512-sqYufApzZDFjyXtu5Yq7HQR8HzY5l9WuTZByfQxDOF62oMP2wx8sE0AGuAlisggJhGpMzNDsEek9VqED81eDzg== +"@solana/wallet-standard-wallet-adapter-react@^1.0.1", "@solana/wallet-standard-wallet-adapter-react@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter-react/-/wallet-standard-wallet-adapter-react-1.1.2.tgz#a7bc71786e8f891d2dd83f7de30db4708767a56a" + integrity sha512-bN6W4QkzenyjUoUz3sC5PAed+z29icGtPh9VSmLl1ZrRO7NbFB49a8uwUUVXNxhL/ZbMsyVKhb9bNj47/p8uhQ== dependencies: - "@solana/wallet-standard-wallet-adapter-base" "^1.0.1" + "@solana/wallet-standard-wallet-adapter-base" "^1.1.2" "@wallet-standard/app" "^1.0.1" "@wallet-standard/base" "^1.0.1" -"@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.6": - 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== +"@solana/wallet-standard-wallet-adapter@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard-wallet-adapter/-/wallet-standard-wallet-adapter-1.1.2.tgz#a9ff9e4d5c379e4f38c03a2b69c9a221904181b6" + integrity sha512-lCwoA+vhPfmvjcmJOhSRV94wouVWTfJv1Z7eeULAe+GodCeKA/0T9/uBYgXHUxQjLHd7o8LpLYIkfm+xjA5sMA== + dependencies: + "@solana/wallet-standard-wallet-adapter-base" "^1.1.2" + "@solana/wallet-standard-wallet-adapter-react" "^1.1.2" + +"@solana/wallet-standard@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@solana/wallet-standard/-/wallet-standard-1.1.2.tgz#b68e38db863f6945979fe278f2cecc2e21f84c2d" + integrity sha512-o7wk+zr5/QgyE393cGRC04K1hacR4EkBu3MB925ddaLvCVaXjwr2asgdviGzN9PEm3FiEJp3sMmMKYHFnwOITQ== + dependencies: + "@solana/wallet-standard-core" "^1.1.1" + "@solana/wallet-standard-wallet-adapter" "^1.1.2" + +"@solana/web3.js@1.56.0", "@solana/web3.js@1.78.8", "@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.43.4", "@solana/web3.js@^1.44.3", "@solana/web3.js@^1.50.1", "@solana/web3.js@^1.53.0", "@solana/web3.js@^1.54.0", "@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.87.5", "@solana/web3.js@^1.87.6", "@solana/web3.js@^1.89.1", "@solana/web3.js@^1.90.0", "@solana/web3.js@^1.91.8", "@solana/web3.js@^1.93.0", "@solana/web3.js@^1.95.0", "@solana/web3.js@^1.95.2", "@solana/web3.js@^1.95.3", "@solana/web3.js@~1.77.3": + version "1.78.8" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.78.8.tgz#d635bcccaac9e36270c6b16340bfeb5502737831" + integrity sha512-y6kMa0ohRjamBGtxIGX4TkdAzL8Cs2bzM4JDPCyYLFPdo7kWk0Cx+BkbhX8hEV4IfvCONF92KIniV7hDvHuq8A== dependencies: "@babel/runtime" "^7.22.6" - "@noble/curves" "^1.0.0" - "@noble/hashes" "^1.3.0" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.1" "@solana/buffer-layout" "^4.0.0" - agentkeepalive "^4.2.1" + agentkeepalive "^4.3.0" bigint-buffer "^1.1.5" bn.js "^5.2.1" borsh "^0.7.0" @@ -4746,15 +5382,45 @@ buffer-layout "^1.2.0" isomorphic-fetch "^3.0.0" -"@solflare-wallet/sdk@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@solflare-wallet/sdk/-/sdk-1.2.0.tgz#3ba412f316cc6ea324679cd6233d363296770ead" - integrity sha512-J3KZJdeYJ2R7jPHa0F53iCtkQEdcD1j7yeFQ4oa6Kk6gU1MOqSEWZxrr56sVDKWuPT/gunzEXGrgcwjd7nxwjg== +"@solflare-wallet/metamask-sdk@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@solflare-wallet/metamask-sdk/-/metamask-sdk-1.0.3.tgz#3baaa22de2c86515e6ba6025285cd1f5d74b04e5" + integrity sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ== dependencies: - "@project-serum/sol-wallet-adapter" "0.2.0" - bs58 "^4.0.1" - eventemitter3 "^4.0.7" - uuid "^8.3.2" + "@solana/wallet-standard-features" "^1.1.0" + "@wallet-standard/base" "^1.0.1" + bs58 "^5.0.0" + eventemitter3 "^5.0.1" + uuid "^9.0.0" + +"@solflare-wallet/sdk@^1.3.0": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@solflare-wallet/sdk/-/sdk-1.4.2.tgz#630b9a26f7bca255ee4a7088f287ae8c8335e345" + integrity sha512-jrseNWipwl9xXZgrzwZF3hhL0eIVxuEtoZOSLmuPuef7FgHjstuTtNJAeT4icA7pzdDV4hZvu54pI2r2f7SmrQ== + dependencies: + bs58 "^5.0.0" + eventemitter3 "^5.0.1" + uuid "^9.0.0" + +"@solworks/soltoolkit-sdk@^0.0.23": + version "0.0.23" + resolved "https://registry.yarnpkg.com/@solworks/soltoolkit-sdk/-/soltoolkit-sdk-0.0.23.tgz#ef32d0aa79f888bcf0f639d280005b2e97cdc624" + integrity sha512-O6lXT3EBR4gmcjt0/33i97VMHVEImwXGi+4TNrDDdifn3tyOUB7V6PR1VGxlavQb9hqmVai3xhedg/rmbQzX7w== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/spl-token" "^0.3.4" + "@solana/web3.js" "^1.54.0" + "@types/bn.js" "^5.1.0" + "@types/node" "^18.7.13" + "@types/node-fetch" "^2.6.2" + bn.js "^5.2.1" + decimal.js "^10.4.0" + typescript "^4.8.2" + +"@soncodi/signal@~2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@soncodi/signal/-/signal-2.0.7.tgz#0a2c361b02dbfdbcf4e66b78e5f711e0a13d6e83" + integrity sha512-zA2oZluZmVvgZEDjF243KWD1S2J+1SH1MVynI0O1KRgDt1lU8nqk7AK3oQfW/WpwT51L5waGSU0xKF/9BTP5Cw== "@sqds/iframe-adapter@1.0.16": version "1.0.16" @@ -4766,6 +5432,15 @@ bs58 "^5.0.0" encoding "^0.1.13" +"@sqds/mesh@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@sqds/mesh/-/mesh-1.0.6.tgz#b3538a04b3232645d61db3ac7377511b5e742e63" + integrity sha512-z+x1GjixJm8K3uPwaDebTsssU3B71zJzRCkywmtz2ZZoMvoz9w/C4nY+v7v6Wg/9OTbfSDgcX/Hoo/FlphkWvg== + dependencies: + "@project-serum/anchor" "^0.25.0" + "@solana/web3.js" "^1.53.0" + bn.js "^5.2.1" + "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -4927,18 +5602,38 @@ dependencies: tslib "^2.4.0" -"@switchboard-xyz/common@^2.3.9": - version "2.3.9" - resolved "https://registry.yarnpkg.com/@switchboard-xyz/common/-/common-2.3.9.tgz#c19e4135d95a6b679f00272d6dbe42130a11bc19" - integrity sha512-Sdr+m1MFzLCNjpPvklazd7BwT/s2g2spfVnhe0dhwc36ONWeObXAALOLMrFJKiLar2wtd+qhclHt5OoBfceFtw== +"@switchboard-xyz/common@^2.3.16", "@switchboard-xyz/common@^2.4.4", "@switchboard-xyz/common@^2.4.7": + version "2.4.7" + resolved "https://registry.yarnpkg.com/@switchboard-xyz/common/-/common-2.4.7.tgz#7b582e7cdd4c17a3d4e36beead520a5363f4f0a8" + integrity sha512-gkUuy7n15gq+D0IKkqKsSqgWb1w5t3rfpjdTkJX0AAlL75QXZfi5fL4Ttwb22ALOWYLYuvYCD0uXFyczgMMkIQ== dependencies: + "@solana/web3.js" "^1.93.0" + axios "^1.7.2" big.js "^6.2.1" bn.js "^5.2.1" bs58 "^5.0.0" + cron-validator "^1.3.1" decimal.js "^10.4.3" + js-sha256 "^0.11.0" lodash "^4.17.21" - protobufjs "^7.2.4" - yaml "^2.2.1" + protobufjs "^7.2.6" + yaml "^2.5.0" + +"@switchboard-xyz/on-demand@^1.2.38": + version "1.2.38" + resolved "https://registry.yarnpkg.com/@switchboard-xyz/on-demand/-/on-demand-1.2.38.tgz#de368176a89b05c365d916c5cb419e1cf918acf3" + integrity sha512-BaZc78dDbmofJmk60SD0dDsf953rnQ9MaTeUrFyn8Z0zRiu79hTJMeKisKbC/pOCG7EMpZZRF/sqXujRfG6QFw== + dependencies: + "@brokerloop/ttlcache" "^3.2.3" + "@coral-xyz/anchor-30" "npm:@coral-xyz/anchor@0.30.1" + "@solana/web3.js" "^1.95.0" + "@solworks/soltoolkit-sdk" "^0.0.23" + "@switchboard-xyz/common" "^2.4.7" + axios "^1.7.4" + big.js "^6.2.1" + bs58 "^5.0.0" + js-yaml "^4.1.0" + protobufjs "^7.2.6" "@switchboard-xyz/sbv2-lite@0.2.4": version "0.2.4" @@ -4956,16 +5651,16 @@ "@project-serum/anchor" "^0.24.2" big.js "^6.1.1" -"@switchboard-xyz/solana.js@3.1.5": - version "3.1.5" - resolved "https://registry.yarnpkg.com/@switchboard-xyz/solana.js/-/solana.js-3.1.5.tgz#b754d1ba2ccee24586d9f14fc8eaf86cd9195262" - integrity sha512-bKNXBw5g7zBbIfLqDim9gAr0KKKNgw3/KgRsVa5/pl1/2JsDPX8dpuv7H0S0p01CaUryu32Lg1mxjN+qznupAg== - dependencies: - "@coral-xyz/anchor" "^0.28.0" - "@coral-xyz/borsh" "^0.28.0" - "@solana/spl-token" "^0.3.8" - "@solana/web3.js" "^1.78.3" - "@switchboard-xyz/common" "^2.3.9" +"@switchboard-xyz/solana.js@3.2.5", "@switchboard-xyz/solana.js@^3.2.5": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@switchboard-xyz/solana.js/-/solana.js-3.2.5.tgz#c4bd3218d0b3b6bfae19215990a21cc0d5a97efa" + integrity sha512-gCovHDTHCr+JPSwB5+JXqoKPwLs4GKM0sqUEEcQHJZXLpIAzE3Q0RDQOS76rgnpNR0sDYzv8a9aneab8GTG4Ag== + dependencies: + "@coral-xyz/anchor" "^0.29.0" + "@coral-xyz/borsh" "^0.29.0" + "@solana/spl-token" "^0.3.11" + "@solana/web3.js" "^1.89.1" + "@switchboard-xyz/common" "^2.3.16" cron-validator "^1.3.1" cross-fetch "^4.0.0" dotenv "^16.3.1" @@ -4973,6 +5668,19 @@ zod "^3.22.2" zod-error "^1.5.0" +"@symmetry-hq/baskets-sdk@0.0.45": + version "0.0.45" + resolved "https://registry.yarnpkg.com/@symmetry-hq/baskets-sdk/-/baskets-sdk-0.0.45.tgz#19d1c96bb0f659eccd7969aad3513bc4a7006a6b" + integrity sha512-w5w3yZl+qTwEAL8b21XGesuLX3HPpaQYyYkkRbwQBheqCJ8Geyg7/NyuZRF+8/a0XdubiQfW70QzBHZch6J0nA== + dependencies: + "@coral-xyz/anchor" "0.29.0" + "@metaplex-foundation/js" "0.19.4" + "@pythnetwork/client" "2.17.0" + "@solana/web3.js" "1.78.8" + "@types/crypto-js" "4.1.1" + axios "0.26.1" + crypto-js "4.1.1" + "@tailwindcss/forms@0.5.3": version "0.5.3" resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.3.tgz#e4d7989686cbcaf416c53f1523df5225332a86e7" @@ -5165,9 +5873,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" @@ -5250,6 +5958,11 @@ dependencies: "@types/node" "*" +"@types/crypto-js@4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.1.1.tgz#602859584cecc91894eb23a4892f38cfa927890d" + integrity sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA== + "@types/d3-array@*", "@types/d3-array@^3.0.3": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.0.4.tgz#44eebe40be57476cad6a0cd6a85b0f57d54185a2" @@ -5467,7 +6180,7 @@ dependencies: "@types/ms" "*" -"@types/estree@*", "@types/estree@^1.0.0": +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0": version "1.0.5" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== @@ -5540,11 +6253,6 @@ "@types/tough-cookie" "*" parse5 "^7.0.0" -"@types/json-schema@^7.0.9": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -5577,6 +6285,14 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/node-fetch@^2.6.2": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" + integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*", "@types/node@>=13.7.0": version "20.5.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.0.tgz#7fc8636d5f1aaa3b21e6245e97d56b7f56702313" @@ -5592,11 +6308,23 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93" integrity sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ== +"@types/node@18.15.13": + version "18.15.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" + integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== + "@types/node@^12.12.54": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/node@^18.7.13": + version "18.19.42" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.42.tgz#b54ed4752c85427906aab40917b0f7f3d724bf72" + integrity sha512-d2ZFc/3lnK2YCYhos8iaNIYu9Vfhr92nHiyJHRltXWjXUBjEE+A4I58Tdbnw4VhggSW+2j5y5gTrLs4biNnubg== + dependencies: + undici-types "~5.26.4" + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -5707,85 +6435,86 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.6.tgz#9c6017b6c1d04894141b4a87816388967f64c359" - integrity sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg== - dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/type-utils" "5.30.6" - "@typescript-eslint/utils" "5.30.6" - debug "^4.3.4" - functional-red-black-tree "^1.0.1" - ignore "^5.2.0" - regexpp "^3.2.0" - semver "^7.3.7" - tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.1.0.tgz#3c020deeaaba82a6f741d00dacf172c53be4911f" + integrity sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/type-utils" "8.1.0" + "@typescript-eslint/utils" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/parser@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" - integrity sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA== +"@typescript-eslint/parser@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.1.0.tgz#b7e77f5fa212df59eba51ecd4986f194bccc2303" + integrity sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA== dependencies: - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/typescript-estree" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.30.6.tgz#ce1b49ff5ce47f55518d63dbe8fc9181ddbd1a33" - integrity sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g== +"@typescript-eslint/scope-manager@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.1.0.tgz#dd8987d2efebb71d230a1c71d82e84a7aead5c3d" + integrity sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" -"@typescript-eslint/type-utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.30.6.tgz#a64aa9acbe609ab77f09f53434a6af2b9685f3af" - integrity sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA== +"@typescript-eslint/type-utils@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.1.0.tgz#dbf5a4308166dfc37a36305390dea04a3a3b5048" + integrity sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA== dependencies: - "@typescript-eslint/utils" "5.30.6" + "@typescript-eslint/typescript-estree" "8.1.0" + "@typescript-eslint/utils" "8.1.0" debug "^4.3.4" - tsutils "^3.21.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/types@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.30.6.tgz#86369d0a7af8c67024115ac1da3e8fb2d38907e1" - integrity sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg== +"@typescript-eslint/types@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.1.0.tgz#fbf1eaa668a7e444ac507732ca9d3c3468e5db9c" + integrity sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog== -"@typescript-eslint/typescript-estree@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.6.tgz#a84a0d6a486f9b54042da1de3d671a2c9f14484e" - integrity sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A== +"@typescript-eslint/typescript-estree@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.1.0.tgz#c44e5667683c0bb5caa43192e27de6a994f4e4c4" + integrity sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg== dependencies: - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/visitor-keys" "5.30.6" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/visitor-keys" "8.1.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" - semver "^7.3.7" - tsutils "^3.21.0" - -"@typescript-eslint/utils@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.30.6.tgz#1de2da14f678e7d187daa6f2e4cdb558ed0609dc" - integrity sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.30.6" - "@typescript-eslint/types" "5.30.6" - "@typescript-eslint/typescript-estree" "5.30.6" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/visitor-keys@5.30.6": - version "5.30.6" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.6.tgz#94dd10bb481c8083378d24de1742a14b38a2678c" - integrity sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA== - dependencies: - "@typescript-eslint/types" "5.30.6" - eslint-visitor-keys "^3.3.0" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.1.0.tgz#a922985a43d2560ce0d293be79148fa80c1325e0" + integrity sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.1.0" + "@typescript-eslint/types" "8.1.0" + "@typescript-eslint/typescript-estree" "8.1.0" + +"@typescript-eslint/visitor-keys@8.1.0": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.1.0.tgz#ab2b3a9699a8ddebf0c205e133f114c1fed9daad" + integrity sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag== + dependencies: + "@typescript-eslint/types" "8.1.0" + eslint-visitor-keys "^3.4.3" "@ubeswap/token-math@^4.4.4": version "4.4.8" @@ -5864,11 +6593,21 @@ dependencies: "@wallet-standard/base" "^1.0.1" -"@wallet-standard/base@^1.0.0", "@wallet-standard/base@^1.0.1": +"@wallet-standard/base@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@wallet-standard/base/-/base-1.0.1.tgz#860dd94d47c9e3c5c43b79d91c6afdbd7a36264e" integrity sha512-1To3ekMfzhYxe0Yhkpri+Fedq0SYcfrOfJi3vbLjMwF2qiKPjTGLwZkf2C9ftdQmxES+hmxhBzTwF4KgcOwf8w== +"@wallet-standard/core@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@wallet-standard/core/-/core-1.0.3.tgz#3b6743e207ca4e1e725ae20f1838b400fb0694ff" + integrity sha512-Jb33IIjC1wM1HoKkYD7xQ6d6PZ8EmMZvyc8R7dFgX66n/xkvksVTW04g9yLvQXrLFbcIjHrCxW6TXMhvpsAAzg== + dependencies: + "@wallet-standard/app" "^1.0.1" + "@wallet-standard/base" "^1.0.1" + "@wallet-standard/features" "^1.0.3" + "@wallet-standard/wallet" "^1.0.1" + "@wallet-standard/features@^1.0.3": version "1.0.3" resolved "https://registry.yarnpkg.com/@wallet-standard/features/-/features-1.0.3.tgz#c992876c5e4f7a0672f8869c4146c87e0dfe48c8" @@ -5894,26 +6633,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": @@ -5931,62 +6671,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" @@ -6038,29 +6775,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" @@ -6069,15 +6804,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" @@ -6086,25 +6821,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": @@ -6185,25 +6919,44 @@ 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.12.0, acorn@^8.4.1, acorn@^8.8.1: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +add-to-calendar-button-react@2.6.13: + version "2.6.13" + resolved "https://registry.yarnpkg.com/add-to-calendar-button-react/-/add-to-calendar-button-react-2.6.13.tgz#4a0254983f90b74ad7f23fc613beb994f3519cf7" + integrity sha512-GQZNxHTkUBZ+I8Y9ojIjFpRRtfVxy5zKdru9PZM0hVJIq2nWuvjU7XgAMXhYQ41adTIXiZa/A5LUC4Xm4+CH7g== + dependencies: + add-to-calendar-button "^2.6.13" + +add-to-calendar-button@^2.6.13: + version "2.6.13" + resolved "https://registry.yarnpkg.com/add-to-calendar-button/-/add-to-calendar-button-2.6.13.tgz#e52c22ee5dc6262d842c5f124e809df3f6eee78b" + integrity sha512-Me2n/8uV8AWq3guJI0tbBpVgeXTsMVXAXmxfZeCFPh6PHItr1pQjKlPRKZmf84BSdDJHvVLXG7kGKE/X78D2pA== + dependencies: + timezones-ical-library "^1.8.2" aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== +aes-js@4.0.0-beta.5: + version "4.0.0-beta.5" + resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" + integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -6211,14 +6964,14 @@ agent-base@6: dependencies: debug "4" -agentkeepalive@^4.2.1: +agentkeepalive@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== dependencies: humanize-ms "^1.2.1" -ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: +ajv@^6.12.3, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -6281,7 +7034,7 @@ ansi-regex@3.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -"ansi-regex@>=3.0.1 <=5.0.1", ansi-regex@^2.0.0, ansi-regex@^3.0.0, ansi-regex@^4.1.0, ansi-regex@^5.0.0, ansi-regex@^5.0.1: +"ansi-regex@>=3.0.1 <=5.0.1", ansi-regex@^2.0.0, ansi-regex@^3.0.0, ansi-regex@^4.1.0, ansi-regex@^5.0.0, ansi-regex@^5.0.1, ansi-regex@^6.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== @@ -6310,6 +7063,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + ansicolors@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" @@ -6320,7 +7078,12 @@ 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: +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +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== @@ -6414,15 +7177,24 @@ aria-query@^5.0.0: dependencies: deep-equal "^2.0.5" -array-includes@^3.1.4, array-includes@^3.1.5: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.5, array-includes@^3.1.7, array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-move@^3.0.1: @@ -6435,26 +7207,75 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array.prototype.flat@^1.2.5: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" -array.prototype.flatmap@^1.2.5: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -6592,10 +7413,12 @@ autoprefixer@^9.6.1: postcss "^7.0.32" postcss-value-parser "^4.1.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" "avsc@https://github.com/Bundlr-Network/avsc#csp-fixes": version "5.4.7" @@ -6611,7 +7434,7 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== -axios@0.26.1, axios@^0.26.0: +axios@0.26.1: version "0.26.1" resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== @@ -6647,21 +7470,12 @@ 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: - version "1.6.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" - integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== +axios@^1.1.3, axios@^1.3.6, axios@^1.4.0, axios@^1.6.2, axios@^1.7.2, axios@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.5.tgz#21eed340eb5daf47d29b6e002424b3e88c8c54b1" + integrity sha512-fZu86yCo+svH3uqJ/yTdQ0QHpQu5oL+/QE+QPSv6BZSkDAoky9vytxp7u5qk83OJFS3kEBcesWni9WTZAv3tSw== dependencies: - follow-redirects "^1.15.0" + follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" @@ -6825,10 +7639,10 @@ bin-links@4.0.1: read-cmd-shim "^4.0.0" write-file-atomic "^5.0.0" -binance-api-node@^0.12.0: - version "0.12.2" - resolved "https://registry.yarnpkg.com/binance-api-node/-/binance-api-node-0.12.2.tgz#a7f9b8d94c2d75f64cb709d7b041b80da1e0e79d" - integrity sha512-X9zKjYhcp+smUMxmZvJdcqd22wQnD8gyjRKCmf1dno9Ft/mr9ZavtzHzjJaoXGbHbcGI2gSSg6fa8ozfT6B6Yg== +binance-api-node@^0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/binance-api-node/-/binance-api-node-0.12.7.tgz#bce64742d5dc5a9398df3cbd861c486b4d4df075" + integrity sha512-hEIPaZg1YwZClOznAJo5Zb1JyxsqdYjT8twG48rhOwhbNVrLJRxkeGj+PTa881wFXOtyOtyrXsDytsEcI2EUHA== dependencies: https-proxy-agent "^5.0.0" isomorphic-fetch "^3.0.0" @@ -7131,30 +7945,38 @@ bufferutil@^4.0.1, bufferutil@^4.0.6: dependencies: node-gyp-build "^4.3.0" -bytebuffer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd" - integrity sha512-IuzSdmADppkZ6DlpycMkm8l9zeEq16fWtLvunEwFiYciR/BHo4E8/xs5piFquG+Za8OWmMqHF8zuRviz2LHvRQ== +bundle-require@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-5.0.0.tgz#071521bdea6534495cf23e92a83f889f91729e93" + integrity sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w== dependencies: - long "~3" + load-tsconfig "^0.2.3" bytes@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + caip@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/caip/-/caip-1.1.0.tgz#0ccd5bf1bff822459389ccec0a8555712a30c374" integrity sha512-yOO3Fu4ygyKYAdznuoaqschMKIZzcdgyMpBNtrIfrUhnOeaOWG+dh0c13wcOS6B/46IGGbncoyzJlio79jU7rw== -call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" callsites@^3.0.0: version "3.1.0" @@ -7230,19 +8052,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" @@ -7279,6 +8088,11 @@ chalk@^2.4.1, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -7295,11 +8109,13 @@ 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: +chokidar@3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -7314,6 +8130,21 @@ chokidar@3.5.3, chokidar@^3.5.2, chokidar@^3.5.3: optionalDependencies: fsevents "~2.3.2" +chokidar@^3.5.2, chokidar@^3.5.3, chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" @@ -7332,6 +8163,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" @@ -7389,6 +8227,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" @@ -7426,6 +8273,16 @@ 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== +clsx@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +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" @@ -7516,12 +8373,17 @@ commander@7: resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^12.0.0, commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.1: +commander@^4.0.0, commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== @@ -7551,6 +8413,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" @@ -7566,6 +8433,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" @@ -7698,6 +8570,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" @@ -7720,7 +8597,7 @@ crypto-hash@^1.3.0: resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== -crypto-js@>=4.1.1, crypto-js@^3.1.9-1, crypto-js@^4.1.1, crypto-js@^4.2.0: +crypto-js@4.1.1, crypto-js@>=4.1.1, crypto-js@^3.1.9-1, crypto-js@^4.1.1, crypto-js@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== @@ -8177,11 +9054,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" @@ -8191,6 +9063,33 @@ data-urls@^3.0.2: whatwg-mimetype "^3.0.0" whatwg-url "^11.0.0" +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + date-fns@2.29.2: version "2.29.2" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.2.tgz#0d4b3d0f3dff0f920820a070920f0d9662c51931" @@ -8206,20 +9105,20 @@ dayjs@1.11.1: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.1.tgz#90b33a3dda3417258d48ad2771b415def6545eb0" integrity sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA== -debug@4, debug@4.3.4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5, debug@~4.3.1, debug@~4.3.2: + version "4.3.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.6.tgz#2ab2c38fbaffebf8aa95fdfe6d88438c7a13c52b" + integrity sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg== + dependencies: + ms "2.1.2" + +debug@4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -8242,7 +9141,7 @@ decimal.js-light@^2.4.1, decimal.js-light@^2.5.1: resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== -decimal.js@^10.4.2, decimal.js@^10.4.3: +decimal.js@10.4.3, decimal.js@^10.4.0, decimal.js@^10.4.2, decimal.js@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== @@ -8254,7 +9153,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== @@ -8271,13 +9170,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" @@ -8316,11 +9208,21 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" -define-properties@^1.1.3, define-properties@^1.1.4: +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" - integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" @@ -8329,6 +9231,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" @@ -8351,6 +9258,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" @@ -8374,6 +9286,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" @@ -8384,6 +9301,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" @@ -8453,9 +9375,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" @@ -8476,13 +9398,6 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - dom-accessibility-api@^0.5.6: version "0.5.14" resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56" @@ -8500,14 +9415,6 @@ dom-helpers@^3.4.0: dependencies: "@babel/runtime" "^7.1.2" -dom-helpers@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - domexception@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" @@ -8571,6 +9478,11 @@ duplexify@^4.1.2: readable-stream "^3.1.1" stream-shift "^1.0.0" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -8579,7 +9491,7 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -ed2curve@0.3.0, ed2curve@^0.3.0: +ed2curve@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/ed2curve/-/ed2curve-0.3.0.tgz#322b575152a45305429d546b071823a93129a05d" integrity sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ== @@ -8631,6 +9543,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -8700,36 +9617,69 @@ error-polyfill@^0.1.3: o3 "^1.0.3" u3 "^0.1.1" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.20.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.5.tgz#e6dc99177be37cacda5988e692c3fa8b218e95d2" - integrity sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ== - dependencies: - call-bind "^1.0.2" +es-abstract@^1.17.5, es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" - function-bind "^1.1.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.1.3" - get-symbol-description "^1.0.0" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" + is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.12.2" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-get-iterator@^1.1.2: version "1.1.2" @@ -8745,12 +9695,48 @@ es-get-iterator@^1.1.2: is-string "^1.0.5" isarray "^2.0.5" -es-shim-unscopables@^1.0.0: +es-iterator-helpers@^1.0.19: + version "1.0.19" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + internal-slot "^1.0.7" + iterator.prototype "^1.1.2" + safe-array-concat "^1.1.2" + +es-object-atoms@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz#702e632193201e3edf8713635d083d378e510241" - integrity sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w== + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== dependencies: - has "^1.0.3" + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" @@ -8778,6 +9764,36 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +esbuild@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.23.0.tgz#de06002d48424d9fdb7eb52dbe8e95927f852599" + integrity sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.23.0" + "@esbuild/android-arm" "0.23.0" + "@esbuild/android-arm64" "0.23.0" + "@esbuild/android-x64" "0.23.0" + "@esbuild/darwin-arm64" "0.23.0" + "@esbuild/darwin-x64" "0.23.0" + "@esbuild/freebsd-arm64" "0.23.0" + "@esbuild/freebsd-x64" "0.23.0" + "@esbuild/linux-arm" "0.23.0" + "@esbuild/linux-arm64" "0.23.0" + "@esbuild/linux-ia32" "0.23.0" + "@esbuild/linux-loong64" "0.23.0" + "@esbuild/linux-mips64el" "0.23.0" + "@esbuild/linux-ppc64" "0.23.0" + "@esbuild/linux-riscv64" "0.23.0" + "@esbuild/linux-s390x" "0.23.0" + "@esbuild/linux-x64" "0.23.0" + "@esbuild/netbsd-x64" "0.23.0" + "@esbuild/openbsd-arm64" "0.23.0" + "@esbuild/openbsd-x64" "0.23.0" + "@esbuild/sunos-x64" "0.23.0" + "@esbuild/win32-arm64" "0.23.0" + "@esbuild/win32-ia32" "0.23.0" + "@esbuild/win32-x64" "0.23.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -8815,186 +9831,168 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== - -eslint-config-prettier@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz#eb25485946dd0c66cd216a46232dc05451518d1f" - integrity sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw== +eslint-config-prettier@9.1.0, eslint-config-prettier@^9.0.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== -eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" - resolve "^1.20.0" + is-core-module "^2.13.0" + resolve "^1.22.4" -eslint-module-utils@^2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974" - integrity sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA== +eslint-module-utils@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" + integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== dependencies: debug "^3.2.7" -eslint-plugin-import@2.26.0: - version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" - integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== +eslint-plugin-import@2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.3" - has "^1.0.3" - is-core-module "^2.8.1" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" is-glob "^4.0.3" minimatch "^3.1.2" - object.values "^1.1.5" - resolve "^1.22.0" - tsconfig-paths "^3.14.1" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" -eslint-plugin-prettier@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b" - integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ== +eslint-plugin-prettier@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95" + integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw== dependencies: prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" -eslint-plugin-react-hooks@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" - integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== - -eslint-plugin-react@7.29.4: - version "7.29.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" - integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== - dependencies: - array-includes "^3.1.4" - array.prototype.flatmap "^1.2.5" +eslint-plugin-react-hooks@4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== + +eslint-plugin-react@7.35.0: + version "7.35.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.35.0.tgz#00b1e4559896710e58af6358898f2ff917ea4c41" + integrity sha512-v501SSMOWv8gerHkk+IIQBkcGRGrO2nfybfj5pLxuJNFTPxxA3PSryhXTK+9pNbtkggheDdsC0E9Q8CuPk6JKA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.2" + array.prototype.tosorted "^1.1.4" doctrine "^2.1.0" + es-iterator-helpers "^1.0.19" estraverse "^5.3.0" + hasown "^2.0.2" jsx-ast-utils "^2.4.1 || ^3.0.0" minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.0" - object.values "^1.1.5" + object.entries "^1.1.8" + object.fromentries "^2.0.8" + object.values "^1.2.0" prop-types "^15.8.1" - resolve "^2.0.0-next.3" - semver "^6.3.0" - string.prototype.matchall "^4.0.6" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.11" + string.prototype.repeat "^1.0.0" -eslint-plugin-unused-imports@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" - integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== - dependencies: - eslint-rule-composer "^0.3.0" - -eslint-rule-composer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" - integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== - -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" +eslint-plugin-unused-imports@4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.3.tgz#079ef6f51914a981e657b3834935a6a417bf3f45" + integrity sha512-lqrNZIZjFMUr7P06eoKtQLwyVRibvG7N+LtfKtObYGizAAGrcqLkc3tDx+iAik2z7q0j/XI3ihjupIqxhFabFA== -eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== +eslint-scope@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.0.2.tgz#5cbb33d4384c9136083a71190d548158fe128f94" + integrity sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== +eslint-visitor-keys@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" + integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== -eslint@8.17.0: - version "8.17.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.17.0.tgz#1cfc4b6b6912f77d24b874ca1506b0fe09328c21" - integrity sha512-gq0m0BTJfci60Fz4nczYxNAlED+sMcihltndR8t9t1evnU/azx53x3t2UHXC/uRjcbvRw/XctpaNygSTcQD+Iw== - dependencies: - "@eslint/eslintrc" "^1.3.0" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" +eslint@9.9.0: + version "9.9.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.9.0.tgz#8d214e69ae4debeca7ae97daebbefe462072d975" + integrity sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.17.1" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.9.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.0" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.2" - esquery "^1.4.0" + eslint-scope "^8.0.2" + eslint-visitor-keys "^4.0.0" + espree "^10.1.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.15.0" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" ignore "^5.2.0" - import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^4.1.0" + is-path-inside "^3.0.3" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" + optionator "^0.9.3" strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^9.3.2, espree@^9.4.0: - version "9.4.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.4.1.tgz#51d6092615567a2c2cff7833445e37c28c0065bd" - integrity sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg== +espree@^10.0.1, espree@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.1.0.tgz#8788dae611574c0f070691f522e4116c5a11fc56" + integrity sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA== dependencies: - acorn "^8.8.0" + acorn "^8.12.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^4.0.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -9005,11 +10003,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -9107,6 +10100,19 @@ ethers@^5.5.1: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" +ethers@^6.10.0: + version "6.11.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.11.1.tgz#96aae00b627c2e35f9b0a4d65c7ab658259ee6af" + integrity sha512-mxTAE6wqJQAbp5QAe/+o+rXOID7Nw91OZXvgpjDa1r4fAbq2Nu314oEZSbjoRLacuCzs7kUC3clEvkCQowffGg== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "18.15.13" + aes-js "4.0.0-beta.5" + tslib "2.4.0" + ws "8.5.0" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -9120,6 +10126,11 @@ eventemitter3@^4.0.1, eventemitter3@^4.0.7: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -9149,7 +10160,7 @@ execa@^3.4.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^5.0.0: +execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -9164,6 +10175,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" @@ -9224,6 +10250,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" @@ -9261,9 +10292,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" @@ -9308,13 +10339,10 @@ 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" +fecha@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== fetch-retry@^5.0.6: version "5.0.6" @@ -9348,12 +10376,12 @@ figures@^3.0.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" file-selector@^0.6.0: version "0.6.0" @@ -9384,7 +10412,7 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@5.0.0: +find-up@5.0.0, find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -9414,23 +10442,23 @@ find@^0.3.0: dependencies: traverse-chain "~0.1.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + flatted "^3.2.9" + keyv "^4.5.4" flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== flatten@^1.0.2: version "1.0.3" @@ -9444,15 +10472,10 @@ focus-lock@^0.11.2: dependencies: tslib "^2.0.3" -focus-visible@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.2.0.tgz#3a9e41fccf587bd25dcc2ef045508284f0a4d6b3" - integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== - -follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.7, follow-redirects@^1.14.8, follow-redirects@^1.14.9, follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.7, follow-redirects@^1.14.8, follow-redirects@^1.14.9, follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-each@^0.3.3: version "0.3.3" @@ -9461,6 +10484,14 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" +foreground-child@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7" + integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -9484,13 +10515,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" @@ -9523,36 +10547,26 @@ 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: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - -functions-have-names@^1.2.2: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -9581,19 +10595,21 @@ 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" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" - integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== +get-intrinsic@^1.1.0, get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: - function-bind "^1.1.1" - has "^1.0.3" + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" has-symbols "^1.0.3" + hasown "^2.0.0" get-nonce@^1.0.0: version "1.0.1" @@ -9610,6 +10626,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" @@ -9622,13 +10643,19 @@ 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-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" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +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.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" getpass@^0.1.1: version "0.1.7" @@ -9663,6 +10690,18 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^10.3.10: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -9691,12 +10730,18 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.15.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globalthis@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - type-fest "^0.20.2" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^11.1.0: version "11.1.0" @@ -9722,6 +10767,11 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + graphql@16.5.0: version "16.5.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.5.0.tgz#41b5c1182eaac7f3d47164fb247f61e4dfb69c85" @@ -9734,6 +10784,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" @@ -9769,37 +10834,35 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" - integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: - get-intrinsic "^1.1.1" + es-define-property "^1.0.0" + +has-proto@^1.0.1, has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: - has-symbols "^1.0.2" + has-symbols "^1.0.3" has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - hash-base@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" @@ -9817,10 +10880,10 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -9902,6 +10965,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" @@ -9929,6 +10997,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" @@ -9960,6 +11033,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" @@ -9978,10 +11056,10 @@ iframe-resizer@^4.3.0: resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.3.6.tgz#61d92c1adefe5d416bff4fbf80c7f1f74be70ec0" integrity sha512-wz0WodRIF6eP0oGQa5NIP1yrITAZ59ZJvVaVJqJRjaeCtfm461vy2C3us6CKx0e7pooqpIGLpVMSTzrfAjX9Sg== -ignore@^5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.1.tgz#c2b1f76cb999ede1502f3a226a9310fdfe88d46c" - integrity sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA== +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== immediate@~3.0.5: version "3.0.6" @@ -9993,17 +11071,12 @@ immer@9.0.15: resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.15.tgz#0b9169e5b1d22137aba7d43f8a81a495dd1b62dc" integrity sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ== -immer@^9.0.14: - version "9.0.16" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198" - integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ== - immutable@~3.7.4: version "3.7.6" resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" integrity sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw== -import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: +import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -10083,13 +11156,13 @@ inquirer@^8.2.0: through "^2.3.6" wrap-ansi "^7.0.0" -internal-slot@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.4.tgz#8551e7baf74a7a6ba5f749cfb16aa60722f0d6f3" - integrity sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" + es-errors "^1.3.0" + hasown "^2.0.0" side-channel "^1.0.4" "internmap@1 - 2": @@ -10114,6 +11187,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" @@ -10122,6 +11215,14 @@ is-arguments@^1.0.4, is-arguments@^1.1.0, is-arguments@^1.1.1: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -10132,6 +11233,13 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -10176,19 +11284,19 @@ is-color-stop@^1.1.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.13.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== +is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.0.tgz#71c72ec5442ace7e76b306e9d48db361f22699ea" + integrity sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" -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== +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== dependencies: - has "^1.0.3" + is-typed-array "^1.1.13" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" @@ -10197,11 +11305,23 @@ 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" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-finalizationregistry@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== + dependencies: + call-bind "^1.0.2" + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -10224,7 +11344,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: +is-generator-function@^1.0.10, is-generator-function@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== @@ -10243,15 +11363,22 @@ 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" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-map@^2.0.1, is-map@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" - integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== +is-map@^2.0.2, is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== is-nan@^1.2.1: version "1.3.2" @@ -10261,10 +11388,10 @@ is-nan@^1.2.1: call-bind "^1.0.0" define-properties "^1.1.3" -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -10290,6 +11417,11 @@ is-observable@^1.1.0: dependencies: symbol-observable "^1.1.0" +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" @@ -10330,17 +11462,17 @@ is-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA== -is-set@^2.0.1, is-set@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.2.tgz#90755fa4c2562dc1c5d4024760d6119b94ca18ec" - integrity sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g== +is-set@^2.0.2, is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== +is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" is-stream@^1.1.0: version "1.1.0" @@ -10352,6 +11484,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" @@ -10366,16 +11503,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.3: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== +is-typed-array@^1.1.13, is-typed-array@^1.1.3: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.14" is-typedarray@~1.0.0: version "1.0.0" @@ -10387,10 +11520,10 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-weakmap@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.1.tgz#5008b59bdc43b698201d18f62b37b2ca243e8cf2" - integrity sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== is-weakref@^1.0.2: version "1.0.2" @@ -10399,13 +11532,27 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-weakset@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.2.tgz#4569d67a747a1ce5a994dfd4ef6dcea76e7c0a1d" - integrity sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg== +is-weakset@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + +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" @@ -10430,11 +11577,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" @@ -10482,10 +11642,30 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jayson@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" - integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== + dependencies: + define-properties "^1.2.1" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" + +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jayson@^4.0.0, jayson@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.1.tgz#282ff13d3cea09776db684b7eeca98c47b2fa99a" + integrity sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w== dependencies: "@types/connect" "^3.4.33" "@types/node" "^12.12.54" @@ -10498,7 +11678,7 @@ jayson@^4.1.0: isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" uuid "^8.3.2" - ws "^7.4.5" + ws "^7.5.10" jest-changed-files@^29.2.0: version "29.2.0" @@ -10875,10 +12055,39 @@ jest@29.2.0: import-local "^3.0.2" jest-cli "^29.2.0" -js-base64@^3.7.2: - version "3.7.3" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.3.tgz#2e784bb0851636bf1e99ef12e4f3a8a8c9b7639f" - integrity sha512-PAr6Xg2jvd7MCR6Ld9Jg3BmTcjYsHEBx1VlwEwULb/qowPf5VD9kEMagj23Gm7JRnSvE/Da/57nChZjnvL8v6A== +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== + +jito-ts@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jito-ts/-/jito-ts-3.0.1.tgz#24126389896e042c26d303c4e802064b249ed27e" + integrity sha512-TSofF7KqcwyaWGjPaSYC8RDoNBY1TPRNBHdrw24bdIi7mQ5bFEDdYK3D//llw/ml8YDvcZlgd644WxhjLTS9yg== + dependencies: + "@grpc/grpc-js" "^1.8.13" + "@noble/ed25519" "^1.7.1" + "@solana/web3.js" "~1.77.3" + agentkeepalive "^4.3.0" + dotenv "^16.0.3" + jayson "^4.0.0" + node-fetch "^2.6.7" + superstruct "^1.0.3" + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +js-base64@^3.7.2, js-base64@^3.7.5: + version "3.7.7" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.7.tgz#e51b84bf78fbf5702b9541e2cb7bfcb893b43e79" + integrity sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw== + +js-sha256@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.11.0.tgz#256a921d9292f7fe98905face82e367abaca9576" + integrity sha512-6xNlKayMZvds9h1Y1VWc0fQHQ82BxTXizWPEtEeGvmOUYpBRy4gbWroHLpzowe6xiQhHpelCQiE7HEdznyBL9Q== js-sha256@^0.9.0: version "0.9.0" @@ -10969,6 +12178,11 @@ json-bigint@^1.0.0: dependencies: bignumber.js "^9.0.0" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -11011,10 +12225,10 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== +json5@^1.0.1, json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" @@ -11023,6 +12237,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" @@ -11083,6 +12302,13 @@ keccak@^3.0.0, keccak@^3.0.2: node-gyp-build "^4.2.0" readable-stream "^3.6.0" +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + keyvaluestorage-interface@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff" @@ -11141,18 +12367,16 @@ lilconfig@^2.0.5: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +lilconfig@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.2.tgz#e4a7c3cb549e3a606c8dcc32e5ae1005e62c05cb" + integrity sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -linkify-it@^2.0.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" - integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== - dependencies: - uc.micro "^1.0.1" - lint-staged@10.0.10: version "10.0.10" resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.0.10.tgz#d14d33ee02a31a31ad36cf9aa7973fc156c461b5" @@ -11172,6 +12396,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" @@ -11216,7 +12464,12 @@ listr@^0.14.3: p-map "^2.0.0" rxjs "^6.3.3" -localforage@1.10.0, localforage@^1.10.0, localforage@^1.8.1: +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + +localforage@1.10.0, localforage@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== @@ -11260,6 +12513,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" @@ -11270,6 +12528,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" @@ -11290,6 +12553,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== + lodash.topath@^4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" @@ -11346,11 +12614,6 @@ long@^5.0.0: resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== -long@~3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" - integrity sha512-ZYvPPOMqUwPoDsbJaR10iQJYnMuZhRTvHYl62ErLIEX7RgFlziSBUUvrt3OVfc47QlHHpzPZYP17g3Fv7oeJkg== - longest-streak@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.1.0.tgz#62fa67cd958742a1574af9f39866364102d90cd4" @@ -11363,13 +12626,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" @@ -11377,17 +12633,10 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -luxon@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.5.0.tgz#098090f67d690b247e83c090267a60b1aa8ea96c" - integrity sha512-IDkEPB80Rb6gCAU+FEib0t4FeJ4uVOuX1CQ9GsvU3O+JAGIgu0J7sf1OarXKaKDygTZIoJyU6YdZzTFRu+YR0A== +lru-cache@^10.0.2, lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lz-string@^1.4.4: version "1.4.4" @@ -11892,7 +13141,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== @@ -11935,6 +13184,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" @@ -11976,6 +13230,13 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.7" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" @@ -11995,6 +13256,11 @@ minipass@^4.0.0: dependencies: yallist "^4.0.0" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -12015,6 +13281,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" @@ -12042,39 +13318,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== @@ -12084,11 +13333,6 @@ mrmime@^1.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -12122,6 +13366,15 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nan@^2.14.0, nan@^2.14.2: version "2.17.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" @@ -12142,6 +13395,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" @@ -12240,10 +13498,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" @@ -12252,6 +13510,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" @@ -12259,6 +13522,13 @@ node-fetch@2.6.1, node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" +node-fetch@3.3.2, "node-fetch@npm:@blockworks-foundation/node-fetch@2.6.11": + version "2.6.11" + resolved "https://registry.yarnpkg.com/@blockworks-foundation/node-fetch/-/node-fetch-2.6.11.tgz#fb536ef0e6a960e7b7993f3c1d3b3bba9bdfbc56" + integrity sha512-HeDTxpIypSR4qCoqgUXGr8YL4OG1z7BbV4VhQ9iQs+pt2wV3MtqO+sQk2vXK3WDKu5C6BsbGmWE22BmIrcuOOw== + 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" @@ -12266,14 +13536,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" @@ -12352,6 +13618,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" @@ -12397,7 +13670,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== @@ -12407,10 +13680,10 @@ object-hash@^2.2.0: resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== -object-inspect@^1.12.2, object-inspect@^1.9.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea" - integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== object-is@^1.0.1, object-is@^1.1.5: version "1.1.5" @@ -12425,56 +13698,72 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.3, object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.3, object.assign@^4.1.4, object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" + call-bind "^1.0.5" + define-properties "^1.2.1" has-symbols "^1.0.3" object-keys "^1.1.1" -object.entries@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.6.tgz#9737d0e5b8291edd340a3e3264bb8a3b00d5fa23" - integrity sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w== +object.entries@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -object.fromentries@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.6.tgz#cdb04da08c539cffa912dcd368b886e0904bfa73" - integrity sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg== +object.fromentries@^2.0.7, object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" -object.hasown@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.2.tgz#f919e21fad4eb38a57bc6345b3afd496515c3f92" - integrity sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw== +object.groupby@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" -object.values@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.values@^1.1.7, object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" oblivious-set@1.1.1: version "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" @@ -12501,6 +13790,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" @@ -12518,17 +13814,17 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" ora@^5.4.1: version "5.4.1" @@ -12600,6 +13896,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pako@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" @@ -12660,16 +13961,34 @@ 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" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-type@^4.0.0: version "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" @@ -12696,10 +14015,10 @@ picocolors@^0.2.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -12736,17 +14055,26 @@ pino@7.11.0: sonic-boom "^2.2.1" thread-stream "^0.15.1" -pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== +pirates@^4.0.1, pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: - find-up "^4.0.0" + 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" @@ -12767,6 +14095,11 @@ polished@^4.1.3, polished@^4.2.2: dependencies: "@babel/runtime" "^7.17.8" +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + postcss-attribute-case-insensitive@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" @@ -12939,6 +14272,13 @@ postcss-load-config@^3.1.0: lilconfig "^2.0.5" yaml "^1.10.2" +postcss-load-config@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-6.0.1.tgz#6fd7dcd8ae89badcf1b2d644489cbabf83aa8096" + integrity sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g== + dependencies: + lilconfig "^3.1.1" + postcss-logical@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" @@ -13254,10 +14594,10 @@ property-information@^6.0.0: resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.2.0.tgz#b74f522c31c097b5149e3c3cb8d7f3defd986a1d" integrity sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg== -protobufjs@^7.2.4: - version "7.2.4" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae" - integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== +protobufjs@>=7.2.5, protobufjs@^7.2.5, protobufjs@^7.2.6: + version "7.2.6" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.6.tgz#4a0ccd79eb292717aacf07530a07e0ed20278215" + integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== dependencies: "@protobufjs/aspromise" "^1.1.2" "@protobufjs/base64" "^1.1.2" @@ -13384,12 +14724,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" @@ -13419,6 +14759,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" @@ -13522,16 +14867,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" @@ -13596,15 +14936,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" @@ -13626,14 +14966,6 @@ react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-linkify@^1.0.0-alpha: - version "1.0.0-alpha" - resolved "https://registry.yarnpkg.com/react-linkify/-/react-linkify-1.0.0-alpha.tgz#b391c7b88e3443752fafe76a95ca4434e82e70d5" - integrity sha512-7gcIUvJkAXXttt1fmBK9cwn+1jTa4hbKLGCZ9J1U6EOkyb2/+LKL1Z28d9rtDLMnpvImlNlLPdTPooorl5cpmg== - dependencies: - linkify-it "^2.0.3" - tlds "^1.199.0" - react-markdown@7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-7.0.0.tgz#66565968e8513af070eeef65abc77e80fc1a9b87" @@ -13653,11 +14985,6 @@ react-markdown@7.0.0: unist-util-visit "^4.0.0" vfile "^5.0.0" -react-media-hook@^0.4.9: - version "0.4.9" - resolved "https://registry.yarnpkg.com/react-media-hook/-/react-media-hook-0.4.9.tgz#7e57092f5800c53787dc9e912ad09e749dfb7bc7" - integrity sha512-FZr/2xA1+23vDJ1IZ794yLqMRRkBoCNOiJATdtTfB5GyVc5djf8FL2qEB/68pSkiNgHdHsmKknMSDr0sC4zBKQ== - react-modal@^3.12.1: version "3.16.1" resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b" @@ -13755,6 +15082,11 @@ react-style-singleton@^2.2.1: invariant "^2.2.4" tslib "^2.0.0" +react-tiny-linkify@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-tiny-linkify/-/react-tiny-linkify-1.2.0.tgz#9182750e51f2c7d10103d1d8d0b7b2926671e77f" + integrity sha512-+h9harQ/FKMpb24CLfEE29ITaCvhuaM0pueS47rIRxOw35f3z+35rgsu47ZrUBawcsNnbWax5jZxbouiKUwJGQ== + react-transition-group@2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d" @@ -13765,16 +15097,6 @@ react-transition-group@2.9.0: prop-types "^15.6.2" react-lifecycles-compat "^3.0.4" -react-transition-group@^4.4.2: - version "4.4.5" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" - integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - react-use-gesture@^9.1.3: version "9.1.3" resolved "https://registry.yarnpkg.com/react-use-gesture/-/react-use-gesture-9.1.3.tgz#92bd143e4f58e69bd424514a5bfccba2a1d62ec0" @@ -13785,10 +15107,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" @@ -13834,9 +15156,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" @@ -13889,6 +15211,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" @@ -13897,6 +15231,19 @@ reduce-css-calc@^2.1.8: css-unit-converter "^1.1.1" postcss-value-parser "^3.3.0" +reflect.getprototypeof@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.1" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + globalthis "^1.0.3" + which-builtin-type "^1.1.3" + regenerator-runtime@^0.13.11: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" @@ -13907,19 +15254,15 @@ regenerator-runtime@^0.14.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== -regexp.prototype.flags@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" - integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== +regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - functions-have-names "^1.2.2" - -regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + call-bind "^1.0.6" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.1" remark-gfm@3.0.1: version "3.0.1" @@ -14023,7 +15366,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, resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -14032,21 +15375,12 @@ 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" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -14125,6 +15459,31 @@ rollup@2.78.0: optionalDependencies: fsevents "~2.3.2" +rollup@^4.19.0: + version "4.19.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.19.1.tgz#21d865cd60d4a325172ce8b082e60caccd97b309" + integrity sha512-K5vziVlg7hTpYfFBI+91zHBEMo6jafYXpkMlqZjg7/zhIG9iHqazBf4xz9AVdjS9BruRn280ROqLI7G3OFRIlw== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.19.1" + "@rollup/rollup-android-arm64" "4.19.1" + "@rollup/rollup-darwin-arm64" "4.19.1" + "@rollup/rollup-darwin-x64" "4.19.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.19.1" + "@rollup/rollup-linux-arm-musleabihf" "4.19.1" + "@rollup/rollup-linux-arm64-gnu" "4.19.1" + "@rollup/rollup-linux-arm64-musl" "4.19.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.19.1" + "@rollup/rollup-linux-riscv64-gnu" "4.19.1" + "@rollup/rollup-linux-s390x-gnu" "4.19.1" + "@rollup/rollup-linux-x64-gnu" "4.19.1" + "@rollup/rollup-linux-x64-musl" "4.19.1" + "@rollup/rollup-win32-arm64-msvc" "4.19.1" + "@rollup/rollup-win32-ia32-msvc" "4.19.1" + "@rollup/rollup-win32-x64-msvc" "4.19.1" + fsevents "~2.3.2" + rpc-websockets@^7.5.1: version "7.6.0" resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.6.0.tgz#d3f4c0dac108ca35566b0e31552c32e58928cd04" @@ -14183,6 +15542,16 @@ sade@^1.7.3: dependencies: mri "^1.1.0" +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -14198,19 +15567,19 @@ safe-json-utils@^1.1.1: resolved "https://registry.yarnpkg.com/safe-json-utils/-/safe-json-utils-1.1.1.tgz#0e883874467d95ab914c3f511096b89bfb3e63b1" integrity sha512-SAJWGKDs50tAbiDXLf89PDwt9XYkWyANFWVzn4dTXl5QyI8t2o/bW5/OJl3lvc2WVU4MEpTo9Yz5NVFNsp+OJQ== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" + call-bind "^1.0.6" + es-errors "^1.3.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" @@ -14285,17 +15654,15 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: - version "7.3.8" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798" - integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A== - dependencies: - lru-cache "^6.0.0" +semver@7.x, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.6.0: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -semver@^6.0.0, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== serialize-javascript@6.0.0: version "6.0.0" @@ -14309,6 +15676,28 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.1, set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -14349,20 +15738,26 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== +side-channel@^1.0.4, side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "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.0.1, 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" @@ -14456,6 +15851,13 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -14477,9 +15879,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" @@ -14515,11 +15917,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" @@ -14529,9 +15941,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" @@ -14561,6 +15973,15 @@ string-similarity@^4.0.3: resolved "https://registry.yarnpkg.com/string-similarity/-/string-similarity-4.0.4.tgz#42d01ab0b34660ea8a018da8f56a3309bb8b2a5b" integrity sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ== +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -14570,15 +15991,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -14596,37 +16008,68 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string.prototype.matchall@^4.0.6: - version "4.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" - integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string.prototype.matchall@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + gopd "^1.0.1" has-symbols "^1.0.3" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.4.3" - side-channel "^1.0.4" + internal-slot "^1.0.7" + regexp.prototype.flags "^1.5.2" + set-function-name "^2.0.2" + side-channel "^1.0.6" -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.1.3" + es-abstract "^1.17.5" -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" + +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@^1.1.1: version "1.3.0" @@ -14651,6 +16094,13 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -14672,12 +16122,12 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: - ansi-regex "^5.0.1" + ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" @@ -14694,6 +16144,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" @@ -14708,7 +16163,7 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@3.1.1, strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -14746,10 +16201,18 @@ stylis@4.1.3: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== -superstruct@0.15.4: - version "0.15.4" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.4.tgz#e3381dd84ca07e704e19f69eda74eee1a5efb1f9" - integrity sha512-eOoMeSbP9ZJChNOm/9RYjE+F36rYR966AAqeG3xhQB02j2sfAUXDp4EQ/7bAOqnlJnuFDB8yvOu50SocvKpUEw== +sucrase@^3.35.0: + version "3.35.0" + resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263" + integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA== + dependencies: + "@jridgewell/gen-mapping" "^0.3.2" + commander "^4.0.0" + glob "^10.3.10" + lines-and-columns "^1.1.6" + mz "^2.7.0" + pirates "^4.0.1" + ts-interface-checker "^0.1.9" superstruct@0.8.3: version "0.8.3" @@ -14759,6 +16222,11 @@ superstruct@0.8.3: kind-of "^6.0.2" tiny-invariant "^1.0.6" +superstruct@1.0.4, superstruct@^1.0.3, superstruct@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== + superstruct@^0.14.2: version "0.14.2" resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" @@ -14805,6 +16273,14 @@ swr@1.3.0, swr@^1.3.0: resolved "https://registry.yarnpkg.com/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8" integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw== +swr@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/swr/-/swr-2.2.5.tgz#063eea0e9939f947227d5ca760cc53696f46446b" + integrity sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg== + dependencies: + client-only "^0.0.1" + use-sync-external-store "^1.2.0" + symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -14815,6 +16291,19 @@ 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== +synckit@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.1.tgz#febbfbb6649979450131f64735aa3f6c14575c88" + integrity sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + +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" @@ -14921,6 +16410,20 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + thread-stream@^0.15.1: version "0.15.2" resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.15.2.tgz#fb95ad87d2f1e28f07116eb23d85aba3bc0425f4" @@ -14933,6 +16436,11 @@ thread-stream@^0.15.1: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +timezones-ical-library@^1.8.2: + version "1.8.2" + resolved "https://registry.yarnpkg.com/timezones-ical-library/-/timezones-ical-library-1.8.2.tgz#33a96db1f2bcce87d5e00ee64f263b9925c37719" + integrity sha512-0bbCp+xXtTUOcBo7bAGkzK5yMiNnY/FmJblTlnkGcqW5O+SChvWNtvsOX9WqbU5/8sT+Nl/MKQ7c9qafIkUstA== + timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" @@ -14955,11 +16463,6 @@ tippy.js@^6.3.1: dependencies: "@popperjs/core" "^2.9.0" -tlds@^1.199.0: - version "1.235.0" - resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.235.0.tgz#9274011fd6e3da8f6acb7db2362e048fe93a656e" - integrity sha512-YOZmbHZzB4xmhd09PQ3xIB9fypeEP+AzTiHHn+1uyo2xNzmnCZySIkrHs4qkUKvB3FOXBnHlUOgUON3DZKPQUA== - tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" @@ -15046,6 +16549,13 @@ tough-cookie@~2.5.0: psl "^1.1.28" punycode "^2.1.1" +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== + dependencies: + punycode "^2.1.0" + tr46@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" @@ -15063,6 +16573,11 @@ traverse-chain@~0.1.0: resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1" integrity sha512-up6Yvai4PYKhpNp5PkYtx50m3KbwQrqDwbuZP/ItyL64YEWHAvH6Md83LFLV/GRSk/BoUVwwgUzX6SOQSbsfAg== +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + treeify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" @@ -15073,11 +16588,21 @@ trough@^2.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-ev@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/ts-ev/-/ts-ev-0.4.0.tgz#b30bbab35bd57516efba7ab89b6417424a1ebf0e" integrity sha512-rLX6QdkC1/jA9sS4y9/DxHABTcOussp33J90h+TxHmya9CWvbGc9uLqdM4c/N4pNRmSdtq9zqhz7sB9KcN1NFQ== +ts-interface-checker@^0.1.9: + version "0.1.13" + resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" + integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== + ts-jest@29.0.3: version "29.0.3" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.0.3.tgz#63ea93c5401ab73595440733cefdba31fcf9cb77" @@ -15120,7 +16645,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== @@ -15158,7 +16683,7 @@ ts-toolbelt@^6.15.1: resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz#cb3b43ed725cb63644782c64fbcad7d8f28c0a83" integrity sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A== -tsconfig-paths@3.14.1, tsconfig-paths@^3.14.1, tsconfig-paths@^3.5.0: +tsconfig-paths@3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== @@ -15168,7 +16693,17 @@ tsconfig-paths@3.14.1, tsconfig-paths@^3.14.1, tsconfig-paths@^3.5.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@1.14.1, tslib@^1.8.1, tslib@^1.9.0: +tsconfig-paths@^3.15.0, tsconfig-paths@^3.5.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@1.14.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -15178,17 +16713,37 @@ tslib@2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" - integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== +tslib@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" +tsup@^8.1.0: + version "8.2.3" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.2.3.tgz#4a1ff2962a4d7c8265fea661b0dd9668de58916d" + integrity sha512-6YNT44oUfXRbZuSMNmN36GzwPPIlD2wBccY7looM2fkTcxkf2NEmwr3OZuDZoySklnrIG4hoEtzy8yUXYOqNcg== + dependencies: + bundle-require "^5.0.0" + cac "^6.7.14" + chokidar "^3.6.0" + consola "^3.2.3" + debug "^4.3.5" + esbuild "^0.23.0" + execa "^5.1.1" + globby "^11.1.0" + joycon "^3.1.1" + picocolors "^1.0.1" + postcss-load-config "^6.0.1" + resolve-from "^5.0.0" + rollup "^4.19.0" + source-map "0.8.0-beta.0" + sucrase "^3.35.0" + tree-kill "^1.2.2" tunnel-agent@^0.6.0: version "0.6.0" @@ -15267,11 +16822,6 @@ type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -15282,17 +16832,61 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -typedoc-plugin-missing-exports@^0.22.6: - version "0.22.6" - resolved "https://registry.yarnpkg.com/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz#7467c60f1cd26507124103f0b9bca271d5aa8d71" - integrity sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typescript-collections@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/typescript-collections/-/typescript-collections-1.3.3.tgz#62d50d93c018c094d425eabee649f00ec5cc0fea" integrity sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ== -typescript@4.9.5, typescript@^4.1.2, typescript@^4.3.5, typescript@^4.5.5, typescript@^4.6.2: +typescript@5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +typescript@^4.1.2, typescript@^4.3.5, typescript@^4.5.5, typescript@^4.6.2, typescript@^4.8.2: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -15312,10 +16906,10 @@ ua-parser-js@^1.0.2: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.32.tgz#786bf17df97de159d5b1c9d5e8e9e89806f8a030" integrity sha512-dXVsz3M4j+5tTiovFVyVqssXBu5HM47//YSOeZ9fQkdDKkfzv2v3PP1jmH6FUyPW+yCSn7aBVK1fGGKNhowdDA== -uc.micro@^1.0.1: - version "1.0.6" - 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" @@ -15334,6 +16928,32 @@ 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== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +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" @@ -15423,6 +17043,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" @@ -15431,6 +17077,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" @@ -15517,10 +17168,10 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uuid@^9.0.0, uuid@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== uvu@^0.5.0: version "0.5.6" @@ -15537,11 +17188,6 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - v8-to-istanbul@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" @@ -15631,11 +17277,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" @@ -15654,6 +17295,11 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" @@ -15720,6 +17366,15 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -15731,32 +17386,49 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-collection@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.1.tgz#70eab71ebbbd2aefaf32f917082fc62cdcb70906" - integrity sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A== +which-builtin-type@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.4.tgz#592796260602fc3514a1b5ee7fa29319b72380c3" + integrity sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w== + dependencies: + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.0.5" + is-finalizationregistry "^1.0.2" + is-generator-function "^1.0.10" + is-regex "^1.1.4" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.0.2" + which-collection "^1.0.2" + which-typed-array "^1.1.15" + +which-collection@^1.0.1, which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: - is-map "^2.0.1" - is-set "^2.0.1" - is-weakmap "^2.0.1" - is-weakset "^2.0.1" + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" 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" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2, which-typed-array@^1.1.8: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" + has-tostringtag "^1.0.2" which@^2.0.1, which@^2.0.2: version "2.0.2" @@ -15777,16 +17449,25 @@ wonka@^6.0.0, wonka@^6.1.2: resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.2.tgz#2c66fa5b26a12f002a03619b988258313d0b5352" integrity sha512-zNrXPMccg/7OEp9tSfFkMgTvhhowqasiSHdJ3eCZolXxVTV/aT6HUTofoZk9gwRbGoFey/Nss3JaZKUMKMbofg== -word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +word-wrap@^1.2.5, word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== workerpool@6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-3.0.1.tgz#288a04d87eda5c286e060dfe8f135ce8d007f8ba" @@ -15804,14 +17485,14 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" wrappy@1: version "1.0.2" @@ -15839,15 +17520,20 @@ ws@7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== -ws@^7.2.0, ws@^7.3.1, ws@^7.4.0, ws@^7.4.5, ws@^7.5.1: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +ws@^7.2.0, ws@^7.3.1, ws@^7.4.0, ws@^7.5.1, ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -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.18.0, ws@^8.5.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== ws@~8.2.3: version "8.2.3" @@ -15894,10 +17580,10 @@ yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yaml@^2.2.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b" - integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ== +yaml@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.5.0.tgz#c6165a721cf8000e91c36490a41d7be25176cf5d" + integrity sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw== yargs-parser@20.2.4: version "20.2.4" @@ -15961,10 +17647,10 @@ yargs@^13.2.4: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^17.3.1: - version "17.6.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" - integrity sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw== +yargs@^17.3.1, yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1"