diff --git a/packages/proposals/src/actions/depositSourceTokens.ts b/packages/proposals/src/actions/depositSourceTokens.ts deleted file mode 100644 index 09a8fe8..0000000 --- a/packages/proposals/src/actions/depositSourceTokens.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { - Account, - Connection, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; -import { - contexts, - utils, - models, - ParsedAccount, - actions, -} 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; -const { approve } = models; - -export const depositSourceTokens = async ( - connection: Connection, - wallet: any, - proposal: ParsedAccount, - existingVoteAccount: PublicKey | undefined, - existingYesVoteAccount: PublicKey | undefined, - existingNoVoteAccount: PublicKey | undefined, - sourceAccount: PublicKey, - votingTokenAmount: number, -): Promise<{ - voteAccount: PublicKey; - yesVoteAccount: PublicKey; - noVoteAccount: PublicKey; -}> => { - const PROGRAM_IDS = utils.programIds(); - - let signers: Account[] = []; - let instructions: TransactionInstruction[] = []; - - const accountRentExempt = await connection.getMinimumBalanceForRentExemption( - AccountLayout.span, - ); - - let needToCreateGovAccountToo = !existingVoteAccount; - if (!existingVoteAccount) { - existingVoteAccount = createTokenAccount( - instructions, - wallet.publicKey, - accountRentExempt, - proposal.info.votingMint, - wallet.publicKey, - signers, - ); - } - - const [governanceVotingRecord] = await PublicKey.findProgramAddress( - [ - PROGRAM_IDS.timelock.programAccountId.toBuffer(), - proposal.pubkey.toBuffer(), - existingVoteAccount.toBuffer(), - ], - PROGRAM_IDS.timelock.programId, - ); - - if (needToCreateGovAccountToo) { - instructions.push( - createEmptyGovernanceVotingRecordInstruction( - governanceVotingRecord, - proposal.pubkey, - existingVoteAccount, - wallet.publicKey, - ), - ); - } - - if (!existingYesVoteAccount) { - existingYesVoteAccount = createTokenAccount( - instructions, - wallet.publicKey, - accountRentExempt, - proposal.info.yesVotingMint, - wallet.publicKey, - signers, - ); - } - - if (!existingNoVoteAccount) { - existingNoVoteAccount = createTokenAccount( - instructions, - wallet.publicKey, - accountRentExempt, - proposal.info.noVotingMint, - wallet.publicKey, - signers, - ); - } - - const [mintAuthority] = await PublicKey.findProgramAddress( - [PROGRAM_IDS.timelock.programAccountId.toBuffer()], - PROGRAM_IDS.timelock.programId, - ); - - const transferAuthority = approve( - instructions, - [], - sourceAccount, - wallet.publicKey, - votingTokenAmount, - ); - - signers.push(transferAuthority); - - instructions.push( - depositSourceTokensInstruction( - governanceVotingRecord, - existingVoteAccount, - sourceAccount, - proposal.info.sourceHolding, - proposal.info.votingMint, - proposal.pubkey, - transferAuthority.publicKey, - mintAuthority, - votingTokenAmount, - ), - ); - - notify({ - message: LABELS.ADDING_VOTES_TO_VOTER, - description: LABELS.PLEASE_WAIT, - type: 'warn', - }); - - try { - let tx = await sendTransaction( - connection, - wallet, - instructions, - signers, - true, - ); - - notify({ - message: LABELS.VOTES_ADDED, - type: 'success', - description: LABELS.TRANSACTION + ` ${tx}`, - }); - } catch (ex) { - 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 index b675b49..41309ab 100644 --- a/packages/proposals/src/actions/depositSourceTokensAndVote.ts +++ b/packages/proposals/src/actions/depositSourceTokensAndVote.ts @@ -1,10 +1,31 @@ -import { Connection, PublicKey } from '@solana/web3.js'; -import { ParsedAccount } from '@oyster/common'; +import { + Account, + Connection, + PublicKey, + TransactionInstruction, +} from '@solana/web3.js'; +import { + contexts, + utils, + models, + ParsedAccount, + actions, +} from '@oyster/common'; import { TimelockConfig, TimelockSet, TimelockState } from '../models/timelock'; -import { vote } from './vote'; -import { depositSourceTokens } from './depositSourceTokens'; +import { AccountLayout } from '@solana/spl-token'; + +import { LABELS } from '../constants'; + +import { depositSourceTokensInstruction } from '../models/depositSourceTokens'; +import { createEmptyGovernanceVotingRecordInstruction } from '../models/createEmptyGovernanceVotingRecord'; +import { voteInstruction } from '../models/vote'; + +const { createTokenAccount } = actions; +const { sendTransactions } = contexts.Connection; +const { notify } = utils; +const { approve } = models; export const depositSourceTokensAndVote = async ( connection: Connection, @@ -22,31 +43,156 @@ export const depositSourceTokensAndVote = async ( const votingTokenAmount = yesVotingTokenAmount > 0 ? yesVotingTokenAmount : noVotingTokenAmount; - const { - voteAccount, - yesVoteAccount, - noVoteAccount, - } = await depositSourceTokens( - connection, - wallet, - proposal, - existingVoteAccount, - existingYesVoteAccount, - existingNoVoteAccount, + const PROGRAM_IDS = utils.programIds(); + + let depositSigners: Account[] = []; + let depositInstructions: TransactionInstruction[] = []; + + const accountRentExempt = await connection.getMinimumBalanceForRentExemption( + AccountLayout.span, + ); + + let needToCreateGovAccountToo = !existingVoteAccount; + if (!existingVoteAccount) { + existingVoteAccount = createTokenAccount( + depositInstructions, + wallet.publicKey, + accountRentExempt, + proposal.info.votingMint, + wallet.publicKey, + depositSigners, + ); + } + + const [governanceVotingRecord] = await PublicKey.findProgramAddress( + [ + PROGRAM_IDS.timelock.programAccountId.toBuffer(), + proposal.pubkey.toBuffer(), + existingVoteAccount.toBuffer(), + ], + PROGRAM_IDS.timelock.programId, + ); + + if (needToCreateGovAccountToo) { + depositInstructions.push( + createEmptyGovernanceVotingRecordInstruction( + governanceVotingRecord, + proposal.pubkey, + existingVoteAccount, + wallet.publicKey, + ), + ); + } + + if (!existingYesVoteAccount) { + existingYesVoteAccount = createTokenAccount( + depositInstructions, + wallet.publicKey, + accountRentExempt, + proposal.info.yesVotingMint, + wallet.publicKey, + depositSigners, + ); + } + + if (!existingNoVoteAccount) { + existingNoVoteAccount = createTokenAccount( + depositInstructions, + wallet.publicKey, + accountRentExempt, + proposal.info.noVotingMint, + wallet.publicKey, + depositSigners, + ); + } + + const [mintAuthority] = await PublicKey.findProgramAddress( + [PROGRAM_IDS.timelock.programAccountId.toBuffer()], + PROGRAM_IDS.timelock.programId, + ); + + const depositAuthority = approve( + depositInstructions, + [], sourceAccount, + wallet.publicKey, votingTokenAmount, ); - await vote( - connection, - wallet, - proposal, - timelockConfig, - state, - voteAccount, - yesVoteAccount, - noVoteAccount, - yesVotingTokenAmount, - noVotingTokenAmount, + depositSigners.push(depositAuthority); + + depositInstructions.push( + depositSourceTokensInstruction( + governanceVotingRecord, + existingVoteAccount, + sourceAccount, + proposal.info.sourceHolding, + proposal.info.votingMint, + proposal.pubkey, + depositAuthority.publicKey, + mintAuthority, + votingTokenAmount, + ), ); + + let voteSigners: Account[] = []; + let voteInstructions: TransactionInstruction[] = []; + + const voteAuthority = approve( + voteInstructions, + [], + existingVoteAccount, + wallet.publicKey, + yesVotingTokenAmount + noVotingTokenAmount, + ); + + voteSigners.push(voteAuthority); + + voteInstructions.push( + voteInstruction( + governanceVotingRecord, + state.pubkey, + existingVoteAccount, + existingYesVoteAccount, + existingNoVoteAccount, + proposal.info.votingMint, + proposal.info.yesVotingMint, + proposal.info.noVotingMint, + proposal.info.sourceMint, + proposal.pubkey, + timelockConfig.pubkey, + voteAuthority.publicKey, + mintAuthority, + yesVotingTokenAmount, + noVotingTokenAmount, + ), + ); + + notify({ + message: LABELS.VOTING_FOR_PROPOSAL, + description: LABELS.PLEASE_WAIT, + type: 'warn', + }); + + try { + await sendTransactions( + connection, + wallet, + [depositInstructions, voteInstructions], + [depositSigners, voteSigners], + true, + ); + + notify({ + message: LABELS.PROPOSAL_VOTED, + type: 'success', + description: + yesVotingTokenAmount > 0 + ? `${yesVotingTokenAmount} ${LABELS.TOKENS_VOTED_FOR_THE_PROPOSAL}.` + : `${noVotingTokenAmount} ${LABELS.TOKENS_VOTED_AGAINST_THE_PROPOSAL}.`, + }); + } catch (ex) { + console.error(ex); + throw new Error(); + } }; diff --git a/packages/proposals/src/actions/vote.ts b/packages/proposals/src/actions/vote.ts deleted file mode 100644 index 0a02074..0000000 --- a/packages/proposals/src/actions/vote.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - Account, - Connection, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; -import { - contexts, - utils, - models, - ParsedAccount, - actions, -} from '@oyster/common'; - -import { TimelockConfig, TimelockSet, TimelockState } from '../models/timelock'; -import { LABELS } from '../constants'; -import { voteInstruction } from '../models/vote'; -const { createTokenAccount } = actions; -const { sendTransaction } = contexts.Connection; -const { notify } = utils; -const { approve } = models; - -export const vote = async ( - connection: Connection, - wallet: any, - proposal: ParsedAccount, - timelockConfig: ParsedAccount, - state: ParsedAccount, - votingAccount: PublicKey, - yesVotingAccount: PublicKey, - noVotingAccount: PublicKey, - yesVotingTokenAmount: number, - noVotingTokenAmount: number, -) => { - const PROGRAM_IDS = utils.programIds(); - - let signers: Account[] = []; - let instructions: TransactionInstruction[] = []; - - const [mintAuthority] = await PublicKey.findProgramAddress( - [PROGRAM_IDS.timelock.programAccountId.toBuffer()], - PROGRAM_IDS.timelock.programId, - ); - - const [governanceVotingRecord] = await PublicKey.findProgramAddress( - [ - PROGRAM_IDS.timelock.programAccountId.toBuffer(), - proposal.pubkey.toBuffer(), - votingAccount.toBuffer(), - ], - PROGRAM_IDS.timelock.programId, - ); - - const transferAuthority = approve( - instructions, - [], - votingAccount, - wallet.publicKey, - yesVotingTokenAmount + noVotingTokenAmount, - ); - - signers.push(transferAuthority); - - instructions.push( - voteInstruction( - governanceVotingRecord, - state.pubkey, - votingAccount, - yesVotingAccount, - noVotingAccount, - proposal.info.votingMint, - proposal.info.yesVotingMint, - proposal.info.noVotingMint, - proposal.info.sourceMint, - proposal.pubkey, - timelockConfig.pubkey, - transferAuthority.publicKey, - mintAuthority, - yesVotingTokenAmount, - noVotingTokenAmount, - ), - ); - - notify({ - message: LABELS.BURNING_VOTES, - description: LABELS.PLEASE_WAIT, - type: 'warn', - }); - - try { - let tx = await sendTransaction( - connection, - wallet, - instructions, - signers, - true, - ); - - notify({ - message: LABELS.VOTES_BURNED, - type: 'success', - description: LABELS.TRANSACTION + ` ${tx}`, - }); - } catch (ex) { - console.error(ex); - throw new Error(); - } -}; diff --git a/packages/proposals/src/components/Proposal/Vote.tsx b/packages/proposals/src/components/Proposal/Vote.tsx index df1273f..868725e 100644 --- a/packages/proposals/src/components/Proposal/Vote.tsx +++ b/packages/proposals/src/components/Proposal/Vote.tsx @@ -74,8 +74,9 @@ export function Vote({ okText: LABELS.CONFIRM, cancelText: LABELS.CANCEL, onOk: async () => { + const vote = await getLatestVote(); + if (userTokenAccount && vote != 0) { - const vote = await getLatestVote(); const voteAmount = userTokenAccount.info.amount.toNumber(); const yesTokenAmount = vote > 0 ? voteAmount : 0; diff --git a/packages/proposals/src/constants/labels.ts b/packages/proposals/src/constants/labels.ts index 9e33f27..90f4c3d 100644 --- a/packages/proposals/src/constants/labels.ts +++ b/packages/proposals/src/constants/labels.ts @@ -39,8 +39,12 @@ export const LABELS = { ADD: 'Add', REMOVE: 'Remove', ADDING_OR_REMOVING: 'Type', - ADDING_VOTES_TO_VOTER: 'Converting governance tokens to voting tokens', - VOTES_ADDED: 'Governance tokens converted.', + + VOTING_FOR_PROPOSAL: 'Voting for proposal.', + PROPOSAL_VOTED: 'Proposal voted.', + TOKENS_VOTED_FOR_THE_PROPOSAL: 'tokens voted for the proposal', + TOKENS_VOTED_AGAINST_THE_PROPOSAL: 'tokens voted against the proposal', + ADDING_GOVERNANCE_TOKENS: 'Adding governance tokens', PLEASE_WAIT: 'Please wait...', GOVERNANCE_TOKENS_ADDED: 'Governance tokens added.', @@ -61,8 +65,6 @@ export const LABELS = { ADD_GOVERNANCE_TOKENS: 'Add Governance Tokens', ADD_COUNCIL_TOKENS: 'Add Council Tokens', ACTIONS: 'Actions', - BURNING_VOTES: 'Burning your votes...', - VOTES_BURNED: 'Votes burned', VOTE: 'Vote', EXECUTING: 'Executing...', EXECUTED: 'Executed.',