Skip to content

Commit

Permalink
small tweaks (solana-labs#1610)
Browse files Browse the repository at this point in the history
  • Loading branch information
bryzettler authored May 15, 2023
1 parent 6ab6e2b commit 8e46623
Show file tree
Hide file tree
Showing 22 changed files with 443 additions and 232 deletions.
178 changes: 178 additions & 0 deletions HeliumVotePlugin/components/ClaimUnreleasedPositions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import React, { useEffect, useState } from 'react'
import useRealm from '@hooks/useRealm'
import useWalletStore from 'stores/useWalletStore'
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,
positionKey,
voterWeightRecordKey,
} from '@helium/voter-stake-registry-sdk'
import {
sendTransactionsV3,
SequenceType,
txBatchesToInstructionSetWithSigners,
} from '@utils/sendTransactions'
import { ProposalState } from '@solana/spl-governance'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'
import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/tokenOwner'

const NFT_SOL_BALANCE = 0.0014616

const ClaimUnreleasedPositions = ({
inAccountDetails,
}: {
inAccountDetails?: boolean
}) => {
const wallet = useWalletOnePointOh()
const [isLoading, setIsLoading] = useState(false)
const { current: connection } = useWalletStore((s) => s.connection)
const [ownVoteRecords, setOwnVoteRecords] = useState<any[]>([])
const [solToBeClaimed, setSolToBeClaimed] = useState(0)
const { realm } = useWalletStore((s) => s.selectedRealm)
const votingPlugin = useVotePluginsClientStore(
(s) => s.state.currentRealmVotingClient
)

const { proposals } = useRealm()
const { data: tokenOwnerRecord } = useAddressQuery_CommunityTokenOwner()
const isHeliumVsr = votingPlugin.client instanceof HeliumVsrClient

const releasePositions = async () => {
if (!wallet?.publicKey) throw new Error('no wallet')
if (!realm) throw new Error()
if (!tokenOwnerRecord) throw new Error()

setIsLoading(true)
const instructions: TransactionInstruction[] = []
const [registrar] = registrarKey(
realm.pubkey,
realm.account.communityMint,
votingPlugin.client!.program.programId
)

const [voterWeightPk] = voterWeightRecordKey(
registrar,
wallet.publicKey,
votingPlugin.client!.program.programId
)

const voteRecords = ownVoteRecords
for (const i of voteRecords) {
const proposal = proposals[i.account.proposal.toBase58()]
const [posKey] = positionKey(
i.account.nftMint,
votingPlugin.client!.program.programId
)
if (proposal.account.state === ProposalState.Voting) {
// ignore this one as it's still in voting
continue
}

const relinquishVoteIx = await (votingPlugin.client as HeliumVsrClient).program.methods
.relinquishVoteV0()
.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 },
{ pubkey: posKey, isSigner: false, isWritable: true },
])
.instruction()
instructions.push(relinquishVoteIx)
}
try {
const insertChunks = chunks(instructions, 10).map((txBatch, batchIdx) => {
return {
instructionsSet: txBatchesToInstructionSetWithSigners(
txBatch,
[],
batchIdx
),
sequenceType: SequenceType.Parallel,
}
})
await sendTransactionsV3({
connection,
wallet: wallet!,
transactionInstructions: insertChunks,
})
setIsLoading(false)
getVoteRecords()
} catch (e) {
setIsLoading(false)
console.log(e)
}
}
const getVoteRecords = async () => {
const currentClient = votingPlugin.client as HeliumVsrClient
const voteRecords =
(await currentClient.program.account['nftVoteRecord']?.all([
{
memcmp: {
offset: 72,
bytes: wallet!.publicKey!.toBase58(),
},
},
])) || []

const voteRecordsFiltered = voteRecords.filter(
(x) =>
proposals[x.account.proposal.toBase58()] &&
proposals[
x.account.proposal.toBase58()
].account.governingTokenMint.toBase58() ===
realm?.account.communityMint.toBase58() &&
proposals[x.account.proposal.toBase58()].account.state !==
ProposalState.Voting
)
setOwnVoteRecords(voteRecordsFiltered)
setSolToBeClaimed(voteRecordsFiltered.length * NFT_SOL_BALANCE)
}

useEffect(() => {
if (wallet?.publicKey && isHeliumVsr && votingPlugin.client) {
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()])

if (isHeliumVsr) {
return (
<>
{((!inAccountDetails && solToBeClaimed > 0) ||
(inAccountDetails && solToBeClaimed != 0)) && (
<div className="w-full">
<div className="flex flex-col w-full gap-2 items-center">
<div className="mb-2 text-xs text-white/50 max-w-[300px] text-center">
Relinquish your old votes and claim {solToBeClaimed.toFixed(4)}{' '}
SOL from past proposal voting costs.
</div>
<SecondaryButton
isLoading={isLoading}
onClick={() => releasePositions()}
className="w-1/2 max-w-[200px]"
>
Relinquish
</SecondaryButton>
</div>
</div>
)}
</>
)
} else {
return null
}
}

export default ClaimUnreleasedPositions
49 changes: 28 additions & 21 deletions HeliumVotePlugin/components/LockTokensAccount.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useAsync } from 'react-async-hook'
import { BN } from '@coral-xyz/anchor'
import {
Expand Down Expand Up @@ -96,6 +96,21 @@ export const LockTokensAccount: React.FC<{
s.getPositions,
])

const sortedPositions = useMemo(
() =>
positions.sort((a, b) => {
if (a.hasGenesisMultiplier || b.hasGenesisMultiplier) {
if (b.hasGenesisMultiplier) {
return a.amountDepositedNative.gt(b.amountDepositedNative) ? 0 : -1
}
return -1
}

return a.amountDepositedNative.gt(b.amountDepositedNative) ? -1 : 0
}),
[positions]
)

useEffect(() => {
if (subDaosError) {
notify({
Expand Down Expand Up @@ -320,26 +335,18 @@ export const LockTokensAccount: React.FC<{
}`}
>
{!loading &&
positions
.sort((a, b) =>
a.hasGenesisMultiplier
? b.hasGenesisMultiplier
? 0
: -1
: 1
)
.map((pos, idx) => (
<PositionCard
key={idx}
position={pos}
subDaos={subDaos}
tokenOwnerRecordPk={
tokenRecords[wallet!.publicKey!.toBase58()]?.pubkey ||
null
}
isOwner={isSameWallet}
/>
))}
sortedPositions.map((pos, idx) => (
<PositionCard
key={idx}
position={pos}
subDaos={subDaos}
tokenOwnerRecordPk={
tokenRecords[wallet!.publicKey!.toBase58()]?.pubkey ||
null
}
isOwner={isSameWallet}
/>
))}
{isSameWallet && (
<div className="border border-fgd-4 flex flex-col items-center justify-center p-6 rounded-lg">
<LightningBoltIcon className="h-8 mb-2 text-primary-light w-8" />
Expand Down
30 changes: 3 additions & 27 deletions HeliumVotePlugin/components/VotingPowerCard.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
import React, { useEffect, useState } from 'react'
import Link from 'next/link'
import { BN } from '@coral-xyz/anchor'
import { GoverningTokenRole } from '@solana/spl-governance'
import useRealm from '@hooks/useRealm'
import { fmtMintAmount } from '@tools/sdk/units'
import { getMintMetadata } from '@components/instructions/programs/splToken'
import useQueryContext from '@hooks/useQueryContext'
import { ChevronRightIcon } from '@heroicons/react/solid'
import InlineNotification from '@components/InlineNotification'
import DelegateTokenBalanceCard from '@components/TokenBalance/DelegateTokenBalanceCard'
import { TokenDeposit } from '@components/TokenBalance/TokenBalanceCard'
import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore'
import { MintInfo } from '@solana/spl-token'
import { VotingPowerBox } from './VotingPowerBox'
import { useAddressQuery_CommunityTokenOwner } from '@hooks/queries/addresses/tokenOwner'
import useWalletOnePointOh from '@hooks/useWalletOnePointOh'

export const VotingPowerCard: React.FC<{
inAccountDetails?: boolean
}> = ({ inAccountDetails }) => {
const { fmtUrlWithCluster } = useQueryContext()
const loading = useHeliumVsrStore((s) => s.state.isLoading)
const [hasGovPower, setHasGovPower] = useState(false)
const { councilMint, ownTokenRecord, mint, symbol } = useRealm()
const { councilMint, ownTokenRecord, mint } = useRealm()
const wallet = useWalletOnePointOh()
const connected = !!wallet?.connected

const councilDepositVisible = !!councilMint
const { data: tokenOwnerRecordPk } = useAddressQuery_CommunityTokenOwner()

const isLoading = !mint || !councilMint
const isLoading = !mint || !councilMint || loading
const isSameWallet =
(connected && !ownTokenRecord) ||
(connected &&
Expand All @@ -37,25 +32,6 @@ export const VotingPowerCard: React.FC<{

return (
<>
<div className="flex items-center justify-between">
<h3 className="mb-0">My governance power</h3>
<Link
href={fmtUrlWithCluster(
`/dao/${symbol}/account/${tokenOwnerRecordPk}`
)}
>
<a
className={`default-transition flex items-center text-fgd-2 text-sm transition-all hover:text-fgd-3 ${
!connected || !tokenOwnerRecordPk
? 'opacity-50 pointer-events-none'
: ''
}`}
>
View
<ChevronRightIcon className="flex-shrink-0 h-6 w-6" />
</a>
</Link>
</div>
{!isLoading ? (
<>
{!hasGovPower && !inAccountDetails && connected && (
Expand Down
4 changes: 3 additions & 1 deletion HeliumVotePlugin/hooks/useTransferPosition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export const useTransferPosition = () => {
!mint ||
!wallet ||
!client ||
!(client instanceof HeliumVsrClient)
!(client instanceof HeliumVsrClient) ||
sourcePosition.numActiveVotes > 0 ||
targetPosition.numActiveVotes > 0

const idl = await Program.fetchIdl(programId, provider)
const hsdProgram = await init(provider as any, programId, idl)
Expand Down
2 changes: 1 addition & 1 deletion HeliumVotePlugin/sdk/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export type VotingMintConfig = IdlTypes<HeliumVoterStakeRegistry>['VotingMintCon
type RegistrarV0 = IdlAccounts<HeliumVoterStakeRegistry>['registrar']
export type Lockup = IdlTypes<HeliumVoterStakeRegistry>['Lockup']
export type PositionV0 = IdlAccounts<HeliumVoterStakeRegistry>['positionV0']
export type DelegatedPostionV0 = IdlAccounts<HeliumSubDaos>['delegatedPositionV0']
export type DelegatedPositionV0 = IdlAccounts<HeliumSubDaos>['delegatedPositionV0']
export interface Registrar extends RegistrarV0 {
votingMints: VotingMintConfig[]
}
Expand Down
4 changes: 2 additions & 2 deletions HeliumVotePlugin/utils/getPositions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
Registrar,
PositionWithMeta,
PositionV0,
DelegatedPostionV0,
DelegatedPositionV0,
} from '../sdk/types'
import { chunks } from '@utils/helpers'
import { HNT_MINT } from '@helium/spl-utils'
Expand Down Expand Up @@ -94,7 +94,7 @@ export const getPositions = async (
? (hsdProgram.coder.accounts.decode(
'DelegatedPositionV0',
delegatedPos.data
) as DelegatedPostionV0)
) as DelegatedPositionV0)
: null
)
})()
Expand Down
8 changes: 5 additions & 3 deletions actions/castVote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,9 +200,11 @@ export async function castVote(
wallet,
transactionInstructions: ixsChunks,
callbacks: {
afterFirstBatchSign: () => (ixsChunks.length > 2 ? null : null),
afterAllTxConfirmed: () =>
runAfterConfirmation ? runAfterConfirmation() : null,
afterAllTxConfirmed: () => {
if (runAfterConfirmation) {
runAfterConfirmation()
}
},
},
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useState, useEffect } from 'react'
import classNames from 'classnames'
import { BigNumber } from 'bignumber.js'
import useRealm from '@hooks/useRealm'
import useHeliumVsrStore from 'HeliumVotePlugin/hooks/useHeliumVsrStore'
Expand Down Expand Up @@ -88,9 +87,10 @@ export default function LockedCommunityNFTRecordVotingPower(props: Props) {

if (isLoading) {
return (
<div
className={classNames(props.className, 'rounded-md bg-bkg-1 h-[76px]')}
/>
<>
<div className="animate-pulse bg-bkg-3 h-12 mb-4 rounded-lg" />
<div className="animate-pulse bg-bkg-3 h-10 rounded-lg" />
</>
)
}

Expand Down
Loading

0 comments on commit 8e46623

Please sign in to comment.