From 89ab83bf342c877bacdb71846d12d683536fc82e Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 5 May 2022 03:35:16 +0900 Subject: [PATCH 1/5] add pyth voter weight --- components/TokenBalance/TokenBalanceCard.tsx | 80 ++++++++++++-------- components/VotePanel.tsx | 11 ++- hooks/useRealm.tsx | 37 ++++++++- hooks/useVotingPlugins.ts | 28 +++++++ models/voteWeights.ts | 80 ++++++++++++++++++++ next.config.js | 1 + package.json | 4 +- pages/dao/[symbol]/index.tsx | 6 +- stores/useVotePluginsClientStore.tsx | 31 ++++++++ utils/uiTypes/VotePlugin.ts | 43 ++++++++++- yarn.lock | 65 +++++++++++----- 11 files changed, 323 insertions(+), 63 deletions(-) diff --git a/components/TokenBalance/TokenBalanceCard.tsx b/components/TokenBalance/TokenBalanceCard.tsx index a960d7342f..09e922b385 100644 --- a/components/TokenBalance/TokenBalanceCard.tsx +++ b/components/TokenBalance/TokenBalanceCard.tsx @@ -37,6 +37,10 @@ import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import Link from 'next/link' import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' import { vsrPluginsPks } from '@hooks/useVotingPlugins' +import { + LOCALNET_REALM_ID as PYTH_LOCALNET_REALM_ID, + PythBalance, +} from 'pyth-staking-api' const TokenBalanceCard = ({ proposal }: { proposal?: Option }) => { const { councilMint, mint, realm, symbol } = useRealm() @@ -143,12 +147,14 @@ const TokenDeposit = ({ const wallet = useWalletStore((s) => s.current) const connected = useWalletStore((s) => s.connected) const connection = useWalletStore((s) => s.connection.current) + const cluster = useWalletStore((s) => s.connection.cluster) const { fetchWalletTokenAccounts, fetchRealm } = useWalletStore( (s) => s.actions ) const client = useVotePluginsClientStore( (s) => s.state.currentRealmVotingClient ) + const pythClient = useVotePluginsClientStore((s) => s.state.pythClient) const maxVoterWeight = useNftPluginStore((s) => s.state.maxVoteRecord)?.pubkey || undefined const { @@ -157,6 +163,7 @@ const TokenDeposit = ({ realmTokenAccount, ownTokenRecord, ownCouncilTokenRecord, + ownVoterWeight, councilTokenAccount, proposals, governances, @@ -366,7 +373,9 @@ const TokenDeposit = ({ : '' const availableTokens = - depositTokenRecord && mint + realmInfo?.realmId.toBase58() === PYTH_LOCALNET_REALM_ID.toBase58() + ? new PythBalance(ownVoterWeight.votingPower!).toString() + : depositTokenRecord && mint ? fmtMintAmount( mint, depositTokenRecord.account.governingTokenDepositAmount @@ -393,38 +402,43 @@ const TokenDeposit = ({ -

- You have {tokensToShow} tokens available to {canExecuteAction}. -

- -
- - - -
+ {realmInfo?.realmId.toBase58() === + PYTH_LOCALNET_REALM_ID.toBase58() ? null : ( + <> +

+ You have {tokensToShow} tokens available to {canExecuteAction}. +

+ +
+ + + +
+ + )} {config?.account.communityVoterWeightAddin && vsrPluginsPks.includes( config?.account.communityVoterWeightAddin.toBase58() diff --git a/components/VotePanel.tsx b/components/VotePanel.tsx index c26757054b..012366e054 100644 --- a/components/VotePanel.tsx +++ b/components/VotePanel.tsx @@ -17,6 +17,7 @@ import { getProgramVersionForRealm } from '@models/registry/api' import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { useRouter } from 'next/router' import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' +import { LOCALNET_REALM_ID as PYTH_LOCALNET_REALM_ID } from 'pyth-staking-api' const VotePanel = () => { const [showVoteModal, setShowVoteModal] = useState(false) @@ -181,9 +182,17 @@ const VotePanel = () => { : !ownVoteRecord?.account.isRelinquished const isPanelVisible = (isVoting || isVoteCast) && isVisibleToWallet + + const isRelinquishVotePanelVisible = !( + realmInfo?.realmId.toBase58() === PYTH_LOCALNET_REALM_ID.toBase58() && + isVoteCast && + connected && + !isVoting + ) + return ( <> - {isPanelVisible && ( + {isPanelVisible && isRelinquishVotePanelVisible && (

{actionLabel}

diff --git a/hooks/useRealm.tsx b/hooks/useRealm.tsx index a6e9949838..8412d77565 100644 --- a/hooks/useRealm.tsx +++ b/hooks/useRealm.tsx @@ -3,7 +3,9 @@ import { ProgramAccount, TokenOwnerRecord } from '@solana/spl-governance' import { isPublicKey } from '@tools/core/pubkey' import { useRouter } from 'next/router' import useNftPluginStore from 'NftVotePlugin/store/nftPluginStore' -import { useMemo, useState } from 'react' +import { PythBalance } from 'pyth-staking-api' +import { useEffect, useMemo, useState } from 'react' +import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import useDepositStore from 'VoteStakeRegistry/stores/useDepositStore' import { createUnchartedRealmInfo, @@ -11,13 +13,18 @@ import { RealmInfo, } from '../models/registry/api' import { + PythVoterWeight, VoteNftWeight, VoteRegistryVoterWeight, VoterWeight, } from '../models/voteWeights' import useWalletStore from '../stores/useWalletStore' -import { nftPluginsPks, vsrPluginsPks } from './useVotingPlugins' +import { + nftPluginsPks, + vsrPluginsPks, + pythPluginsPks, +} from './useVotingPlugins' export default function useRealm() { const router = useRouter() @@ -39,6 +46,27 @@ export default function useRealm() { } = useWalletStore((s) => s.selectedRealm) const votingPower = useDepositStore((s) => s.state.votingPower) const nftVotingPower = useNftPluginStore((s) => s.state.votingPower) + + const pythClient = useVotePluginsClientStore((s) => s.state.pythClient) + const [pythVoterWeight, setPythVoterWeight] = useState< + PythBalance | undefined + >(undefined) + + useEffect(() => { + const getPythVoterWeight = async () => { + if (connected && wallet?.publicKey && pythClient) { + const sa = await pythClient.stakeConnection.getMainAccount( + wallet.publicKey + ) + const vw = sa?.getVoterWeight( + await pythClient.stakeConnection.getTime() + ) + setPythVoterWeight(vw) + } + } + getPythVoterWeight() + }, [connected]) + const [realmInfo, setRealmInfo] = useState(undefined) useMemo(async () => { let realmInfo = isPublicKey(symbol as string) @@ -124,6 +152,7 @@ export default function useRealm() { ownTokenRecord, votingPower, nftVotingPower, + pythVoterWeight?.toBN() || new BN(0), ownCouncilTokenRecord ) return { @@ -157,6 +186,7 @@ const getVoterWeight = ( ownTokenRecord: ProgramAccount | undefined, votingPower: BN, nftVotingPower: BN, + pythVotingPower: BN, ownCouncilTokenRecord: ProgramAccount | undefined ) => { if (currentPluginPk) { @@ -170,6 +200,9 @@ const getVoterWeight = ( nftVotingPower ) } + if (pythPluginsPks.includes(currentPluginPk.toBase58())) { + return new PythVoterWeight(ownTokenRecord, pythVotingPower) + } } return new VoterWeight(ownTokenRecord, ownCouncilTokenRecord) } diff --git a/hooks/useVotingPlugins.ts b/hooks/useVotingPlugins.ts index ba00a02af6..a554e6d39b 100644 --- a/hooks/useVotingPlugins.ts +++ b/hooks/useVotingPlugins.ts @@ -9,6 +9,8 @@ import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { getMaxVoterWeightRecord } from '@solana/spl-governance' import { getNftMaxVoterWeightRecord } from 'NftVotePlugin/sdk/accounts' import { notify } from '@utils/notifications' +import { LOCALNET_STAKING_ADDRESS as PYTH_LOCALNET_STAKING_ADDRESS } from 'pyth-staking-api' + export const vsrPluginsPks: string[] = [ '4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo', ] @@ -17,6 +19,10 @@ export const nftPluginsPks: string[] = [ 'GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw', ] +export const pythPluginsPks: string[] = [ + PYTH_LOCALNET_STAKING_ADDRESS.toBase58(), +] + export function useVotingPlugins() { const { realm, config } = useRealm() const { @@ -24,6 +30,7 @@ export function useVotingPlugins() { handleSetVsrClient, handleSetNftClient, handleSetNftRegistrar, + handleSetPythClient, handleSetCurrentRealmVotingClient, } = useVotePluginsClientStore() const { @@ -37,6 +44,8 @@ export function useVotingPlugins() { const connected = useWalletStore((s) => s.connected) const vsrClient = useVotePluginsClientStore((s) => s.state.vsrClient) const nftClient = useVotePluginsClientStore((s) => s.state.nftClient) + const pythClient = useVotePluginsClientStore((s) => s.state.pythClient) + const currentClient = useVotePluginsClientStore( (s) => s.state.currentRealmVotingClient ) @@ -109,6 +118,7 @@ export function useVotingPlugins() { useEffect(() => { handleSetVsrClient(wallet, connection) handleSetNftClient(wallet, connection) + handleSetPythClient(wallet, connection) }, [connection.endpoint]) useEffect(() => { @@ -144,6 +154,22 @@ export function useVotingPlugins() { } } } + + const handlePythPlugin = () => { + if ( + pythClient && + currentPluginPk && + pythPluginsPks.includes(currentPluginPk.toBase58()) + ) { + if (connected) { + handleSetCurrentRealmVotingClient({ + client: pythClient, + realm, + walletPk: wallet?.publicKey, + }) + } + } + } if ( !currentClient || currentClient.realm?.pubkey.toBase58() !== realm?.pubkey.toBase58() || @@ -151,11 +177,13 @@ export function useVotingPlugins() { ) { handleNftplugin() handleVsrPlugin() + handlePythPlugin() } }, [ currentPluginPk?.toBase58(), vsrClient?.program.programId.toBase58(), nftClient?.program.programId.toBase58(), + pythClient?.program.programId.toBase58(), realm?.pubkey.toBase58(), connection.endpoint, connected, diff --git a/models/voteWeights.ts b/models/voteWeights.ts index 901fb698e6..f83b69016b 100644 --- a/models/voteWeights.ts +++ b/models/voteWeights.ts @@ -111,6 +111,86 @@ export class VoteRegistryVoterWeight implements VoterWeightInterface { } } +/// VoterWeight encapsulates logic to determine voter weights from token records (community or council) +export class PythVoterWeight implements VoterWeightInterface { + //TODO implement council + communityTokenRecord: ProgramAccount | undefined + councilTokenRecord: ProgramAccount | undefined + votingPower: BN + + constructor( + communityTokenRecord: ProgramAccount | undefined, + votingPower: BN + ) { + this.communityTokenRecord = communityTokenRecord + this.councilTokenRecord = undefined + this.votingPower = votingPower + } + + // Checks if the voter has any voting weight + hasAnyWeight() { + return !this.votingPower.isZero() + } + + // Returns first available tokenRecord + getTokenRecord() { + if (this.communityTokenRecord) { + return this.communityTokenRecord.pubkey + } + + throw new Error('Current wallet has no Token Owner Records') + } + + hasMinCommunityWeight(minCommunityWeight: BN) { + return ( + this.communityTokenRecord && this.votingPower.cmp(minCommunityWeight) >= 0 + ) + } + hasMinCouncilWeight() { + return false + } + + canCreateProposal(config: GovernanceConfig) { + return this.hasMinCommunityWeight(config.minCommunityTokensToCreateProposal) + } + canCreateGovernanceUsingCommunityTokens(realm: ProgramAccount) { + return this.hasMinCommunityWeight( + realm.account.config.minCommunityTokensToCreateGovernance + ) + } + canCreateGovernanceUsingCouncilTokens() { + return false + } + canCreateGovernance(realm: ProgramAccount) { + return ( + this.canCreateGovernanceUsingCommunityTokens(realm) || + this.canCreateGovernanceUsingCouncilTokens() + ) + } + hasMinAmountToVote(mintPk: PublicKey) { + const isCommunity = + this.communityTokenRecord?.account.governingTokenMint.toBase58() === + mintPk.toBase58() + const isCouncil = + this.councilTokenRecord?.account.governingTokenMint.toBase58() === + mintPk.toBase58() + if (isCouncil) { + return false + } + if (isCommunity) { + return !this.votingPower.isZero() + } + } + + getTokenRecordToCreateProposal(config: GovernanceConfig) { + // Prefer community token owner record as proposal owner + if (this.hasMinCommunityWeight(config.minCommunityTokensToCreateProposal)) { + return this.communityTokenRecord! + } + throw new Error('Not enough vote weight to create proposal') + } +} + export class VoteNftWeight implements VoterWeightInterface { //TODO implement council communityTokenRecord: ProgramAccount | undefined diff --git a/next.config.js b/next.config.js index d867e45733..1fc2458475 100644 --- a/next.config.js +++ b/next.config.js @@ -14,6 +14,7 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ module.exports = withBundleAnalyzer( withTM({ webpack: (config, { isServer }) => { + config.experiments = { asyncWebAssembly: true } config.module.rules.push({ test: /\.svg$/, use: ['@svgr/webpack'], diff --git a/package.json b/package.json index e3c06d0c9e..1a3f448ea1 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,8 @@ "@heroicons/react": "^1.0.1", "@marinade.finance/marinade-ts-sdk": "^2.0.9", "@metaplex-foundation/mpl-token-metadata": "^1.2.5", - "@next/bundle-analyzer": "^12.1.4", - "@mithraic-labs/serum-remote": "^0.0.1-rc.16", "@next/bundle-analyzer": "^12.1.5", + "@mithraic-labs/serum-remote": "^0.0.1-rc.16", "@nfteyez/sol-rayz": "^0.10.2", "@nivo/bar": "^0.79.1", "@nivo/core": "^0.79.0", @@ -66,6 +65,7 @@ "next-themes": "^0.1.1", "next-transpile-modules": "^8.0.0", "node-fetch": "^2.6.1", + "pyth-staking-api": "^1.1.25", "rc-slider": "^9.7.5", "react": "^18.1.0", "react-dom": "^18.0.0", diff --git a/pages/dao/[symbol]/index.tsx b/pages/dao/[symbol]/index.tsx index 55db244fae..349eb6b895 100644 --- a/pages/dao/[symbol]/index.tsx +++ b/pages/dao/[symbol]/index.tsx @@ -28,6 +28,7 @@ import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { NftVoterClient } from '@solana/governance-program-library' import { notify } from '@utils/notifications' import { sendSignedTransaction } from '@utils/send' +import { LOCALNET_REALM_ID as PYTH_LOCALNET_REALM_ID } from 'pyth-staking-api' const AccountsCompactWrapper = dynamic( () => import('@components/TreasuryAccount/AccountsCompactWrapper') @@ -482,7 +483,10 @@ const REALM = () => {
- + {realmInfo?.realmId.toBase58() === + PYTH_LOCALNET_REALM_ID.toBase58() ? null : ( + + )}
diff --git a/stores/useVotePluginsClientStore.tsx b/stores/useVotePluginsClientStore.tsx index 18d981aee3..8162022df5 100644 --- a/stores/useVotePluginsClientStore.tsx +++ b/stores/useVotePluginsClientStore.tsx @@ -9,6 +9,7 @@ import { ConnectionContext } from '@utils/connection' import { ProgramAccount, Realm } from '@solana/spl-governance' import { getNftRegistrarPDA } from 'NftVotePlugin/sdk/accounts' import { VotingClient, VotingClientProps } from '@utils/uiTypes/VotePlugin' +import { PythClient } from 'pyth-staking-api' import { PublicKey } from '@solana/web3.js' interface UseVotePluginsClientStore extends State { @@ -16,6 +17,7 @@ interface UseVotePluginsClientStore extends State { //diffrent plugins to choose because we will still have functions related only to one plugin vsrClient: VsrClient | undefined nftClient: NftVoterClient | undefined + pythClient: PythClient | undefined voteStakeRegistryRegistrar: Registrar | null nftMintRegistrar: any currentRealmVotingClient: VotingClient @@ -29,6 +31,10 @@ interface UseVotePluginsClientStore extends State { wallet: SignerWalletAdapter | undefined, connection: ConnectionContext ) => void + handleSetPythClient: ( + wallet: SignerWalletAdapter | undefined, + connection: ConnectionContext + ) => void handleSetVsrRegistrar: ( client: VsrClient, realm: ProgramAccount | undefined @@ -47,6 +53,7 @@ interface UseVotePluginsClientStore extends State { const defaultState = { vsrClient: undefined, nftClient: undefined, + pythClient: undefined, voteStakeRegistryRegistrar: null, voteStakeRegistryRegistrarPk: null, nftMintRegistrar: null, @@ -117,6 +124,30 @@ const useVotePluginsClientStore = create( s.state.nftMintRegistrar = existingRegistrar }) }, + handleSetPythClient: async (wallet, connection) => { + if ( + connection.cluster === 'localnet' || + connection.cluster === 'devnet' + ) { + const options = AnchorProvider.defaultOptions() + const provider = new AnchorProvider( + connection.current, + (wallet as unknown) as Wallet, + options + ) + try { + const pythClient = await PythClient.connect( + provider, + connection.cluster + ) + set((s) => { + s.state.pythClient = pythClient + }) + } catch (e) { + console.error(e) + } + } + }, handleSetCurrentRealmVotingClient: ({ client, realm, walletPk }) => { set((s) => { s.state.currentRealmVotingClient = new VotingClient({ diff --git a/utils/uiTypes/VotePlugin.ts b/utils/uiTypes/VotePlugin.ts index 4b428d9345..1bf30bacfe 100644 --- a/utils/uiTypes/VotePlugin.ts +++ b/utils/uiTypes/VotePlugin.ts @@ -15,6 +15,7 @@ import { getNftVoterWeightRecord, getNftMaxVoterWeightRecord, } from 'NftVotePlugin/sdk/accounts' +import { PythClient } from 'pyth-staking-api' import { getRegistrarPDA, getVoterPDA, @@ -30,7 +31,7 @@ type UpdateVoterWeightRecordTypes = | 'signOffProposal' export interface VotingClientProps { - client: VsrClient | NftVoterClient | undefined + client: VsrClient | NftVoterClient | PythClient | undefined realm: ProgramAccount | undefined walletPk: PublicKey | null | undefined } @@ -43,6 +44,7 @@ enum VotingClientType { NoClient, VsrClient, NftVoterClient, + PythClient, } class AccountData { @@ -67,7 +69,7 @@ interface ProgramAddresses { //Abstract for common functions that plugins will implement export class VotingClient { - client: VsrClient | NftVoterClient | undefined + client: VsrClient | NftVoterClient | PythClient | undefined realm: ProgramAccount | undefined walletPk: PublicKey | null | undefined votingNfts: NFTWithMeta[] @@ -88,11 +90,16 @@ export class VotingClient { this.clientType = VotingClientType.NftVoterClient this.noClient = false } + if (this.client instanceof PythClient) { + this.clientType = VotingClientType.PythClient + this.noClient = false + } } withUpdateVoterWeightRecord = async ( instructions: TransactionInstruction[], tokenOwnerRecord: ProgramAccount, - type: UpdateVoterWeightRecordTypes + type: UpdateVoterWeightRecordTypes, + voterWeightTarget?: PublicKey ): Promise => { if (this.noClient) { return @@ -165,6 +172,27 @@ export class VotingClient { instructions.push(updateVoterWeightRecordIx) return { voterWeightPk, maxVoterWeightRecord } } + if (this.client instanceof PythClient) { + const stakeAccount = await this.client!.stakeConnection.getMainAccount( + walletPk + ) + + let obj = {} + obj[type] = {} + const { + voterWeightAccount, + } = await this.client.stakeConnection.withUpdateVoterWeight( + instructions, + stakeAccount!, + obj, + voterWeightTarget + ) + + return { + voterWeightPk: voterWeightAccount, + maxVoterWeightRecord: undefined, + } + } } withCastPluginVote = async ( instructions: TransactionInstruction[], @@ -280,6 +308,15 @@ export class VotingClient { ) return props } + if (this.client instanceof PythClient) { + const props = await this.withUpdateVoterWeightRecord( + instructions, + tokeOwnerRecord, + 'castVote', + proposal.pubkey + ) + return props + } } withRelinquishVote = async ( instructions, diff --git a/yarn.lock b/yarn.lock index 902d33dc78..9afbcd2655 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1668,6 +1668,26 @@ 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.11.1": version "0.11.1" resolved "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz" @@ -1791,26 +1811,6 @@ 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/borsh@^0.2.2", "@project-serum/borsh@^0.2.3", "@project-serum/borsh@^0.2.4", "@project-serum/borsh@^0.2.5": version "0.2.5" resolved "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz" @@ -5000,7 +5000,7 @@ encodeurl@~1.0.2: resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -encoding@^0.1.12: +encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== @@ -10125,6 +10125,24 @@ purgecss@^4.0.3: postcss "^8.3.5" postcss-selector-parser "^6.0.6" +pyth-staking-api@^1.1.25: + version "1.1.25" + resolved "https://registry.yarnpkg.com/pyth-staking-api/-/pyth-staking-api-1.1.25.tgz#80b0cfae5e1347c390bbce342fde86f365f5ead8" + integrity sha512-NRXJdkY3ZkRtOUkh0Y+7ULnPhx9qa4OWPiyj3ZaCSlxX+MiJHFArKogWSo5yr1VKWeYHSMZbj41MtNIMtVIzBQ== + dependencies: + "@project-serum/anchor" "0.24.2" + "@solana/spl-governance" "^0.0.34" + "@solana/spl-token" "^0.1.8" + "@solana/web3.js" "^1.36.0" + encoding "^0.1.13" + pyth-staking-wasm "0.2.6" + typescript "^4.3.5" + +pyth-staking-wasm@0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/pyth-staking-wasm/-/pyth-staking-wasm-0.2.6.tgz#778a53583b06ff719b9e2f1028b5c03de0aee1a8" + integrity sha512-anUllRqnaYUyRtqkHJpOWTeSfyn20CgqsmUTOskpeK2gxK1xyK1d3fhnWBg2Ux/3OfNNblv3HjkAFIl/bNrPUA== + qrcode-terminal@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz" @@ -11984,6 +12002,11 @@ typescript@^4.2.4: resolved "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz" integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== +typescript@^4.3.5: + version "4.6.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" + integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== + typescript@^4.5.5, typescript@^4.6.3: version "4.6.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" From 8323949e80f2db7a3faf8be1c2d910fa39211e07 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 5 May 2022 03:36:26 +0900 Subject: [PATCH 2/5] fix treasury error when on localnet --- Strategies/store/marketStore.tsx | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Strategies/store/marketStore.tsx b/Strategies/store/marketStore.tsx index 8ac694b606..759abd8330 100644 --- a/Strategies/store/marketStore.tsx +++ b/Strategies/store/marketStore.tsx @@ -13,6 +13,7 @@ import { TokenInfo, } from '@blockworks-foundation/mango-client' import { ConnectionContext } from '@utils/connection' +import { Connection } from '@solana/web3.js' export interface MarketStore extends State { groupConfig?: GroupConfig @@ -30,6 +31,10 @@ export interface MarketStore extends State { const useMarketStore = create((set, _get) => ({ loadMarket: async (connection: ConnectionContext, cluster: string) => { const GROUP = cluster === 'devnet' ? 'devnet.2' : 'mainnet.1' + const mangoConnection = + cluster === 'localnet' + ? new Connection(Config.ids().cluster_urls.mainnet) + : connection.current const groupConfig = Config.ids().getGroupWithName(GROUP)! const DEFAULT_MARKET = 'SOL' const DEFAULT_MARKET_INDEX = getMarketIndexBySymbol( @@ -37,23 +42,20 @@ const useMarketStore = create((set, _get) => ({ DEFAULT_MARKET ) const marketConfig = groupConfig?.perpMarkets[DEFAULT_MARKET_INDEX] - const client = new MangoClient( - connection.current, - groupConfig.mangoProgramId - ) + const client = new MangoClient(mangoConnection, groupConfig.mangoProgramId) const group = await client.getMangoGroup(groupConfig.publicKey) const [perpMarket] = await Promise.all([ group.loadPerpMarket( - connection.current, + mangoConnection, marketConfig.marketIndex, marketConfig.baseDecimals, marketConfig.quoteDecimals ), - group.loadRootBanks(connection.current), + group.loadRootBanks(mangoConnection), ]) - const cache = await group.loadCache(connection.current) + const cache = await group.loadCache(mangoConnection) const indexPrice = group.getPriceUi(marketConfig.marketIndex, cache) set((s: MarketStore) => { s.groupConfig = groupConfig From bc841c325b8d0ce8975d0b8ff94107f151b2496b Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 5 May 2022 03:39:54 +0900 Subject: [PATCH 3/5] remove unused vars and refactor --- components/TokenBalance/TokenBalanceCard.tsx | 2 -- utils/uiTypes/VotePlugin.ts | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/components/TokenBalance/TokenBalanceCard.tsx b/components/TokenBalance/TokenBalanceCard.tsx index 09e922b385..3472bffb99 100644 --- a/components/TokenBalance/TokenBalanceCard.tsx +++ b/components/TokenBalance/TokenBalanceCard.tsx @@ -147,14 +147,12 @@ const TokenDeposit = ({ const wallet = useWalletStore((s) => s.current) const connected = useWalletStore((s) => s.connected) const connection = useWalletStore((s) => s.connection.current) - const cluster = useWalletStore((s) => s.connection.cluster) const { fetchWalletTokenAccounts, fetchRealm } = useWalletStore( (s) => s.actions ) const client = useVotePluginsClientStore( (s) => s.state.currentRealmVotingClient ) - const pythClient = useVotePluginsClientStore((s) => s.state.pythClient) const maxVoterWeight = useNftPluginStore((s) => s.state.maxVoteRecord)?.pubkey || undefined const { diff --git a/utils/uiTypes/VotePlugin.ts b/utils/uiTypes/VotePlugin.ts index 1bf30bacfe..9768def7fe 100644 --- a/utils/uiTypes/VotePlugin.ts +++ b/utils/uiTypes/VotePlugin.ts @@ -177,14 +177,12 @@ export class VotingClient { walletPk ) - let obj = {} - obj[type] = {} const { voterWeightAccount, } = await this.client.stakeConnection.withUpdateVoterWeight( instructions, stakeAccount!, - obj, + { [type]: {} }, voterWeightTarget ) From 4c40cbaf1a00bc9e247baaf4c2fc06a03007f629 Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 5 May 2022 11:20:04 +0900 Subject: [PATCH 4/5] enable experiments.layers for wasm --- next.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 1fc2458475..0f2bf79937 100644 --- a/next.config.js +++ b/next.config.js @@ -14,7 +14,7 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ module.exports = withBundleAnalyzer( withTM({ webpack: (config, { isServer }) => { - config.experiments = { asyncWebAssembly: true } + config.experiments = { asyncWebAssembly: true, layers: true } config.module.rules.push({ test: /\.svg$/, use: ['@svgr/webpack'], From 7ff987ccdcefb3ddf7d6a6f11a409eca8887d42f Mon Sep 17 00:00:00 2001 From: Daniel Chew Date: Thu, 5 May 2022 15:20:09 +0900 Subject: [PATCH 5/5] add devnet staking address to pyth plugin --- hooks/useRealm.tsx | 7 +++---- hooks/useVotingPlugins.ts | 13 +++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hooks/useRealm.tsx b/hooks/useRealm.tsx index 8412d77565..21dc69cf76 100644 --- a/hooks/useRealm.tsx +++ b/hooks/useRealm.tsx @@ -48,9 +48,7 @@ export default function useRealm() { const nftVotingPower = useNftPluginStore((s) => s.state.votingPower) const pythClient = useVotePluginsClientStore((s) => s.state.pythClient) - const [pythVoterWeight, setPythVoterWeight] = useState< - PythBalance | undefined - >(undefined) + const [pythVoterWeight, setPythVoterWeight] = useState() useEffect(() => { const getPythVoterWeight = async () => { @@ -147,12 +145,13 @@ export default function useRealm() { currentPluginPk && vsrPluginsPks.includes(currentPluginPk?.toBase58()) const isNftMode = currentPluginPk && nftPluginsPks.includes(currentPluginPk?.toBase58()) + const pythVotingPower = pythVoterWeight?.toBN() || new BN(0) const ownVoterWeight = getVoterWeight( currentPluginPk, ownTokenRecord, votingPower, nftVotingPower, - pythVoterWeight?.toBN() || new BN(0), + pythVotingPower, ownCouncilTokenRecord ) return { diff --git a/hooks/useVotingPlugins.ts b/hooks/useVotingPlugins.ts index e933397a8f..054bdb0245 100644 --- a/hooks/useVotingPlugins.ts +++ b/hooks/useVotingPlugins.ts @@ -9,7 +9,10 @@ import useVotePluginsClientStore from 'stores/useVotePluginsClientStore' import { getMaxVoterWeightRecord } from '@solana/spl-governance' import { getNftMaxVoterWeightRecord } from 'NftVotePlugin/sdk/accounts' import { notify } from '@utils/notifications' -import { LOCALNET_STAKING_ADDRESS as PYTH_LOCALNET_STAKING_ADDRESS } from 'pyth-staking-api' +import { + LOCALNET_STAKING_ADDRESS as PYTH_LOCALNET_STAKING_ADDRESS, + DEVNET_STAKING_ADDRESS as PYTH_DEVNET_STAKING_ADDRESS, +} from 'pyth-staking-api' export const vsrPluginsPks: string[] = [ '4Q6WW2ouZ6V3iaNm56MTd5n2tnTm4C5fiH8miFHnAFHo', @@ -21,6 +24,7 @@ export const nftPluginsPks: string[] = [ export const pythPluginsPks: string[] = [ PYTH_LOCALNET_STAKING_ADDRESS.toBase58(), + PYTH_DEVNET_STAKING_ADDRESS.toBase58(), ] export function useVotingPlugins() { @@ -33,11 +37,8 @@ export function useVotingPlugins() { handleSetPythClient, handleSetCurrentRealmVotingClient, } = useVotePluginsClientStore() - const { - setVotingNfts, - setMaxVoterWeight, - setIsLoadingNfts, - } = useNftPluginStore() + const { setVotingNfts, setMaxVoterWeight, setIsLoadingNfts } = + useNftPluginStore() const wallet = useWalletStore((s) => s.current) const connection = useWalletStore((s) => s.connection)