From f13b63b0b288738ddc42ce1b869e6081b2ccadd7 Mon Sep 17 00:00:00 2001 From: "Sebastian.Bor" Date: Fri, 2 Apr 2021 10:46:28 +0100 Subject: [PATCH] feat: add quick vote --- .../src/actions/depositSourceTokens.ts | 18 ++- .../src/actions/depositSourceTokensAndVote.ts | 52 ++++++++ .../src/components/Proposal/QuickVote.tsx | 118 ++++++++++++++++++ packages/proposals/src/constants/labels.ts | 1 + .../proposals/src/views/proposal/index.tsx | 6 + 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 packages/proposals/src/actions/depositSourceTokensAndVote.ts create mode 100644 packages/proposals/src/components/Proposal/QuickVote.tsx diff --git a/packages/proposals/src/actions/depositSourceTokens.ts b/packages/proposals/src/actions/depositSourceTokens.ts index 7bda08b..09a8fe8 100644 --- a/packages/proposals/src/actions/depositSourceTokens.ts +++ b/packages/proposals/src/actions/depositSourceTokens.ts @@ -13,10 +13,12 @@ import { } from '@oyster/common'; import { TimelockSet } from '../models/timelock'; + import { AccountLayout } from '@solana/spl-token'; import { depositSourceTokensInstruction } from '../models/depositSourceTokens'; import { LABELS } from '../constants'; import { createEmptyGovernanceVotingRecordInstruction } from '../models/createEmptyGovernanceVotingRecord'; + const { createTokenAccount } = actions; const { sendTransaction } = contexts.Connection; const { notify } = utils; @@ -31,7 +33,11 @@ export const depositSourceTokens = async ( existingNoVoteAccount: PublicKey | undefined, sourceAccount: PublicKey, votingTokenAmount: number, -) => { +): Promise<{ + voteAccount: PublicKey; + yesVoteAccount: PublicKey; + noVoteAccount: PublicKey; +}> => { const PROGRAM_IDS = utils.programIds(); let signers: Account[] = []; @@ -74,7 +80,7 @@ export const depositSourceTokens = async ( } if (!existingYesVoteAccount) { - createTokenAccount( + existingYesVoteAccount = createTokenAccount( instructions, wallet.publicKey, accountRentExempt, @@ -85,7 +91,7 @@ export const depositSourceTokens = async ( } if (!existingNoVoteAccount) { - createTokenAccount( + existingNoVoteAccount = createTokenAccount( instructions, wallet.publicKey, accountRentExempt, @@ -148,4 +154,10 @@ export const depositSourceTokens = async ( console.error(ex); throw new Error(); } + + return { + voteAccount: existingVoteAccount, + yesVoteAccount: existingYesVoteAccount, + noVoteAccount: existingNoVoteAccount, + }; }; diff --git a/packages/proposals/src/actions/depositSourceTokensAndVote.ts b/packages/proposals/src/actions/depositSourceTokensAndVote.ts new file mode 100644 index 0000000..b675b49 --- /dev/null +++ b/packages/proposals/src/actions/depositSourceTokensAndVote.ts @@ -0,0 +1,52 @@ +import { Connection, PublicKey } from '@solana/web3.js'; +import { ParsedAccount } from '@oyster/common'; + +import { TimelockConfig, TimelockSet, TimelockState } from '../models/timelock'; + +import { vote } from './vote'; +import { depositSourceTokens } from './depositSourceTokens'; + +export const depositSourceTokensAndVote = async ( + connection: Connection, + wallet: any, + proposal: ParsedAccount, + existingVoteAccount: PublicKey | undefined, + existingYesVoteAccount: PublicKey | undefined, + existingNoVoteAccount: PublicKey | undefined, + sourceAccount: PublicKey, + timelockConfig: ParsedAccount, + state: ParsedAccount, + yesVotingTokenAmount: number, + noVotingTokenAmount: number, +) => { + const votingTokenAmount = + yesVotingTokenAmount > 0 ? yesVotingTokenAmount : noVotingTokenAmount; + + const { + voteAccount, + yesVoteAccount, + noVoteAccount, + } = await depositSourceTokens( + connection, + wallet, + proposal, + existingVoteAccount, + existingYesVoteAccount, + existingNoVoteAccount, + sourceAccount, + votingTokenAmount, + ); + + await vote( + connection, + wallet, + proposal, + timelockConfig, + state, + voteAccount, + yesVoteAccount, + noVoteAccount, + yesVotingTokenAmount, + noVotingTokenAmount, + ); +}; diff --git a/packages/proposals/src/components/Proposal/QuickVote.tsx b/packages/proposals/src/components/Proposal/QuickVote.tsx new file mode 100644 index 0000000..16c1e74 --- /dev/null +++ b/packages/proposals/src/components/Proposal/QuickVote.tsx @@ -0,0 +1,118 @@ +import { ParsedAccount } from '@oyster/common'; +import { Button, Col, Modal, Row, Switch } from 'antd'; +import React, { useState } from 'react'; +import { + TimelockConfig, + TimelockSet, + TimelockState, + TimelockStateStatus, + VotingEntryRule, +} from '../../models/timelock'; +import { LABELS } from '../../constants'; +import { depositSourceTokensAndVote } from '../../actions/depositSourceTokensAndVote'; +import { contexts, hooks } from '@oyster/common'; +import { + CheckOutlined, + CloseOutlined, + ExclamationCircleOutlined, +} from '@ant-design/icons'; + +const { useWallet } = contexts.Wallet; +const { useConnection } = contexts.Connection; +const { useAccountByMint } = hooks; + +const { cache } = contexts.Accounts; + +const { confirm } = Modal; +export function QuickVote({ + proposal, + state, + timelockConfig, +}: { + proposal: ParsedAccount; + state: ParsedAccount; + timelockConfig: ParsedAccount; +}) { + const wallet = useWallet(); + const connection = useConnection(); + + const voteAccount = useAccountByMint(proposal.info.votingMint); + const yesVoteAccount = useAccountByMint(proposal.info.yesVotingMint); + const noVoteAccount = useAccountByMint(proposal.info.noVotingMint); + + const userTokenAccount = useAccountByMint(proposal.info.sourceMint); + const alreadyHaveTokens = + (voteAccount && voteAccount.info.amount.toNumber() > 0) || + (yesVoteAccount && yesVoteAccount.info.amount.toNumber() > 0) || + (noVoteAccount && noVoteAccount.info.amount.toNumber() > 0); + + const [mode, setMode] = useState(true); + + const eligibleToView = + timelockConfig.info.votingEntryRule == VotingEntryRule.Anytime && + [TimelockStateStatus.Draft, TimelockStateStatus.Voting].includes( + state.info.status, + ); + + return eligibleToView ? ( + + ) : null; +} diff --git a/packages/proposals/src/constants/labels.ts b/packages/proposals/src/constants/labels.ts index b87ffd8..e03fe79 100644 --- a/packages/proposals/src/constants/labels.ts +++ b/packages/proposals/src/constants/labels.ts @@ -69,6 +69,7 @@ export const LABELS = { WITHDRAWING_VOTING_TOKENS: 'Refunding voting tokens as Source Tokens', TOKENS_WITHDRAWN: 'Voting tokens refunded as Source Tokens', REGISTER_TO_VOTE: 'Register to Vote', + QUICK_VOTE: 'Quick Vote', CONFIRM: 'Confirm', CANCEL: 'Cancel', ADD_MORE_VOTES: 'Add More Votes', diff --git a/packages/proposals/src/views/proposal/index.tsx b/packages/proposals/src/views/proposal/index.tsx index b79d379..4906e99 100644 --- a/packages/proposals/src/views/proposal/index.tsx +++ b/packages/proposals/src/views/proposal/index.tsx @@ -25,6 +25,7 @@ import AddSigners from '../../components/Proposal/AddSigners'; import MintSourceTokens from '../../components/Proposal/MintSourceTokens'; import { Vote } from '../../components/Proposal/Vote'; import { RegisterToVote } from '../../components/Proposal/RegisterToVote'; +import { QuickVote } from '../../components/Proposal/QuickVote'; import { WithdrawTokens } from '../../components/Proposal/WithdrawTokens'; import './style.less'; import { getGovernanceVotingRecords } from '../../utils/lookups'; @@ -306,6 +307,11 @@ function InnerProposalView({ proposal={proposal} state={timelockState} /> +