diff --git a/.vscode/settings.json b/.vscode/settings.json index 02e42b3..41d54e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,6 @@ "typescript.enablePromptUseWorkspaceTsdk": true, "prettier.prettierPath": ".vscode/pnpify/prettier/index.js", "cSpell.words": [ - "Timelock" + ] } diff --git a/packages/common/src/utils/ids.ts b/packages/common/src/utils/ids.ts index f89f4bf..e3a8987 100644 --- a/packages/common/src/utils/ids.ts +++ b/packages/common/src/utils/ids.ts @@ -46,7 +46,7 @@ let WORMHOLE_BRIDGE: { wrappedMaster: string; }; -let TIMELOCK: { +let GOVERNANCE: { programId: PublicKey; }; @@ -66,7 +66,7 @@ export const ENABLE_FEES_INPUT = false; export const PROGRAM_IDS = [ { name: 'mainnet-beta', - timelock: () => ({ + governance: () => ({ programId: new PublicKey('9iAeqqppjn7g1Jn8o2cQCqU5aQVV3h4q9bbWdKRbeC2w'), }), wormhole: () => ({ @@ -87,7 +87,7 @@ export const PROGRAM_IDS = [ }, { name: 'testnet', - timelock: () => ({ + governance: () => ({ programId: new PublicKey('DCVPuhaGNMLh73FRWFroH4o3ERUhBKMRWfBgJV94VqRk'), }), wormhole: () => ({ @@ -105,7 +105,7 @@ export const PROGRAM_IDS = [ }, { name: 'devnet', - timelock: () => ({ + governance: () => ({ programId: new PublicKey('DCVPuhaGNMLh73FRWFroH4o3ERUhBKMRWfBgJV94VqRk'), }), wormhole: () => ({ @@ -123,8 +123,8 @@ export const PROGRAM_IDS = [ }, { name: 'localnet', - timelock: () => ({ - programId: new PublicKey('3KEiR9eX7isb8xeFzTzbLZij8tKH6YFYUbMyjBp8ygDK'), + governance: () => ({ + programId: new PublicKey('2uWrXQ3tMurqTLe3Dmue6DzasUGV9UPqK7AK7HzS7v3D'), }), wormhole: () => ({ pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'), @@ -155,7 +155,7 @@ export const setProgramIds = (envName: string) => { SWAP_PROGRAM_LAYOUT = swap.current.layout; SWAP_PROGRAM_LEGACY_IDS = swap.legacy; - TIMELOCK = instance.timelock(); + GOVERNANCE = instance.governance(); if (envName === 'mainnet-beta') { LENDING_PROGRAM_ID = new PublicKey( @@ -172,7 +172,7 @@ export const programIds = () => { swapLayout: SWAP_PROGRAM_LAYOUT, lending: LENDING_PROGRAM_ID, wormhole: WORMHOLE_BRIDGE, - timelock: TIMELOCK, + governance: GOVERNANCE, associatedToken: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, bpf_upgrade_loader: BPF_UPGRADE_LOADER_ID, system: SYSTEM, diff --git a/packages/proposals/.env b/packages/governance/.env similarity index 100% rename from packages/proposals/.env rename to packages/governance/.env diff --git a/packages/proposals/.env.production b/packages/governance/.env.production similarity index 100% rename from packages/proposals/.env.production rename to packages/governance/.env.production diff --git a/packages/proposals/craco.config.js b/packages/governance/craco.config.js similarity index 95% rename from packages/proposals/craco.config.js rename to packages/governance/craco.config.js index bd78054..1ce0585 100644 --- a/packages/proposals/craco.config.js +++ b/packages/governance/craco.config.js @@ -10,7 +10,7 @@ module.exports = { webpack: { configure: (webpackConfig, { env, paths }) => { paths.appBuild = webpackConfig.output.path = path.resolve( - './../../build/proposals', + './../../build/governance', ); return webpackConfig; }, diff --git a/packages/proposals/package.json b/packages/governance/package.json similarity index 93% rename from packages/proposals/package.json rename to packages/governance/package.json index 95eb581..b7a3fed 100644 --- a/packages/proposals/package.json +++ b/packages/governance/package.json @@ -1,5 +1,5 @@ { - "name": "proposals", + "name": "governance", "version": "0.0.1", "dependencies": { "@ant-design/icons": "^4.4.0", @@ -60,8 +60,8 @@ "localnet:down": "solana-localnet down", "localnet:logs": "solana-localnet logs -f", "predeploy": "git pull --ff-only && yarn && yarn build", - "deploy": "gh-pages -d ../../build/proposals --repo https://github.com/solana-labs/oyster-gov", - "deploy:ar": "arweave deploy-dir ../../build/proposals --key-file ", + "deploy": "gh-pages -d ../../build/governance --repo https://github.com/solana-labs/oyster-gov", + "deploy:ar": "arweave deploy-dir ../../build/governance --key-file ", "format:fix": "prettier --write \"**/*.+(js|jsx|ts|tsx|json|css|md)\"" }, "eslintConfig": { diff --git a/packages/proposals/public/index.html b/packages/governance/public/index.html similarity index 100% rename from packages/proposals/public/index.html rename to packages/governance/public/index.html diff --git a/packages/proposals/public/logo.ico b/packages/governance/public/logo.ico similarity index 100% rename from packages/proposals/public/logo.ico rename to packages/governance/public/logo.ico diff --git a/packages/proposals/public/manifest.json b/packages/governance/public/manifest.json similarity index 100% rename from packages/proposals/public/manifest.json rename to packages/governance/public/manifest.json diff --git a/packages/proposals/public/robots.txt b/packages/governance/public/robots.txt similarity index 100% rename from packages/proposals/public/robots.txt rename to packages/governance/public/robots.txt diff --git a/packages/proposals/public/splash.svg b/packages/governance/public/splash.svg similarity index 100% rename from packages/proposals/public/splash.svg rename to packages/governance/public/splash.svg diff --git a/packages/proposals/src/App.less b/packages/governance/src/App.less similarity index 100% rename from packages/proposals/src/App.less rename to packages/governance/src/App.less diff --git a/packages/proposals/src/App.tsx b/packages/governance/src/App.tsx similarity index 100% rename from packages/proposals/src/App.tsx rename to packages/governance/src/App.tsx diff --git a/packages/proposals/src/actions/addCustomSingleSignerTransaction.ts b/packages/governance/src/actions/addCustomSingleSignerTransaction.ts similarity index 86% rename from packages/proposals/src/actions/addCustomSingleSignerTransaction.ts rename to packages/governance/src/actions/addCustomSingleSignerTransaction.ts index 4be6682..5fd87ec 100644 --- a/packages/proposals/src/actions/addCustomSingleSignerTransaction.ts +++ b/packages/governance/src/actions/addCustomSingleSignerTransaction.ts @@ -8,10 +8,10 @@ import { import { contexts, utils, models, ParsedAccount } from '@oyster/common'; import { GOVERNANCE_AUTHORITY_SEED, - CustomSingleSignerTimelockTransactionLayout, - TimelockSet, - TimelockState, -} from '../models/timelock'; + CustomSingleSignerTransactionLayout, + Proposal, + ProposalState, +} from '../models/governance'; import { addCustomSingleSignerTransactionInstruction } from '../models/addCustomSingleSignerTransaction'; const { sendTransaction } = contexts.Connection; @@ -21,8 +21,8 @@ const { approve } = models; export const addCustomSingleSignerTransaction = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, - state: ParsedAccount, + proposal: ParsedAccount, + state: ParsedAccount, sigAccount: PublicKey, slot: string, instruction: string, @@ -34,7 +34,7 @@ export const addCustomSingleSignerTransaction = async ( let instructions: TransactionInstruction[] = []; const rentExempt = await connection.getMinimumBalanceForRentExemption( - CustomSingleSignerTimelockTransactionLayout.span, + CustomSingleSignerTransactionLayout.span, ); const txnKey = new Account(); @@ -43,13 +43,13 @@ export const addCustomSingleSignerTransaction = async ( fromPubkey: wallet.publicKey, newAccountPubkey: txnKey.publicKey, lamports: rentExempt, - space: CustomSingleSignerTimelockTransactionLayout.span, - programId: PROGRAM_IDS.timelock.programId, + space: CustomSingleSignerTransactionLayout.span, + programId: PROGRAM_IDS.governance.programId, }); const [authority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); signers.push(txnKey); diff --git a/packages/proposals/src/actions/addSigner.ts b/packages/governance/src/actions/addSigner.ts similarity index 92% rename from packages/proposals/src/actions/addSigner.ts rename to packages/governance/src/actions/addSigner.ts index f03b39a..9263bd3 100644 --- a/packages/proposals/src/actions/addSigner.ts +++ b/packages/governance/src/actions/addSigner.ts @@ -14,9 +14,9 @@ import { import { GOVERNANCE_AUTHORITY_SEED, - TimelockSet, - TimelockState, -} from '../models/timelock'; + Proposal, + ProposalState, +} from '../models/governance'; import { AccountLayout } from '@solana/spl-token'; import { addSignerInstruction } from '../models/addSigner'; const { createTokenAccount } = actions; @@ -27,8 +27,8 @@ const { approve } = models; export const addSigner = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, - state: ParsedAccount, + proposal: ParsedAccount, + state: ParsedAccount, adminAccount: PublicKey, newSignatoryAccountOwner: PublicKey, ) => { @@ -52,7 +52,7 @@ export const addSigner = async ( const [mintAuthority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); const transferAuthority = approve( diff --git a/packages/proposals/src/actions/createProposal.ts b/packages/governance/src/actions/createProposal.ts similarity index 77% rename from packages/proposals/src/actions/createProposal.ts rename to packages/governance/src/actions/createProposal.ts index 052687c..6ba48ad 100644 --- a/packages/proposals/src/actions/createProposal.ts +++ b/packages/governance/src/actions/createProposal.ts @@ -14,13 +14,13 @@ import { } from '@oyster/common'; import { AccountLayout, MintLayout } from '@solana/spl-token'; -import { initTimelockSetInstruction } from '../models/initTimelockSet'; +import { initProposalInstruction } from '../models/initProposal'; import { GOVERNANCE_AUTHORITY_SEED, - TimelockConfig, - TimelockSetLayout, - TimelockStateLayout, -} from '../models/timelock'; + Governance, + ProposalLayout, + ProposalStateLayout, +} from '../models/governance'; const { cache } = contexts.Accounts; const { sendTransactions } = contexts.Connection; @@ -33,7 +33,7 @@ export const createProposal = async ( name: string, description: string, useGovernance: boolean, - timelockConfig: ParsedAccount, + governance: ParsedAccount, ): Promise => { const PROGRAM_IDS = utils.programIds(); @@ -51,12 +51,12 @@ export const createProposal = async ( await cache.queryMint( connection, useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!, + ? governance.info.governanceMint + : governance.info.councilMint!, ) ).decimals; - const timelockSetKey = new Account(); + const proposalKey = new Account(); const { sigMint, @@ -79,54 +79,54 @@ export const createProposal = async ( wallet, accountRentExempt, mintRentExempt, - timelockConfig, + governance, useGovernance, sourceMintDecimals, - timelockSetKey, + proposalKey, ); - let createTimelockAccountsSigners: Account[] = []; - let createTimelockAccountsInstructions: TransactionInstruction[] = []; + let createGovernanceAccountsSigners: Account[] = []; + let createGovernanceAccountsInstructions: TransactionInstruction[] = []; - const timelockRentExempt = await connection.getMinimumBalanceForRentExemption( - TimelockSetLayout.span, + const proposalRentExempt = await connection.getMinimumBalanceForRentExemption( + ProposalLayout.span, ); - const timelockStateRentExempt = await connection.getMinimumBalanceForRentExemption( - TimelockStateLayout.span, + const proposalStateRentExempt = await connection.getMinimumBalanceForRentExemption( + ProposalStateLayout.span, ); - const timelockStateKey = new Account(); + const proposalStateKey = new Account(); - const uninitializedTimelockStateInstruction = SystemProgram.createAccount({ + const uninitializedProposalStateInstruction = SystemProgram.createAccount({ fromPubkey: wallet.publicKey, - newAccountPubkey: timelockStateKey.publicKey, - lamports: timelockStateRentExempt, - space: TimelockStateLayout.span, - programId: PROGRAM_IDS.timelock.programId, + newAccountPubkey: proposalStateKey.publicKey, + lamports: proposalStateRentExempt, + space: ProposalStateLayout.span, + programId: PROGRAM_IDS.governance.programId, }); - signers.push(timelockStateKey); - createTimelockAccountsSigners.push(timelockStateKey); - createTimelockAccountsInstructions.push( - uninitializedTimelockStateInstruction, + signers.push(proposalStateKey); + createGovernanceAccountsSigners.push(proposalStateKey); + createGovernanceAccountsInstructions.push( + uninitializedProposalStateInstruction, ); - const uninitializedTimelockSetInstruction = SystemProgram.createAccount({ + const uninitializedProposalInstruction = SystemProgram.createAccount({ fromPubkey: wallet.publicKey, - newAccountPubkey: timelockSetKey.publicKey, - lamports: timelockRentExempt, - space: TimelockSetLayout.span, - programId: PROGRAM_IDS.timelock.programId, + newAccountPubkey: proposalKey.publicKey, + lamports: proposalRentExempt, + space: ProposalLayout.span, + programId: PROGRAM_IDS.governance.programId, }); - signers.push(timelockSetKey); - createTimelockAccountsSigners.push(timelockSetKey); - createTimelockAccountsInstructions.push(uninitializedTimelockSetInstruction); + signers.push(proposalKey); + createGovernanceAccountsSigners.push(proposalKey); + createGovernanceAccountsInstructions.push(uninitializedProposalInstruction); instructions.push( - initTimelockSetInstruction( - timelockStateKey.publicKey, - timelockSetKey.publicKey, - timelockConfig.pubkey, + initProposalInstruction( + proposalStateKey.publicKey, + proposalKey.publicKey, + governance.pubkey, sigMint, adminMint, voteMint, @@ -141,8 +141,8 @@ export const createProposal = async ( noVoteDumpAccount, sourceHoldingAccount, useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!, + ? governance.info.governanceMint + : governance.info.councilMint!, authority, description, name, @@ -161,11 +161,12 @@ export const createProposal = async ( wallet, [ ...associatedInstructions, - createTimelockAccountsInstructions, + createGovernanceAccountsInstructions, instructions, ], - [...associatedSigners, createTimelockAccountsSigners, signers], - SequenceType.Sequential, + [...associatedSigners, createGovernanceAccountsSigners, signers], + true, + true, ); notify({ @@ -174,7 +175,7 @@ export const createProposal = async ( description: `Transaction - ${tx}`, }); - return timelockSetKey; + return proposalKey; } catch (ex) { console.error(ex); throw new Error(); @@ -204,7 +205,7 @@ async function getAssociatedAccountsAndInstructions( wallet: any, accountRentExempt: number, mintRentExempt: number, - timelockConfig: ParsedAccount, + governance: ParsedAccount, useGovernance: boolean, sourceMintDecimals: number, newProposalKey: Account, @@ -216,7 +217,7 @@ async function getAssociatedAccountsAndInstructions( Buffer.from(GOVERNANCE_AUTHORITY_SEED), newProposalKey.publicKey.toBuffer(), ], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); let mintSigners: Account[] = []; @@ -351,8 +352,8 @@ async function getAssociatedAccountsAndInstructions( wallet.publicKey, accountRentExempt, useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!, + ? governance.info.governanceMint + : governance.info.councilMint!, authority, holdingSigners, ); diff --git a/packages/proposals/src/actions/depositSourceTokensAndVote.ts b/packages/governance/src/actions/depositSourceTokensAndVote.ts similarity index 93% rename from packages/proposals/src/actions/depositSourceTokensAndVote.ts rename to packages/governance/src/actions/depositSourceTokensAndVote.ts index 29cc5db..608d431 100644 --- a/packages/proposals/src/actions/depositSourceTokensAndVote.ts +++ b/packages/governance/src/actions/depositSourceTokensAndVote.ts @@ -14,10 +14,10 @@ import { import { GOVERNANCE_AUTHORITY_SEED, - TimelockConfig, - TimelockSet, - TimelockState, -} from '../models/timelock'; + Governance, + Proposal, + ProposalState, +} from '../models/governance'; import { AccountLayout } from '@solana/spl-token'; @@ -35,13 +35,13 @@ const { approve } = models; export const depositSourceTokensAndVote = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, + proposal: ParsedAccount, existingVoteAccount: PublicKey | undefined, existingYesVoteAccount: PublicKey | undefined, existingNoVoteAccount: PublicKey | undefined, sourceAccount: PublicKey, - timelockConfig: ParsedAccount, - state: ParsedAccount, + governance: ParsedAccount, + state: ParsedAccount, yesVotingTokenAmount: number, noVotingTokenAmount: number, ) => { @@ -72,11 +72,11 @@ export const depositSourceTokensAndVote = async ( const [governanceVotingRecord] = await PublicKey.findProgramAddress( [ Buffer.from(GOVERNANCE_AUTHORITY_SEED), - PROGRAM_IDS.timelock.programId.toBuffer(), + PROGRAM_IDS.governance.programId.toBuffer(), proposal.pubkey.toBuffer(), existingVoteAccount.toBuffer(), ], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); if (needToCreateGovAccountToo) { @@ -114,7 +114,7 @@ export const depositSourceTokensAndVote = async ( const [mintAuthority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); const depositAuthority = approve( @@ -166,7 +166,7 @@ export const depositSourceTokensAndVote = async ( proposal.info.noVotingMint, proposal.info.sourceMint, proposal.pubkey, - timelockConfig.pubkey, + governance.pubkey, voteAuthority.publicKey, mintAuthority, yesVotingTokenAmount, diff --git a/packages/governance/src/actions/execute.ts b/packages/governance/src/actions/execute.ts new file mode 100644 index 0000000..e08b04b --- /dev/null +++ b/packages/governance/src/actions/execute.ts @@ -0,0 +1,71 @@ +import { + Account, + Connection, + Message, + TransactionInstruction, +} from '@solana/web3.js'; +import { contexts, utils, ParsedAccount } from '@oyster/common'; + +import { + Proposal, + ProposalState, + GovernanceTransaction, +} from '../models/governance'; +import { executeInstruction } from '../models/execute'; +import { LABELS } from '../constants'; +import { getMessageAccountInfos } from '../utils/transactions'; +const { sendTransaction } = contexts.Connection; +const { notify } = utils; + +export const execute = async ( + connection: Connection, + wallet: any, + proposal: ParsedAccount, + state: ParsedAccount, + transaction: ParsedAccount, +) => { + let signers: Account[] = []; + let instructions: TransactionInstruction[] = []; + const actualMessage = decodeBufferIntoMessage(transaction.info.instruction); + const accountInfos = getMessageAccountInfos(actualMessage); + + instructions.push( + executeInstruction( + transaction.pubkey, + state.pubkey, + proposal.pubkey, + actualMessage.accountKeys[actualMessage.instructions[0].programIdIndex], + proposal.info.config, + accountInfos, + ), + ); + + notify({ + message: LABELS.EXECUTING, + description: LABELS.PLEASE_WAIT, + type: 'warn', + }); + + try { + let tx = await sendTransaction( + connection, + wallet, + instructions, + signers, + true, + ); + + notify({ + message: LABELS.EXECUTED, + type: 'success', + description: LABELS.TRANSACTION + ` ${tx}`, + }); + } catch (ex) { + console.error(ex); + throw new Error(); + } +}; + +function decodeBufferIntoMessage(instruction: number[]): Message { + return Message.from(instruction); +} diff --git a/packages/proposals/src/actions/mintSourceTokens.ts b/packages/governance/src/actions/mintSourceTokens.ts similarity index 89% rename from packages/proposals/src/actions/mintSourceTokens.ts rename to packages/governance/src/actions/mintSourceTokens.ts index 43d05c7..8c93ff2 100644 --- a/packages/proposals/src/actions/mintSourceTokens.ts +++ b/packages/governance/src/actions/mintSourceTokens.ts @@ -12,7 +12,7 @@ import { SequenceType, } from '@oyster/common'; -import { TimelockConfig } from '../models/timelock'; +import { Governance } from '../models/governance'; import { AccountLayout, Token } from '@solana/spl-token'; import { LABELS } from '../constants'; const { createTokenAccount } = actions; @@ -26,7 +26,7 @@ export interface SourceEntryInterface { export const mintSourceTokens = async ( connection: Connection, wallet: any, - timelockConfig: ParsedAccount, + governance: ParsedAccount, useGovernance: boolean, entries: SourceEntryInterface[], setSavePerc: (num: number) => void, @@ -50,8 +50,8 @@ export const mintSourceTokens = async ( wallet.publicKey, accountRentExempt, useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!, + ? governance.info.governanceMint + : governance.info.councilMint!, e.owner, signers, ); @@ -60,8 +60,8 @@ export const mintSourceTokens = async ( Token.createMintToInstruction( PROGRAM_IDS.token, useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!, + ? governance.info.governanceMint + : governance.info.councilMint!, e.sourceAccount, wallet.publicKey, [], diff --git a/packages/proposals/src/actions/registerProgramGovernance.ts b/packages/governance/src/actions/registerProgramGovernance.ts similarity index 58% rename from packages/proposals/src/actions/registerProgramGovernance.ts rename to packages/governance/src/actions/registerProgramGovernance.ts index e42df27..058f478 100644 --- a/packages/proposals/src/actions/registerProgramGovernance.ts +++ b/packages/governance/src/actions/registerProgramGovernance.ts @@ -10,13 +10,13 @@ import { AccountLayout, MintLayout, Token } from '@solana/spl-token'; import { GOVERNANCE_AUTHORITY_SEED, ExecutionType, - TimelockConfig, - TimelockType, + Governance, + GovernanceType, VotingEntryRule, -} from '../models/timelock'; -import { initTimelockConfigInstruction } from '../models/initTimelockConfig'; +} from '../models/governance'; +import { initGovernanceInstruction } from '../models/initGovernance'; import BN from 'bn.js'; -import { createEmptyTimelockConfigInstruction } from '../models/createEmptyTimelockConfig'; +import { createEmptyGovernanceInstruction } from '../models/createEmptyGovernance'; const { sendTransactions } = contexts.Connection; const { createMint, createTokenAccount } = actions; @@ -25,7 +25,7 @@ const { notify } = utils; export const registerProgramGovernance = async ( connection: Connection, wallet: any, - uninitializedTimelockConfig: Partial, + uninitializedGovernance: Partial, useCouncil: boolean, ): Promise => { const PROGRAM_IDS = utils.programIds(); @@ -41,13 +41,13 @@ export const registerProgramGovernance = async ( AccountLayout.span, ); - if (!uninitializedTimelockConfig.program) - uninitializedTimelockConfig.program = new Account().publicKey; // Random generation if none given + if (!uninitializedGovernance.program) + uninitializedGovernance.program = new Account().publicKey; // Random generation if none given - if (!uninitializedTimelockConfig.councilMint && useCouncil) { + if (!uninitializedGovernance.councilMint && useCouncil) { // Initialize the mint, an account for the admin, and give them one council token // to start their lives with. - uninitializedTimelockConfig.councilMint = createMint( + uninitializedGovernance.councilMint = createMint( mintInstructions, wallet.publicKey, mintRentExempt, @@ -61,7 +61,7 @@ export const registerProgramGovernance = async ( mintInstructions, wallet.publicKey, accountRentExempt, - uninitializedTimelockConfig.councilMint, + uninitializedGovernance.councilMint, wallet.publicKey, mintSigners, ); @@ -69,7 +69,7 @@ export const registerProgramGovernance = async ( mintInstructions.push( Token.createMintToInstruction( PROGRAM_IDS.token, - uninitializedTimelockConfig.councilMint, + uninitializedGovernance.councilMint, adminsCouncilToken, wallet.publicKey, [], @@ -78,10 +78,10 @@ export const registerProgramGovernance = async ( ); } - if (!uninitializedTimelockConfig.governanceMint) { + if (!uninitializedGovernance.governanceMint) { // Initialize the mint, an account for the admin, and give them one governance token // to start their lives with. - uninitializedTimelockConfig.governanceMint = createMint( + uninitializedGovernance.governanceMint = createMint( mintInstructions, wallet.publicKey, mintRentExempt, @@ -95,7 +95,7 @@ export const registerProgramGovernance = async ( mintInstructions, wallet.publicKey, accountRentExempt, - uninitializedTimelockConfig.governanceMint, + uninitializedGovernance.governanceMint, wallet.publicKey, mintSigners, ); @@ -103,7 +103,7 @@ export const registerProgramGovernance = async ( mintInstructions.push( Token.createMintToInstruction( PROGRAM_IDS.token, - uninitializedTimelockConfig.governanceMint, + uninitializedGovernance.governanceMint, adminsGovernanceToken, wallet.publicKey, [], @@ -112,52 +112,44 @@ export const registerProgramGovernance = async ( ); } - const councilMintSeed = uninitializedTimelockConfig.councilMint - ? uninitializedTimelockConfig.councilMint.toBuffer() - : Buffer.from(''); - - const [timelockConfigKey] = await PublicKey.findProgramAddress( + const [governanceKey] = await PublicKey.findProgramAddress( [ Buffer.from(GOVERNANCE_AUTHORITY_SEED), - PROGRAM_IDS.timelock.programId.toBuffer(), - uninitializedTimelockConfig.governanceMint.toBuffer(), - councilMintSeed, - uninitializedTimelockConfig.program.toBuffer(), + uninitializedGovernance.program.toBuffer(), ], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); const [programDataAccount] = await PublicKey.findProgramAddress( - [uninitializedTimelockConfig.program.toBuffer()], + [uninitializedGovernance.program.toBuffer()], PROGRAM_IDS.bpf_upgrade_loader, ); instructions.push( - createEmptyTimelockConfigInstruction( - timelockConfigKey, - uninitializedTimelockConfig.program, + createEmptyGovernanceInstruction( + governanceKey, + uninitializedGovernance.program, programDataAccount, wallet.publicKey, - uninitializedTimelockConfig.governanceMint, + uninitializedGovernance.governanceMint, wallet.publicKey, - uninitializedTimelockConfig.councilMint, + uninitializedGovernance.councilMint, ), ); instructions.push( - initTimelockConfigInstruction( - timelockConfigKey, - uninitializedTimelockConfig.program, - uninitializedTimelockConfig.governanceMint, + initGovernanceInstruction( + governanceKey, + uninitializedGovernance.program, + uninitializedGovernance.governanceMint, - uninitializedTimelockConfig.voteThreshold!, - uninitializedTimelockConfig.executionType || ExecutionType.Independent, - uninitializedTimelockConfig.timelockType || - TimelockType.CustomSingleSignerV1, - uninitializedTimelockConfig.votingEntryRule || VotingEntryRule.Anytime, - uninitializedTimelockConfig.minimumSlotWaitingPeriod || new BN(0), - uninitializedTimelockConfig.timeLimit || new BN(0), - uninitializedTimelockConfig.name || '', - uninitializedTimelockConfig.councilMint, + uninitializedGovernance.voteThreshold!, + uninitializedGovernance.executionType || ExecutionType.Independent, + uninitializedGovernance.governanceType || GovernanceType.Governance, + uninitializedGovernance.votingEntryRule || VotingEntryRule.Anytime, + uninitializedGovernance.minimumSlotWaitingPeriod || new BN(0), + uninitializedGovernance.timeLimit || new BN(0), + uninitializedGovernance.name || '', + uninitializedGovernance.councilMint, ), ); @@ -184,7 +176,7 @@ export const registerProgramGovernance = async ( description: `Transaction - ${tx}`, }); - return timelockConfigKey; + return governanceKey; } catch (ex) { console.error(ex); throw new Error(); diff --git a/packages/proposals/src/actions/removeSigner.ts b/packages/governance/src/actions/removeSigner.ts similarity index 91% rename from packages/proposals/src/actions/removeSigner.ts rename to packages/governance/src/actions/removeSigner.ts index 02ba946..9dd2747 100644 --- a/packages/proposals/src/actions/removeSigner.ts +++ b/packages/governance/src/actions/removeSigner.ts @@ -6,7 +6,7 @@ import { } from '@solana/web3.js'; import { contexts, utils, models, ParsedAccount } from '@oyster/common'; -import { GOVERNANCE_AUTHORITY_SEED, TimelockSet } from '../models/timelock'; +import { GOVERNANCE_AUTHORITY_SEED, Proposal } from '../models/governance'; import { removeSignerInstruction } from '../models/removeSigner'; const { sendTransaction } = contexts.Connection; const { notify } = utils; @@ -15,7 +15,7 @@ const { approve } = models; export const removeSigner = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, + proposal: ParsedAccount, adminAccount: PublicKey, sigAccount: PublicKey, ) => { @@ -26,7 +26,7 @@ export const removeSigner = async ( const [mintAuthority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); const transferAuthority = approve( diff --git a/packages/proposals/src/actions/sign.ts b/packages/governance/src/actions/sign.ts similarity index 89% rename from packages/proposals/src/actions/sign.ts rename to packages/governance/src/actions/sign.ts index 02d34a3..725deed 100644 --- a/packages/proposals/src/actions/sign.ts +++ b/packages/governance/src/actions/sign.ts @@ -8,9 +8,9 @@ import { contexts, utils, models, ParsedAccount } from '@oyster/common'; import { GOVERNANCE_AUTHORITY_SEED, - TimelockSet, - TimelockState, -} from '../models/timelock'; + Proposal, + ProposalState, +} from '../models/governance'; import { signInstruction } from '../models/sign'; const { sendTransaction } = contexts.Connection; @@ -20,8 +20,8 @@ const { approve } = models; export const sign = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, - state: ParsedAccount, + proposal: ParsedAccount, + state: ParsedAccount, sigAccount: PublicKey, ) => { const PROGRAM_IDS = utils.programIds(); @@ -31,7 +31,7 @@ export const sign = async ( const [mintAuthority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); const transferAuthority = approve( diff --git a/packages/proposals/src/actions/withdrawVotingTokens.ts b/packages/governance/src/actions/withdrawVotingTokens.ts similarity index 92% rename from packages/proposals/src/actions/withdrawVotingTokens.ts rename to packages/governance/src/actions/withdrawVotingTokens.ts index 424ba34..0cc584e 100644 --- a/packages/proposals/src/actions/withdrawVotingTokens.ts +++ b/packages/governance/src/actions/withdrawVotingTokens.ts @@ -14,10 +14,10 @@ import { import { GOVERNANCE_AUTHORITY_SEED, - TimelockSet, - TimelockState, - TimelockStateStatus, -} from '../models/timelock'; + Proposal, + ProposalState, + ProposalStateStatus, +} from '../models/governance'; import { AccountLayout } from '@solana/spl-token'; import { withdrawVotingTokensInstruction } from '../models/withdrawVotingTokens'; import { LABELS } from '../constants'; @@ -29,8 +29,8 @@ const { approve } = models; export const withdrawVotingTokens = async ( connection: Connection, wallet: any, - proposal: ParsedAccount, - state: ParsedAccount, + proposal: ParsedAccount, + state: ParsedAccount, existingVoteAccount: PublicKey | undefined, existingYesVoteAccount: PublicKey | undefined, existingNoVoteAccount: PublicKey | undefined, @@ -81,7 +81,7 @@ export const withdrawVotingTokens = async ( const [mintAuthority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); // We dont know in this scope how much is in each account so we just ask for all in each. @@ -119,11 +119,11 @@ export const withdrawVotingTokens = async ( const [governanceVotingRecord] = await PublicKey.findProgramAddress( [ Buffer.from(GOVERNANCE_AUTHORITY_SEED), - PROGRAM_IDS.timelock.programId.toBuffer(), + PROGRAM_IDS.governance.programId.toBuffer(), proposal.pubkey.toBuffer(), existingVoteAccount.toBuffer(), ], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); signers.push(transferAuthority); @@ -150,7 +150,7 @@ export const withdrawVotingTokens = async ( ); const [msg, completedMsg] = - state.info.status === TimelockStateStatus.Voting + state.info.status === ProposalStateStatus.Voting ? [LABELS.WITHDRAWING_YOUR_VOTE, LABELS.VOTE_WITHDRAWN] : [LABELS.REFUNDING_YOUR_TOKENS, LABELS.TOKENS_REFUNDED]; diff --git a/packages/proposals/src/ant-custom.less b/packages/governance/src/ant-custom.less similarity index 100% rename from packages/proposals/src/ant-custom.less rename to packages/governance/src/ant-custom.less diff --git a/packages/proposals/src/components/Background/index.tsx b/packages/governance/src/components/Background/index.tsx similarity index 100% rename from packages/proposals/src/components/Background/index.tsx rename to packages/governance/src/components/Background/index.tsx diff --git a/packages/proposals/src/components/Background/styles.less b/packages/governance/src/components/Background/styles.less similarity index 100% rename from packages/proposals/src/components/Background/styles.less rename to packages/governance/src/components/Background/styles.less diff --git a/packages/proposals/src/components/Background/useCannon.tsx b/packages/governance/src/components/Background/useCannon.tsx similarity index 52% rename from packages/proposals/src/components/Background/useCannon.tsx rename to packages/governance/src/components/Background/useCannon.tsx index 1821fe6..8cab58b 100644 --- a/packages/proposals/src/components/Background/useCannon.tsx +++ b/packages/governance/src/components/Background/useCannon.tsx @@ -1,53 +1,49 @@ -import * as CANNON from 'cannon' -import React, { useState, useEffect, useContext, useRef } from 'react' -import { useFrame } from 'react-three-fiber' +import * as CANNON from 'cannon'; +import React, { useState, useEffect, useContext, useRef } from 'react'; +import { useFrame } from 'react-three-fiber'; // Cannon-world context provider -export const CannonContext = React.createContext( - null, -); +export const CannonContext = React.createContext(null); export function Provider({ children = null as any }) { // Set up physics const [world] = useState(() => new CANNON.World()); useEffect(() => { - world.broadphase = new CANNON.NaiveBroadphase() - world.solver.iterations = 10 - world.gravity.set(0, 0, -25) + world.broadphase = new CANNON.NaiveBroadphase(); + world.solver.iterations = 10; + world.gravity.set(0, 0, -25); }, [world]); // Run world stepper every frame useFrame(() => world.step(1 / 60)); // Distribute world via context - return ( - - ); + return ; } // Custom hook to maintain a world physics body export function useCannon({ ...props }, fn: any, deps = []) { - const ref = useRef() + const ref = useRef(); // Get cannon world object - const world = useContext(CannonContext) + const world = useContext(CannonContext); // Instanciate a physics body - const [body] = useState(() => new CANNON.Body(props)) + const [body] = useState(() => new CANNON.Body(props)); useEffect(() => { // Call function so the user can add shapes - fn(body) + fn(body); // Add body to world on mount - world.addBody(body) + world.addBody(body); // Remove body on unmount - return () => world.removeBody(body) - }, deps) + return () => world.removeBody(body); + }, deps); //eslint-disable-line useFrame(() => { if (ref.current) { // Transport cannon physics into the referenced threejs object - ref.current.position.copy(body.position) - ref.current.quaternion.copy(body.quaternion) + ref.current.position.copy(body.position); + ref.current.quaternion.copy(body.quaternion); } - }) + }); - return ref + return ref; } diff --git a/packages/proposals/src/components/Layout/dark-horizontal-combined-rainbow.inline.svg b/packages/governance/src/components/Layout/dark-horizontal-combined-rainbow.inline.svg similarity index 100% rename from packages/proposals/src/components/Layout/dark-horizontal-combined-rainbow.inline.svg rename to packages/governance/src/components/Layout/dark-horizontal-combined-rainbow.inline.svg diff --git a/packages/proposals/src/components/Layout/index.tsx b/packages/governance/src/components/Layout/index.tsx similarity index 51% rename from packages/proposals/src/components/Layout/index.tsx rename to packages/governance/src/components/Layout/index.tsx index b3ede8c..f6b9baa 100644 --- a/packages/proposals/src/components/Layout/index.tsx +++ b/packages/governance/src/components/Layout/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; import './../../App.less'; -import { Breadcrumb, Layout } from 'antd'; -import { Link, useLocation } from 'react-router-dom'; +import { Layout } from 'antd'; +import { Link } from 'react-router-dom'; import { LABELS } from '../../constants'; import { components } from '@oyster/common'; @@ -11,30 +11,31 @@ import Logo from './dark-horizontal-combined-rainbow.inline.svg'; const { AppBar } = components; export const AppLayout = React.memo((props: any) => { - const location = useLocation(); + // const location = useLocation(); - const breadcrumbNameMap: any = { - '/governance': 'Governance', - '/apps/1': 'Application1', - '/apps/2': 'Application2', - '/apps/1/detail': 'Detail', - '/apps/2/detail': 'Detail', - }; + // const breadcrumbNameMap: any = { + // '/governance': 'Governance', + // '/apps/1': 'Application1', + // '/apps/2': 'Application2', + // '/apps/1/detail': 'Detail', + // '/apps/2/detail': 'Detail', + // }; - const pathSnippets = location.pathname.split('/').filter(i => i); - const extraBreadcrumbItems = pathSnippets.map((_, index) => { - const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; - return ( - - {breadcrumbNameMap[url]} - - ); - }); - const breadcrumbItems = [ - - Home - , - ].concat(extraBreadcrumbItems); + //const pathSnippets = location.pathname.split('/').filter(i => i); + // const extraBreadcrumbItems = pathSnippets.map((_, index) => { + // const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; + // return ( + // + // {breadcrumbNameMap[url]} + // + // ); + // }); + + // const breadcrumbItems = [ + // + // Home + // , + // ].concat(extraBreadcrumbItems); // TODO: add breadcrumb diff --git a/packages/proposals/src/components/Proposal/AddSigners.tsx b/packages/governance/src/components/Proposal/AddSigners.tsx similarity index 96% rename from packages/proposals/src/components/Proposal/AddSigners.tsx rename to packages/governance/src/components/Proposal/AddSigners.tsx index fe27065..33f3f20 100644 --- a/packages/proposals/src/components/Proposal/AddSigners.tsx +++ b/packages/governance/src/components/Proposal/AddSigners.tsx @@ -1,7 +1,7 @@ import { ParsedAccount } from '@oyster/common'; import { Button, Modal, Input, Form, Progress } from 'antd'; import React, { useState } from 'react'; -import { TimelockSet, TimelockState } from '../../models/timelock'; +import { Proposal, ProposalState } from '../../models/governance'; import { utils, contexts, hooks } from '@oyster/common'; import { addSigner } from '../../actions/addSigner'; import { PublicKey } from '@solana/web3.js'; @@ -22,8 +22,8 @@ export default function AddSigners({ proposal, state, }: { - proposal: ParsedAccount; - state: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; }) { const wallet = useWallet(); const connection = useConnection(); diff --git a/packages/proposals/src/components/Proposal/InstructionCard.tsx b/packages/governance/src/components/Proposal/InstructionCard.tsx similarity index 72% rename from packages/proposals/src/components/Proposal/InstructionCard.tsx rename to packages/governance/src/components/Proposal/InstructionCard.tsx index 1e8ba7d..a1c4f80 100644 --- a/packages/proposals/src/components/Proposal/InstructionCard.tsx +++ b/packages/governance/src/components/Proposal/InstructionCard.tsx @@ -7,17 +7,19 @@ import { RedoOutlined, } from '@ant-design/icons'; import { ParsedAccount, contexts } from '@oyster/common'; -import { Card } from 'antd'; +import { Message } from '@solana/web3.js'; +import { Card, Button } from 'antd'; import Meta from 'antd/lib/card/Meta'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { execute } from '../../actions/execute'; import { LABELS } from '../../constants'; import { - TimelockSet, - TimelockState, - TimelockStateStatus, - TimelockTransaction, -} from '../../models/timelock'; + Proposal, + ProposalState, + ProposalStateStatus, + GovernanceTransaction, +} from '../../models/governance'; + import './style.less'; const { useWallet } = contexts.Wallet; @@ -35,22 +37,33 @@ export function InstructionCard({ state, position, }: { - instruction: ParsedAccount; - proposal: ParsedAccount; - state: ParsedAccount; + instruction: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; position: number; }) { const [tabKey, setTabKey] = useState('info'); const [playing, setPlaying] = useState( instruction.info.executed === 1 ? Playstate.Played : Playstate.Unplayed, ); + + const instructionDetails = useMemo(() => { + const message = Message.from(instruction.info.instruction); + + return { + instructionProgramID: + message.accountKeys[message.instructions[0].programIdIndex], + instructionData: message.instructions[0].data, + }; + }, [instruction]); + const contentList: Record = { info: ( -

Instruction: TODO

+

{`${LABELS.INSTRUCTION}: ${instructionDetails.instructionData}`}

{LABELS.DELAY}: {instruction.info.slot.toNumber()}

@@ -93,9 +106,9 @@ function PlayStatusButton({ setPlaying, instruction, }: { - proposal: ParsedAccount; - state: ParsedAccount; - instruction: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; + instruction: ParsedAccount; playing: Playstate; setPlaying: React.Dispatch>; }) { @@ -131,25 +144,25 @@ function PlayStatusButton({ }; if ( - state.info.status !== TimelockStateStatus.Executing && - state.info.status !== TimelockStateStatus.Completed + state.info.status !== ProposalStateStatus.Executing && + state.info.status !== ProposalStateStatus.Completed ) return null; if (ineligibleToSee) return null; if (playing === Playstate.Unplayed) return ( - + ); else if (playing === Playstate.Playing) return ; else if (playing === Playstate.Error) return ( - + ); else return ; } diff --git a/packages/proposals/src/components/Proposal/MintSourceTokens.tsx b/packages/governance/src/components/Proposal/MintSourceTokens.tsx similarity index 96% rename from packages/proposals/src/components/Proposal/MintSourceTokens.tsx rename to packages/governance/src/components/Proposal/MintSourceTokens.tsx index 3e538be..291f1d6 100644 --- a/packages/proposals/src/components/Proposal/MintSourceTokens.tsx +++ b/packages/governance/src/components/Proposal/MintSourceTokens.tsx @@ -1,7 +1,7 @@ import { ParsedAccount } from '@oyster/common'; import { Button, Modal, Input, Form, Progress, InputNumber, Radio } from 'antd'; import React, { useState } from 'react'; -import { TimelockConfig } from '../../models/timelock'; +import { Governance } from '../../models/governance'; import { utils, contexts } from '@oyster/common'; import { PublicKey } from '@solana/web3.js'; import { LABELS } from '../../constants'; @@ -22,18 +22,18 @@ const layout = { }; export default function MintSourceTokens({ - timelockConfig, + governance, useGovernance, }: { - timelockConfig: ParsedAccount; + governance: ParsedAccount; useGovernance: boolean; }) { const PROGRAM_IDS = utils.programIds(); const wallet = useWallet(); const connection = useConnection(); const mintKey = useGovernance - ? timelockConfig.info.governanceMint - : timelockConfig.info.councilMint!; + ? governance.info.governanceMint + : governance.info.councilMint!; const mint = useMint(mintKey); const [saving, setSaving] = useState(false); @@ -108,7 +108,7 @@ export default function MintSourceTokens({ try { if (sourceHolders[i].owner) { const tokenAccounts = await connection.getTokenAccountsByOwner( - sourceHolders[i].owner || PROGRAM_IDS.timelock, + sourceHolders[i].owner || PROGRAM_IDS.governance, { programId: PROGRAM_IDS.token, }, @@ -130,7 +130,7 @@ export default function MintSourceTokens({ await mintSourceTokens( connection, wallet.wallet, - timelockConfig, + governance, useGovernance, sourceHoldersToRun, setSavePerc, diff --git a/packages/proposals/src/components/Proposal/NewInstructionCard.tsx b/packages/governance/src/components/Proposal/NewInstructionCard.tsx similarity index 92% rename from packages/proposals/src/components/Proposal/NewInstructionCard.tsx rename to packages/governance/src/components/Proposal/NewInstructionCard.tsx index af8fc55..f57d238 100644 --- a/packages/proposals/src/components/Proposal/NewInstructionCard.tsx +++ b/packages/governance/src/components/Proposal/NewInstructionCard.tsx @@ -3,10 +3,10 @@ import { Card } from 'antd'; import { Form, Input } from 'antd'; import { INSTRUCTION_LIMIT, - TimelockConfig, - TimelockSet, - TimelockState, -} from '../../models/timelock'; + Governance, + Proposal, + ProposalState, +} from '../../models/governance'; import { contexts, ParsedAccount, hooks, utils } from '@oyster/common'; import { addCustomSingleSignerTransaction } from '../../actions/addCustomSingleSignerTransaction'; import { SaveOutlined } from '@ant-design/icons'; @@ -28,9 +28,9 @@ export function NewInstructionCard({ position, config, }: { - proposal: ParsedAccount; - state: ParsedAccount; - config: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; + config: ParsedAccount; position: number; }) { const [form] = Form.useForm(); diff --git a/packages/proposals/src/components/Proposal/SignButton.tsx b/packages/governance/src/components/Proposal/SignButton.tsx similarity index 92% rename from packages/proposals/src/components/Proposal/SignButton.tsx rename to packages/governance/src/components/Proposal/SignButton.tsx index 0e9ba8d..2d74b84 100644 --- a/packages/proposals/src/components/Proposal/SignButton.tsx +++ b/packages/governance/src/components/Proposal/SignButton.tsx @@ -3,7 +3,7 @@ import { ParsedAccount, hooks, contexts, utils } from '@oyster/common'; import { Button, Modal } from 'antd'; import React from 'react'; import { sign } from '../../actions/sign'; -import { TimelockSet, TimelockState } from '../../models/timelock'; +import { Proposal, ProposalState } from '../../models/governance'; const { confirm } = Modal; const { useWallet } = contexts.Wallet; @@ -15,8 +15,8 @@ export default function SignButton({ proposal, state, }: { - proposal: ParsedAccount; - state: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; }) { const wallet = useWallet(); const connection = useConnection(); diff --git a/packages/proposals/src/components/Proposal/StateBadge.tsx b/packages/governance/src/components/Proposal/StateBadge.tsx similarity index 67% rename from packages/proposals/src/components/Proposal/StateBadge.tsx rename to packages/governance/src/components/Proposal/StateBadge.tsx index 16098eb..9666210 100644 --- a/packages/proposals/src/components/Proposal/StateBadge.tsx +++ b/packages/governance/src/components/Proposal/StateBadge.tsx @@ -3,15 +3,15 @@ import { Badge, Tag } from 'antd'; import React from 'react'; import { STATE_COLOR, - TimelockState, - TimelockStateStatus, -} from '../../models/timelock'; + ProposalState, + ProposalStateStatus, +} from '../../models/governance'; export function StateBadgeRibbon({ state, children, }: { - state: ParsedAccount; + state: ParsedAccount; children?: any; }) { const status = state.info.status; @@ -19,19 +19,19 @@ export function StateBadgeRibbon({ return ( {children} ); } -export function StateBadge({ state }: { state: ParsedAccount }) { +export function StateBadge({ state }: { state: ParsedAccount }) { const status = state.info.status; let color = STATE_COLOR[status]; return ( - {TimelockStateStatus[status]} + {ProposalStateStatus[status]} ); } diff --git a/packages/proposals/src/components/Proposal/Vote.tsx b/packages/governance/src/components/Proposal/Vote.tsx similarity index 88% rename from packages/proposals/src/components/Proposal/Vote.tsx rename to packages/governance/src/components/Proposal/Vote.tsx index 630eb0e..76806cd 100644 --- a/packages/proposals/src/components/Proposal/Vote.tsx +++ b/packages/governance/src/components/Proposal/Vote.tsx @@ -2,11 +2,11 @@ import { ParsedAccount } from '@oyster/common'; import { Button, Col, Modal, Row } from 'antd'; import React from 'react'; import { - TimelockConfig, - TimelockSet, - TimelockState, - TimelockStateStatus, -} from '../../models/timelock'; + Governance, + Proposal, + ProposalState, + ProposalStateStatus, +} from '../../models/governance'; import { LABELS } from '../../constants'; import { depositSourceTokensAndVote } from '../../actions/depositSourceTokensAndVote'; import { contexts, hooks } from '@oyster/common'; @@ -22,12 +22,12 @@ const { confirm } = Modal; export function Vote({ proposal, state, - timelockConfig, + governance, yeahVote, }: { - proposal: ParsedAccount; - state: ParsedAccount; - timelockConfig: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; + governance: ParsedAccount; yeahVote: boolean; }) { const wallet = useWallet(); @@ -42,7 +42,7 @@ export function Vote({ const eligibleToView = userTokenAccount && userTokenAccount.info.amount.toNumber() > 0 && - state.info.status === TimelockStateStatus.Voting; + state.info.status === ProposalStateStatus.Voting; const [btnLabel, title, msg, icon] = yeahVote ? [ @@ -90,7 +90,7 @@ export function Vote({ yesVoteAccount?.pubkey, noVoteAccount?.pubkey, userTokenAccount.pubkey, - timelockConfig, + governance, state, yesTokenAmount, noTokenAmount, diff --git a/packages/proposals/src/components/Proposal/VoterBubbleGraph.tsx b/packages/governance/src/components/Proposal/VoterBubbleGraph.tsx similarity index 82% rename from packages/proposals/src/components/Proposal/VoterBubbleGraph.tsx rename to packages/governance/src/components/Proposal/VoterBubbleGraph.tsx index 2d7fee0..4dc236e 100644 --- a/packages/proposals/src/components/Proposal/VoterBubbleGraph.tsx +++ b/packages/governance/src/components/Proposal/VoterBubbleGraph.tsx @@ -14,10 +14,6 @@ const MAX_BUBBLE_AMOUNT = 50; export function VoterBubbleGraph(props: IVoterBubbleGraph) { const { data, width, height, endpoint } = props; - const subdomain = endpoint - .replace('http://', '') - .replace('https://', '') - .split('.')[0]; // For some reason giving this a type causes an issue where setRef // cant be used with ref={} prop...not sure why. SetStateAction nonsense. @@ -31,24 +27,30 @@ export function VoterBubbleGraph(props: IVoterBubbleGraph) { d.name.slice(d.name.length - 3, d.name.length), })); //console.log('Data', limitedData); - const format = d3.format(',d'); - const color = d3 - .scaleOrdinal() - .domain([VoteType.Undecided, VoteType.Yes, VoteType.No]) - .range(['grey', 'green', 'red']); - - const pack = (data: Array) => { - return d3 - .pack() - .size([width - 2, height - 2]) - .padding(3)( - //@ts-ignore - d3.hierarchy({ children: data }).sum(d => (d.value ? d.value : 0)), - ); - }; useEffect(() => { if (ref) { + const subdomain = endpoint + .replace('http://', '') + .replace('https://', '') + .split('.')[0]; + + const format = d3.format(',d'); + const color = d3 + .scaleOrdinal() + .domain([VoteType.Undecided, VoteType.Yes, VoteType.No]) + .range(['grey', 'green', 'red']); + + const pack = (data: Array) => { + return d3 + .pack() + .size([width - 2, height - 2]) + .padding(3)( + //@ts-ignore + d3.hierarchy({ children: data }).sum(d => (d.value ? d.value : 0)), + ); + }; + ref.innerHTML = ''; const root = pack(limitedData); // console.log('Re-rendered'); @@ -127,7 +129,7 @@ export function VoterBubbleGraph(props: IVoterBubbleGraph) { }${format(d.value)}`, ); } - }, [ref, limitedData, height, width]); + }, [ref, limitedData, height, width, endpoint]); return (
; - state: ParsedAccount; - timelockConfig: ParsedAccount; + proposal: ParsedAccount; + state: ParsedAccount; }) { const wallet = useWallet(); const connection = useConnection(); @@ -41,13 +39,13 @@ export function WithdrawVote({ const eligibleToView = votingTokens > 0 && - (state.info.status === TimelockStateStatus.Voting || - state.info.status === TimelockStateStatus.Completed || - state.info.status === TimelockStateStatus.Executing || - state.info.status === TimelockStateStatus.Defeated); + (state.info.status === ProposalStateStatus.Voting || + state.info.status === ProposalStateStatus.Completed || + state.info.status === ProposalStateStatus.Executing || + state.info.status === ProposalStateStatus.Defeated); const [btnLabel, title, msg, action] = - state.info.status === TimelockStateStatus.Voting + state.info.status === ProposalStateStatus.Voting ? [ LABELS.WITHDRAW_VOTE, LABELS.WITHDRAW_YOUR_VOTE_QUESTION, diff --git a/packages/proposals/src/components/Proposal/style.less b/packages/governance/src/components/Proposal/style.less similarity index 100% rename from packages/proposals/src/components/Proposal/style.less rename to packages/governance/src/components/Proposal/style.less diff --git a/packages/proposals/src/constants/index.tsx b/packages/governance/src/constants/index.tsx similarity index 100% rename from packages/proposals/src/constants/index.tsx rename to packages/governance/src/constants/index.tsx diff --git a/packages/proposals/src/constants/labels.ts b/packages/governance/src/constants/labels.ts similarity index 99% rename from packages/proposals/src/constants/labels.ts rename to packages/governance/src/constants/labels.ts index 81fc4cd..8054d73 100644 --- a/packages/proposals/src/constants/labels.ts +++ b/packages/governance/src/constants/labels.ts @@ -99,7 +99,10 @@ export const LABELS = { TOKENS_REFUNDED: 'Your voting tokens have been refunded', REGISTER_GOVERNANCE: 'Register', - PROGRAM: 'Program ID', + + PROGRAM_ID: 'Program ID', + INSTRUCTION: 'Instruction', + GOVERNANCE: 'Governance Token Holders', COUNCIL: 'The Council', GOVERNANCE_MINT: 'Governance Mint ID', diff --git a/packages/proposals/src/constants/style.tsx b/packages/governance/src/constants/style.tsx similarity index 100% rename from packages/proposals/src/constants/style.tsx rename to packages/governance/src/constants/style.tsx diff --git a/packages/proposals/src/contexts/proposals.tsx b/packages/governance/src/contexts/proposals.tsx similarity index 57% rename from packages/proposals/src/contexts/proposals.tsx rename to packages/governance/src/contexts/proposals.tsx index b1d6569..b5920e0 100644 --- a/packages/proposals/src/contexts/proposals.tsx +++ b/packages/governance/src/contexts/proposals.tsx @@ -15,26 +15,26 @@ import { cache, } from '@oyster/common'; import { - CustomSingleSignerTimelockTransactionLayout, - CustomSingleSignerTimelockTransactionParser, - TimelockConfig, - TimelockConfigLayout, - TimelockConfigParser, - TimelockSet, - TimelockState, - TimelockSetLayout, - TimelockSetParser, - TimelockTransaction, - TimelockStateParser, - TimelockStateLayout, - CustomSingleSignerTimelockTransaction, -} from '../models/timelock'; + CustomSingleSignerTransactionLayout, + CustomSingleSignerTransactionParser, + Governance, + GovernanceLayout, + GovernanceParser, + Proposal, + ProposalState, + ProposalLayout, + ProposalParser, + GovernanceTransaction, + ProposalStateParser, + ProposalStateLayout, + CustomSingleSignerTransaction, +} from '../models/governance'; export interface ProposalsContextState { - proposals: Record>; - transactions: Record>; - states: Record>; - configs: Record>; + proposals: Record>; + transactions: Record>; + states: Record>; + configs: Record>; } export const ProposalsContext = React.createContext( @@ -82,49 +82,47 @@ function useSetupProposalsCache({ setStates: React.Dispatch>; setConfigs: React.Dispatch>; }) { - const PROGRAM_IDS = utils.programIds(); - useEffect(() => { + const PROGRAM_IDS = utils.programIds(); + const query = async () => { const programAccounts = await connection.getProgramAccounts( - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); return programAccounts; }; Promise.all([query()]).then((all: PublicKeyAndAccount[][]) => { - const newProposals: Record> = {}; + const newProposals: Record> = {}; const newTransactions: Record< string, - ParsedAccount + ParsedAccount > = {}; - const newStates: Record> = {}; - const newConfigs: Record> = {}; + const newStates: Record> = {}; + const newConfigs: Record> = {}; all[0].forEach(a => { let cached; switch (a.account.data.length) { - case TimelockSetLayout.span: - cache.add(a.pubkey, a.account, TimelockSetParser); - cached = cache.get(a.pubkey) as ParsedAccount; + case ProposalLayout.span: + cache.add(a.pubkey, a.account, ProposalParser); + cached = cache.get(a.pubkey) as ParsedAccount; newProposals[a.pubkey.toBase58()] = cached; break; - case CustomSingleSignerTimelockTransactionLayout.span: - cache.add( + case CustomSingleSignerTransactionLayout.span: + cache.add(a.pubkey, a.account, CustomSingleSignerTransactionParser); + cached = cache.get( a.pubkey, - a.account, - CustomSingleSignerTimelockTransactionParser, - ); - cached = cache.get(a.pubkey) as ParsedAccount; + ) as ParsedAccount; newTransactions[a.pubkey.toBase58()] = cached; break; - case TimelockConfigLayout.span: - cache.add(a.pubkey, a.account, TimelockConfigParser); - cached = cache.get(a.pubkey) as ParsedAccount; + case GovernanceLayout.span: + cache.add(a.pubkey, a.account, GovernanceParser); + cached = cache.get(a.pubkey) as ParsedAccount; newConfigs[a.pubkey.toBase58()] = cached; break; - case TimelockStateLayout.span: - cache.add(a.pubkey, a.account, TimelockStateParser); - cached = cache.get(a.pubkey) as ParsedAccount; + case ProposalStateLayout.span: + cache.add(a.pubkey, a.account, ProposalStateParser); + cached = cache.get(a.pubkey) as ParsedAccount; newStates[a.pubkey.toBase58()] = cached; break; } @@ -136,46 +134,42 @@ function useSetupProposalsCache({ setConfigs(newConfigs); }); const subID = connection.onProgramAccountChange( - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, async (info: KeyedAccountInfo) => { const pubkey = typeof info.accountId === 'string' ? new PublicKey((info.accountId as unknown) as string) : info.accountId; [ - [TimelockSetLayout.span, TimelockSetParser, setProposals], + [ProposalLayout.span, ProposalParser, setProposals], [ - CustomSingleSignerTimelockTransactionLayout.span, - CustomSingleSignerTimelockTransactionParser, + CustomSingleSignerTransactionLayout.span, + CustomSingleSignerTransactionParser, setTransactions, ], - [TimelockStateLayout.span, TimelockStateParser, setStates], - [TimelockConfigLayout.span, TimelockConfigParser, setConfigs], + [ProposalStateLayout.span, ProposalStateParser, setStates], + [GovernanceLayout.span, GovernanceParser, setConfigs], ].forEach(arr => { const [span, parser, setter] = arr; if (info.accountInfo.data.length === span) { cache.add(info.accountId, info.accountInfo, parser); let cached: any; switch (info.accountInfo.data.length) { - case TimelockSetLayout.span: - cached = cache.get( - pubkey, - ) as ParsedAccount; + case ProposalLayout.span: + cached = cache.get(info.accountId) as ParsedAccount; break; - case CustomSingleSignerTimelockTransactionLayout.span: + case CustomSingleSignerTransactionLayout.span: cached = cache.get( - pubkey, - ) as ParsedAccount; + info.accountId, + ) as ParsedAccount; break; - case TimelockConfigLayout.span: - cached = cache.get( - pubkey, - ) as ParsedAccount; + case GovernanceLayout.span: + cached = cache.get(info.accountId) as ParsedAccount; break; - case TimelockStateLayout.span: + case ProposalStateLayout.span: cached = cache.get( - pubkey, - ) as ParsedAccount; + info.accountId, + ) as ParsedAccount; break; } setter((obj: any) => ({ @@ -190,7 +184,7 @@ function useSetupProposalsCache({ return () => { connection.removeProgramAccountChangeListener(subID); }; - }, [connection, PROGRAM_IDS.timelock.programId.toBase58()]); + }, [connection]); //eslint-disable-line } export const useProposals = () => { const context = useContext(ProposalsContext); diff --git a/packages/proposals/src/hooks/useVotingRecords.ts b/packages/governance/src/hooks/useVotingRecords.ts similarity index 90% rename from packages/proposals/src/hooks/useVotingRecords.ts rename to packages/governance/src/hooks/useVotingRecords.ts index a9b814d..23c64ed 100644 --- a/packages/proposals/src/hooks/useVotingRecords.ts +++ b/packages/governance/src/hooks/useVotingRecords.ts @@ -11,7 +11,7 @@ import { GovernanceVotingRecord, GovernanceVotingRecordLayout, GovernanceVotingRecordParser, -} from '../models/timelock'; +} from '../models/governance'; import { getGovernanceVotingRecords } from '../utils/lookups'; export function useVotingRecords(proposal: PublicKey) { @@ -31,9 +31,9 @@ export function useVotingRecords(proposal: PublicKey) { const records = await getGovernanceVotingRecords(proposal, endpoint); setVotingRecords(records); - const { timelock } = utils.programIds(); + const { governance } = utils.programIds(); - return connection.onProgramAccountChange(timelock.programId, info => { + return connection.onProgramAccountChange(governance.programId, info => { if ( info.accountInfo.data.length === GovernanceVotingRecordLayout.span ) { diff --git a/packages/proposals/src/index.tsx b/packages/governance/src/index.tsx similarity index 100% rename from packages/proposals/src/index.tsx rename to packages/governance/src/index.tsx diff --git a/packages/proposals/src/manifest.json b/packages/governance/src/manifest.json similarity index 84% rename from packages/proposals/src/manifest.json rename to packages/governance/src/manifest.json index adc115d..87bc3cd 100644 --- a/packages/proposals/src/manifest.json +++ b/packages/governance/src/manifest.json @@ -1,6 +1,6 @@ { - "name": "Oyster Proposals", - "short_name": "Oyster Proposals", + "name": "Oyster Governance", + "short_name": "Oyster Governance", "display": "standalone", "start_url": "./", "theme_color": "#002140", diff --git a/packages/proposals/src/models/addCustomSingleSignerTransaction.ts b/packages/governance/src/models/addCustomSingleSignerTransaction.ts similarity index 70% rename from packages/proposals/src/models/addCustomSingleSignerTransaction.ts rename to packages/governance/src/models/addCustomSingleSignerTransaction.ts index e15890f..b75c125 100644 --- a/packages/proposals/src/models/addCustomSingleSignerTransaction.ts +++ b/packages/governance/src/models/addCustomSingleSignerTransaction.ts @@ -5,32 +5,32 @@ import * as Layout from '../utils/layout'; import * as BufferLayout from 'buffer-layout'; import { INSTRUCTION_LIMIT, - TimelockInstruction, - TRANSACTION_SLOTS, -} from './timelock'; + GovernanceInstruction, + MAX_TRANSACTIONS, +} from './governance'; import BN from 'bn.js'; /// [Requires Signatory token] -/// Adds a Transaction to the Timelock Set. Max of 10 of any Transaction type. More than 10 will throw error. +/// Adds a Transaction to the Proposal. Max of 10 of any Transaction type. More than 10 will throw error. /// Creates a PDA using your authority to be used to later execute the instruction. /// This transaction needs to contain authority to execute the program. /// -/// 0. `[writable]` Uninitialized Timelock Transaction account. -/// 1. `[writable]` Timelock set account. +/// 0. `[writable]` Uninitialized Proposal Transaction account. +/// 1. `[writable]` Proposal account. /// 2. `[writable]` Signatory account /// 3. `[writable]` Signatory validation account. -/// 4. `[]` Timelock Set account. -/// 5. `[]` Timelock Config account. +/// 4. `[]` Proposal account. +/// 5. `[]` Governance account. /// 6. `[]` Transfer authority -/// 7. `[]` Timelock mint authority +/// 7. `[]` Governance mint authority /// 8. `[]` Token program account. export const addCustomSingleSignerTransactionInstruction = ( - timelockTransactionAccount: PublicKey, - timelockStateAccount: PublicKey, + proposalTransactionAccount: PublicKey, + proposalStateAccount: PublicKey, signatoryAccount: PublicKey, signatoryValidationAccount: PublicKey, - timelockSetAccount: PublicKey, - timelockConfigAccount: PublicKey, + proposalAccount: PublicKey, + governanceAccount: PublicKey, transferAuthority: PublicKey, authority: PublicKey, slot: string, @@ -53,9 +53,9 @@ export const addCustomSingleSignerTransactionInstruction = ( ); } - if (position > TRANSACTION_SLOTS) { + if (position > MAX_TRANSACTIONS) { throw new Error( - 'Position is more than ' + TRANSACTION_SLOTS + ' which is not allowed.', + 'Position is more than ' + MAX_TRANSACTIONS + ' which is not allowed.', ); } @@ -75,7 +75,7 @@ export const addCustomSingleSignerTransactionInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.AddCustomSingleSignerTransaction, + instruction: GovernanceInstruction.AddCustomSingleSignerTransaction, slot: new BN(slot), instructions: instructionAsBytes, position: position, @@ -85,12 +85,12 @@ export const addCustomSingleSignerTransactionInstruction = ( ); const keys = [ - { pubkey: timelockTransactionAccount, isSigner: true, isWritable: true }, - { pubkey: timelockStateAccount, isSigner: false, isWritable: true }, + { pubkey: proposalTransactionAccount, isSigner: true, isWritable: true }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: true }, { pubkey: signatoryAccount, isSigner: false, isWritable: true }, { pubkey: signatoryValidationAccount, isSigner: false, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, - { pubkey: timelockConfigAccount, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, + { pubkey: governanceAccount, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: authority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, @@ -98,7 +98,7 @@ export const addCustomSingleSignerTransactionInstruction = ( return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/addSigner.ts b/packages/governance/src/models/addSigner.ts similarity index 73% rename from packages/proposals/src/models/addSigner.ts rename to packages/governance/src/models/addSigner.ts index 244354e..e785c8d 100644 --- a/packages/proposals/src/models/addSigner.ts +++ b/packages/governance/src/models/addSigner.ts @@ -1,10 +1,10 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; /// [Requires Admin token] -/// Adds a signatory to the Timelock which means that this timelock can't leave Draft state until yet another signatory burns +/// Adds a signatory to the Proposal which means that this Proposal can't leave Draft state until yet another signatory burns /// their signatory token indicating they are satisfied with the instruction queue. They'll receive an signatory token /// as a result of this call that they can burn later. /// @@ -12,18 +12,18 @@ import { TimelockInstruction } from './timelock'; /// 1. `[writable]` Initialized Signatory mint account. /// 2. `[writable]` Admin account. /// 3. `[writable]` Admin validation account. -/// 4. `[writable]` Timelock set account. -/// 5. `[]` Timelock set account. +/// 4. `[writable]` Proposal account. +/// 5. `[]` Proposal account. /// 6. `[]` Transfer authority -/// 7. `[]` Timelock program mint authority +/// 7. `[]` Governance program mint authority /// 8. '[]` Token program id. export const addSignerInstruction = ( signatoryAccount: PublicKey, signatoryMintAccount: PublicKey, adminAccount: PublicKey, adminValidationAccount: PublicKey, - timelockStateAccount: PublicKey, - timelockSetAccount: PublicKey, + proposalStateAccount: PublicKey, + proposalAccount: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, ): TransactionInstruction => { @@ -35,7 +35,7 @@ export const addSignerInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.AddSigner, + instruction: GovernanceInstruction.AddSigner, }, data, ); @@ -45,15 +45,15 @@ export const addSignerInstruction = ( { pubkey: signatoryMintAccount, isSigner: false, isWritable: true }, { pubkey: adminAccount, isSigner: false, isWritable: true }, { pubkey: adminValidationAccount, isSigner: false, isWritable: true }, - { pubkey: timelockStateAccount, isSigner: false, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: true }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/createEmptyTimelockConfig.ts b/packages/governance/src/models/createEmptyGovernance.ts similarity index 55% rename from packages/proposals/src/models/createEmptyTimelockConfig.ts rename to packages/governance/src/models/createEmptyGovernance.ts index 29d594a..a46a193 100644 --- a/packages/proposals/src/models/createEmptyTimelockConfig.ts +++ b/packages/governance/src/models/createEmptyGovernance.ts @@ -1,18 +1,18 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; -/// 0. `[]` Timelock config key. Needs to be set with pubkey set to PDA with seeds of the -/// program account key, governance mint key, council mint key, and timelock program account key. -/// 1. `[]` Program account to tie this config to. -/// 2. `[]` Governance mint to tie this config to -/// 3. `[]` Payer -/// 4. `[]` Timelock program pub key. +/// 0. `[]` Governance account. The account pubkey needs to be set to PDA with the following seeds: +/// 1) 'governance' const prefix, 2) Governed Program account key +/// 1. `[]` Account of the Program governed by this Governance account +/// 2. `[writable]` Program Data account of the Program governed by this Governance account +/// 3. `[signer]` Current Upgrade Authority account of the Program governed by this Governance account +/// 4. `[signer]` Payer /// 5. `[]` System account. -/// 6. `[]` Council mint [optional] to tie this config to [Optional] -export const createEmptyTimelockConfigInstruction = ( - timelockConfigAccount: PublicKey, +/// 6. `[]` bpf_upgrade_loader account. +export const createEmptyGovernanceInstruction = ( + governanceAccount: PublicKey, programAccount: PublicKey, programDataAccount: PublicKey, programUpgradeAuthority: PublicKey, @@ -28,17 +28,17 @@ export const createEmptyTimelockConfigInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.CreateEmptyTimelockConfig, + instruction: GovernanceInstruction.CreateEmptyGovernance, }, data, ); const keys = [ - { pubkey: timelockConfigAccount, isSigner: false, isWritable: false }, + { pubkey: governanceAccount, isSigner: false, isWritable: false }, { pubkey: programAccount, isSigner: false, isWritable: false }, { pubkey: programDataAccount, isSigner: false, isWritable: true }, { pubkey: programUpgradeAuthority, isSigner: true, isWritable: false }, - { pubkey: governanceMint, isSigner: false, isWritable: false }, + { pubkey: payer, isSigner: true, isWritable: false }, { pubkey: PROGRAM_IDS.system, isSigner: false, isWritable: false }, { @@ -48,13 +48,9 @@ export const createEmptyTimelockConfigInstruction = ( }, ]; - if (councilMint) { - keys.push({ pubkey: councilMint, isSigner: false, isWritable: false }); - } - return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/createEmptyGovernanceVotingRecord.ts b/packages/governance/src/models/createEmptyGovernanceVotingRecord.ts similarity index 83% rename from packages/proposals/src/models/createEmptyGovernanceVotingRecord.ts rename to packages/governance/src/models/createEmptyGovernanceVotingRecord.ts index 9326817..4a3a813 100644 --- a/packages/proposals/src/models/createEmptyGovernanceVotingRecord.ts +++ b/packages/governance/src/models/createEmptyGovernanceVotingRecord.ts @@ -1,14 +1,14 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; /// 0. `[]` Governance voting record key. Needs to be set with pubkey set to PDA with seeds of the /// program account key, proposal key, your voting account key. /// 1. `[]` Proposal key /// 2. `[]` Your voting account /// 3. `[]` Payer -/// 4. `[]` Timelock program pub key. +/// 4. `[]` Governance program pub key /// 5. `[]` System account. export const createEmptyGovernanceVotingRecordInstruction = ( governanceRecordAccount: PublicKey, @@ -24,7 +24,7 @@ export const createEmptyGovernanceVotingRecordInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.CreateGovernanceVotingRecord, + instruction: GovernanceInstruction.CreateGovernanceVotingRecord, }, data, ); @@ -35,7 +35,7 @@ export const createEmptyGovernanceVotingRecordInstruction = ( { pubkey: votingAccount, isSigner: false, isWritable: false }, { pubkey: payer, isSigner: true, isWritable: false }, { - pubkey: PROGRAM_IDS.timelock.programId, + pubkey: PROGRAM_IDS.governance.programId, isSigner: false, isWritable: false, }, @@ -43,7 +43,7 @@ export const createEmptyGovernanceVotingRecordInstruction = ( ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/depositSourceTokens.ts b/packages/governance/src/models/depositSourceTokens.ts similarity index 79% rename from packages/proposals/src/models/depositSourceTokens.ts rename to packages/governance/src/models/depositSourceTokens.ts index 371d8e6..4ccef75 100644 --- a/packages/proposals/src/models/depositSourceTokens.ts +++ b/packages/governance/src/models/depositSourceTokens.ts @@ -3,22 +3,22 @@ import { utils } from '@oyster/common'; import * as Layout from '../utils/layout'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; import BN from 'bn.js'; -/// [Requires tokens of the Governance mint or Council mint depending on type of TimelockSet] -/// Deposits voting tokens to be used during the voting process in a timelock. +/// [Requires tokens of the Governance mint or Council mint depending on type of Proposal] +/// Deposits voting tokens to be used during the voting process in a Proposal. /// These tokens are removed from your account and can be returned by withdrawing -/// them from the timelock (but then you will miss the vote.) +/// them from the Proposal (but then you will miss the vote.) /// /// 0. `[writable]` Governance voting record account. See Vote docs for more detail. /// 1. `[writable]` Initialized Voting account to hold your received voting tokens. /// 2. `[writable]` User token account to deposit tokens from. -/// 3. `[writable]` Source holding account for timelock that will accept the tokens in escrow. +/// 3. `[writable]` Source holding account for Proposal that will accept the tokens in escrow. /// 4. `[writable]` Voting mint account. -/// 5. `[]` Timelock set account. +/// 5. `[]` Proposal account. /// 6. `[]` Transfer authority -/// 7. `[]` Timelock program mint authority +/// 7. `[]` Governance program mint authority (pda with seed of Proposal key) /// 8. `[]` Token program account. export const depositSourceTokensInstruction = ( governanceVotingRecord: PublicKey, @@ -26,7 +26,7 @@ export const depositSourceTokensInstruction = ( sourceAccount: PublicKey, sourceHoldingAccount: PublicKey, votingMint: PublicKey, - timelockSetAccount: PublicKey, + proposalAccount: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, votingTokenAmount: number, @@ -42,7 +42,7 @@ export const depositSourceTokensInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.DepositGovernanceTokens, + instruction: GovernanceInstruction.DepositGovernanceTokens, votingTokenAmount: new BN(votingTokenAmount), }, data, @@ -54,7 +54,7 @@ export const depositSourceTokensInstruction = ( { pubkey: sourceAccount, isSigner: false, isWritable: true }, { pubkey: sourceHoldingAccount, isSigner: false, isWritable: true }, { pubkey: votingMint, isSigner: false, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, @@ -62,7 +62,7 @@ export const depositSourceTokensInstruction = ( return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/execute.ts b/packages/governance/src/models/execute.ts similarity index 66% rename from packages/proposals/src/models/execute.ts rename to packages/governance/src/models/execute.ts index 5a56361..8863120 100644 --- a/packages/proposals/src/models/execute.ts +++ b/packages/governance/src/models/execute.ts @@ -5,23 +5,24 @@ import { } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; -/// Executes a command in the timelock set. +/// Executes a command in the Proposal /// /// 0. `[writable]` Transaction account you wish to execute. -/// 1. `[writable]` Timelock state account. +/// 1. `[writable]` Proposal state account. /// 2. `[]` Program being invoked account -/// 3. `[]` Timelock set account. -/// 4. `[]` Timelock config -/// 5. `[]` Clock sysvar. +/// 3. `[]` Proposal account. +/// 4. `[]` Governance account +/// 5. `[]` Governance program account pub key. +/// 6. `[]` Clock sysvar. /// 7+ Any extra accounts that are part of the instruction, in order export const executeInstruction = ( transactionAccount: PublicKey, - timelockStateAccount: PublicKey, - timelockSetAccount: PublicKey, + proposalStateAccount: PublicKey, + proposalAccount: PublicKey, programBeingInvokedAccount: PublicKey, - timelockConfig: PublicKey, + governance: PublicKey, accountInfos: { pubkey: PublicKey; isWritable: boolean; isSigner: boolean }[], ): TransactionInstruction => { const PROGRAM_IDS = utils.programIds(); @@ -35,7 +36,7 @@ export const executeInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.Execute, + instruction: GovernanceInstruction.Execute, numberOfExtraAccounts: accountInfos.length, }, data, @@ -44,16 +45,16 @@ export const executeInstruction = ( const keys = [ // just a note this were all set to writable true...come back and check on this { pubkey: transactionAccount, isSigner: false, isWritable: true }, - { pubkey: timelockStateAccount, isSigner: false, isWritable: true }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: true }, { pubkey: programBeingInvokedAccount, isSigner: false, isWritable: false }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, - { pubkey: timelockConfig, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, + { pubkey: governance, isSigner: false, isWritable: false }, { pubkey: SYSVAR_CLOCK_PUBKEY, isSigner: false, isWritable: false }, ...accountInfos, ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/timelock.ts b/packages/governance/src/models/governance.ts similarity index 81% rename from packages/proposals/src/models/timelock.ts rename to packages/governance/src/models/governance.ts index 19996fe..3f32591 100644 --- a/packages/proposals/src/models/timelock.ts +++ b/packages/governance/src/models/governance.ts @@ -8,25 +8,25 @@ export const DESC_SIZE = 200; export const NAME_SIZE = 32; export const CONFIG_NAME_LENGTH = 32; export const INSTRUCTION_LIMIT = 450; -export const TRANSACTION_SLOTS = 5; +export const MAX_TRANSACTIONS = 5; export const TEMP_FILE_TXN_SIZE = 1000; /// Seed for proposal authority export const GOVERNANCE_AUTHORITY_SEED = 'governance'; -export enum TimelockInstruction { - InitTimelockSet = 1, +export enum GovernanceInstruction { + InitProposal = 1, AddSigner = 2, RemoveSigner = 3, AddCustomSingleSignerTransaction = 4, Sign = 8, Vote = 9, - InitTimelockConfig = 10, + InitGovernance = 10, Execute = 11, DepositGovernanceTokens = 12, WithdrawVotingTokens = 13, - CreateEmptyTimelockConfig = 14, + CreateEmptyGovernance = 14, CreateGovernanceVotingRecord = 15, } @@ -58,15 +58,15 @@ export const GovernanceVotingRecordLayout: typeof BufferLayout.Structure = Buffe ], ); -export interface TimelockConfig { +export interface Governance { /// Account type accountType: GovernanceAccountType; /// Vote threshold voteThreshold: number; /// Execution type executionType: ExecutionType; - /// Timelock Type - timelockType: TimelockType; + /// Governance Type + governanceType: GovernanceType; /// Voting entry rule votingEntryRule: VotingEntryRule; /// Minimum slot time-distance from creation of proposal for an instruction to be placed @@ -94,12 +94,12 @@ export enum GovernanceAccountType { CustomSingleSignerTransaction = 5, } -export const TimelockConfigLayout: typeof BufferLayout.Structure = BufferLayout.struct( +export const GovernanceLayout: typeof BufferLayout.Structure = BufferLayout.struct( [ BufferLayout.u8('accountType'), BufferLayout.u8('voteThreshold'), BufferLayout.u8('executionType'), - BufferLayout.u8('timelockType'), + BufferLayout.u8('governanceType'), BufferLayout.u8('votingEntryRule'), Layout.uint64('minimumSlotWaitingPeriod'), Layout.publicKey('governanceMint'), @@ -121,11 +121,11 @@ export enum ExecutionType { Independent = 0, } -export enum TimelockType { - CustomSingleSignerV1 = 0, +export enum GovernanceType { + Governance = 0, } -export enum TimelockStateStatus { +export enum ProposalStateStatus { /// Draft Draft = 0, /// Taking votes @@ -145,21 +145,21 @@ export enum TimelockStateStatus { } export const STATE_COLOR: Record = { - [TimelockStateStatus.Draft]: 'orange', - [TimelockStateStatus.Voting]: 'blue', - [TimelockStateStatus.Executing]: 'green', - [TimelockStateStatus.Completed]: 'purple', - [TimelockStateStatus.Deleted]: 'gray', - [TimelockStateStatus.Defeated]: 'red', + [ProposalStateStatus.Draft]: 'orange', + [ProposalStateStatus.Voting]: 'blue', + [ProposalStateStatus.Executing]: 'green', + [ProposalStateStatus.Completed]: 'purple', + [ProposalStateStatus.Deleted]: 'gray', + [ProposalStateStatus.Defeated]: 'red', }; -export interface TimelockState { +export interface ProposalState { /// Account type accountType: GovernanceAccountType; - timelockSet: PublicKey; - status: TimelockStateStatus; + proposal: PublicKey; + status: ProposalStateStatus; totalSigningTokensMinted: BN; - timelockTransactions: PublicKey[]; + proposalTransactions: PublicKey[]; name: string; descLink: string; votingEndedAt: BN; @@ -171,12 +171,12 @@ export interface TimelockState { usedTxnSlots: number; } -const timelockTxns = []; -for (let i = 0; i < TRANSACTION_SLOTS; i++) { - timelockTxns.push(Layout.publicKey('timelockTxn' + i.toString())); +const proposalTxns = []; +for (let i = 0; i < MAX_TRANSACTIONS; i++) { + proposalTxns.push(Layout.publicKey('proposalTxn' + i.toString())); } -export const TimelockSetLayout: typeof BufferLayout.Structure = BufferLayout.struct( +export const ProposalLayout: typeof BufferLayout.Structure = BufferLayout.struct( [ BufferLayout.u8('accountType'), Layout.publicKey('config'), @@ -198,11 +198,11 @@ export const TimelockSetLayout: typeof BufferLayout.Structure = BufferLayout.str ], ); -export const TimelockStateLayout: typeof BufferLayout.Structure = BufferLayout.struct( +export const ProposalStateLayout: typeof BufferLayout.Structure = BufferLayout.struct( [ BufferLayout.u8('accountType'), - Layout.publicKey('timelockSet'), - BufferLayout.u8('timelockStateStatus'), + Layout.publicKey('proposal'), + BufferLayout.u8('proposalStateStatus'), Layout.uint64('totalSigningTokensMinted'), BufferLayout.seq(BufferLayout.u8(), DESC_SIZE, 'descLink'), BufferLayout.seq(BufferLayout.u8(), NAME_SIZE, 'name'), @@ -213,12 +213,12 @@ export const TimelockStateLayout: typeof BufferLayout.Structure = BufferLayout.s Layout.uint64('deletedAt'), BufferLayout.u8('executions'), BufferLayout.u8('usedTxnSlots'), - ...timelockTxns, + ...proposalTxns, BufferLayout.seq(BufferLayout.u8(), 300, 'padding'), ], ); -export interface TimelockSet { +export interface Proposal { /// Account type accountType: GovernanceAccountType; @@ -270,7 +270,7 @@ export interface TimelockSet { noVotingDump: PublicKey; } -export const CustomSingleSignerTimelockTransactionLayout: typeof BufferLayout.Structure = BufferLayout.struct( +export const CustomSingleSignerTransactionLayout: typeof BufferLayout.Structure = BufferLayout.struct( [ BufferLayout.u8('accountType'), Layout.uint64('slot'), @@ -281,7 +281,7 @@ export const CustomSingleSignerTimelockTransactionLayout: typeof BufferLayout.St ], ); -export interface TimelockTransaction { +export interface GovernanceTransaction { /// Account type accountType: GovernanceAccountType; @@ -293,15 +293,14 @@ export interface TimelockTransaction { instructionEndIndex: number; } -export interface CustomSingleSignerTimelockTransaction - extends TimelockTransaction {} +export interface CustomSingleSignerTransaction extends GovernanceTransaction {} -export const TimelockSetParser = ( +export const ProposalParser = ( pubKey: PublicKey, info: AccountInfo, ) => { const buffer = Buffer.from(info.data); - const data = TimelockSetLayout.decode(buffer); + const data = ProposalLayout.decode(buffer); const details = { pubkey: pubKey, account: { @@ -354,16 +353,16 @@ export const GovernanceVotingRecordParser = ( return details; }; -export const TimelockStateParser = ( +export const ProposalStateParser = ( pubKey: PublicKey, info: AccountInfo, ) => { const buffer = Buffer.from(info.data); - const data = TimelockStateLayout.decode(buffer); + const data = ProposalStateLayout.decode(buffer); - const timelockTxns = []; - for (let i = 0; i < TRANSACTION_SLOTS; i++) { - timelockTxns.push(data['timelockTxn' + i.toString()]); + const proposalTxns = []; + for (let i = 0; i < MAX_TRANSACTIONS; i++) { + proposalTxns.push(data['proposalTxn' + i.toString()]); } const details = { @@ -373,12 +372,12 @@ export const TimelockStateParser = ( }, info: { accountType: data.accountType, - timelockSet: data.timelockSet, - status: data.timelockStateStatus, + proposal: data.proposal, + status: data.proposalStateStatus, totalSigningTokensMinted: data.totalSigningTokensMinted, descLink: utils.fromUTF8Array(data.descLink).replaceAll('\u0000', ''), name: utils.fromUTF8Array(data.name).replaceAll('\u0000', ''), - timelockTransactions: timelockTxns, + proposalTransactions: proposalTxns, votingEndedAt: data.votingEndedAt, votingBeganAt: data.votingBeganAt, createdAt: data.createdAt, @@ -392,12 +391,12 @@ export const TimelockStateParser = ( return details; }; -export const CustomSingleSignerTimelockTransactionParser = ( +export const CustomSingleSignerTransactionParser = ( pubKey: PublicKey, info: AccountInfo, ) => { const buffer = Buffer.from(info.data); - const data = CustomSingleSignerTimelockTransactionLayout.decode(buffer); + const data = CustomSingleSignerTransactionLayout.decode(buffer); const details = { pubkey: pubKey, @@ -417,12 +416,12 @@ export const CustomSingleSignerTimelockTransactionParser = ( return details; }; -export const TimelockConfigParser = ( +export const GovernanceParser = ( pubKey: PublicKey, info: AccountInfo, ) => { const buffer = Buffer.from(info.data); - const data = TimelockConfigLayout.decode(buffer); + const data = GovernanceLayout.decode(buffer); const details = { pubkey: pubKey, @@ -433,7 +432,7 @@ export const TimelockConfigParser = ( accountType: data.accountType, voteThreshold: data.voteThreshold, executionType: data.executionType, - timelockType: data.timelockType, + governanceType: data.governanceType, votingEntryRule: data.votingEntryRule, minimumSlotWaitingPeriod: data.minimumSlotWaitingPeriod, governanceMint: data.governanceMint, diff --git a/packages/proposals/src/models/initTimelockConfig.ts b/packages/governance/src/models/initGovernance.ts similarity index 68% rename from packages/proposals/src/models/initTimelockConfig.ts rename to packages/governance/src/models/initGovernance.ts index eead19f..f6f33d5 100644 --- a/packages/proposals/src/models/initTimelockConfig.ts +++ b/packages/governance/src/models/initGovernance.ts @@ -1,22 +1,22 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { CONFIG_NAME_LENGTH, TimelockInstruction } from './timelock'; +import { CONFIG_NAME_LENGTH, GovernanceInstruction } from './governance'; import BN from 'bn.js'; import * as Layout from '../utils/layout'; -/// 0. `[writable]` Timelock config key. Needs to be set with pubkey set to PDA with seeds of the -/// program account key, governance mint key, council mint key, timelock program account key. -/// 1. `[]` Program account that this config uses -/// 2. `[]` Governance mint that this config uses -/// 3. `[]` Council mint that this config uses [Optional] -export const initTimelockConfigInstruction = ( - timelockConfigAccount: PublicKey, +/// 0. `[writable]` Governance account. The account pubkey needs to be set to PDA with the following seeds: +/// 1) 'governance' const prefix, 2) Governed Program account key +/// 1. `[]` Account of the Program governed by this Governance account +/// 2. `[]` Governance mint that this Governance uses +/// 3. `[]` Council mint that this Governance uses [Optional] +export const initGovernanceInstruction = ( + governanceAccount: PublicKey, programAccount: PublicKey, governanceMint: PublicKey, voteThreshold: number, executionType: number, - timelockType: number, + governanceType: number, votingEntryRule: number, minimumSlotWaitingPeriod: BN, timeLimit: BN, @@ -33,7 +33,7 @@ export const initTimelockConfigInstruction = ( BufferLayout.u8('instruction'), BufferLayout.u8('voteThreshold'), BufferLayout.u8('executionType'), - BufferLayout.u8('timelockType'), + BufferLayout.u8('governanceType'), BufferLayout.u8('votingEntryRule'), Layout.uint64('minimumSlotWaitingPeriod'), Layout.uint64('timeLimit'), @@ -49,10 +49,10 @@ export const initTimelockConfigInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.InitTimelockConfig, + instruction: GovernanceInstruction.InitGovernance, voteThreshold, executionType, - timelockType, + governanceType, votingEntryRule, minimumSlotWaitingPeriod, timeLimit, @@ -62,7 +62,7 @@ export const initTimelockConfigInstruction = ( ); const keys = [ - { pubkey: timelockConfigAccount, isSigner: false, isWritable: true }, + { pubkey: governanceAccount, isSigner: false, isWritable: true }, { pubkey: programAccount, isSigner: false, isWritable: false }, { pubkey: governanceMint, isSigner: false, isWritable: false }, ]; @@ -73,7 +73,7 @@ export const initTimelockConfigInstruction = ( return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/initTimelockSet.ts b/packages/governance/src/models/initProposal.ts similarity index 81% rename from packages/proposals/src/models/initTimelockSet.ts rename to packages/governance/src/models/initProposal.ts index 8feda01..262a2d8 100644 --- a/packages/proposals/src/models/initTimelockSet.ts +++ b/packages/governance/src/models/initProposal.ts @@ -5,14 +5,14 @@ import { } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { DESC_SIZE, NAME_SIZE, TimelockInstruction } from './timelock'; +import { DESC_SIZE, NAME_SIZE, GovernanceInstruction } from './governance'; -/// Initializes a new empty Timelocked set of Instructions that will be executed at various slots in the future in draft mode. +/// Initializes a new empty Proposal for Instructions that will be executed at various slots in the future in draft mode. /// Grants Admin token to caller. /// -/// 0. `[writable]` Uninitialized Timelock state account . -/// 1. `[writable]` Uninitialized Timelock set account . -/// 2. `[writable]` Initialized Timelock config account. +/// 0. `[writable]` Uninitialized Proposal state account . +/// 1. `[writable]` Uninitialized Proposal account . +/// 2. `[writable]` Initialized Governance account. /// 3. `[writable]` Initialized Signatory Mint account /// 4. `[writable]` Initialized Admin Mint account /// 5. `[writable]` Initialized Voting Mint account @@ -27,13 +27,13 @@ import { DESC_SIZE, NAME_SIZE, TimelockInstruction } from './timelock'; /// 14. `[writable]` Initialized No voting dump account /// 15. `[writable]` Initialized source holding account /// 16. `[]` Source mint -/// 17. `[]` Timelock minting authority +/// 17. `[]` Governance minting authority (pda with seed of Proposal key) /// 18. '[]` Token program id /// 19. `[]` Rent sysvar -export const initTimelockSetInstruction = ( - timelockStateAccount: PublicKey, - timelockSetAccount: PublicKey, - timelockConfigAccount: PublicKey, +export const initProposalInstruction = ( + proposalStateAccount: PublicKey, + proposalAccount: PublicKey, + governanceAccount: PublicKey, signatoryMintAccount: PublicKey, adminMintAccount: PublicKey, votingMintAccount: PublicKey, @@ -80,7 +80,7 @@ export const initTimelockSetInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.InitTimelockSet, + instruction: GovernanceInstruction.InitProposal, descLink: descAsBytes, name: nameAsBytes, }, @@ -88,9 +88,9 @@ export const initTimelockSetInstruction = ( ); const keys = [ - { pubkey: timelockStateAccount, isSigner: true, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: true, isWritable: true }, - { pubkey: timelockConfigAccount, isSigner: false, isWritable: true }, + { pubkey: proposalStateAccount, isSigner: true, isWritable: true }, + { pubkey: proposalAccount, isSigner: true, isWritable: true }, + { pubkey: governanceAccount, isSigner: false, isWritable: true }, { pubkey: signatoryMintAccount, isSigner: false, isWritable: true }, { pubkey: adminMintAccount, isSigner: false, isWritable: true }, { pubkey: votingMintAccount, isSigner: false, isWritable: true }, @@ -115,7 +115,7 @@ export const initTimelockSetInstruction = ( ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/removeSigner.ts b/packages/governance/src/models/removeSigner.ts similarity index 75% rename from packages/proposals/src/models/removeSigner.ts rename to packages/governance/src/models/removeSigner.ts index 6dec5a7..72afff6 100644 --- a/packages/proposals/src/models/removeSigner.ts +++ b/packages/governance/src/models/removeSigner.ts @@ -1,7 +1,7 @@ import { PublicKey, TransactionInstruction } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; /// [Requires Admin token] /// Removes a signer from the set. @@ -10,16 +10,17 @@ import { TimelockInstruction } from './timelock'; /// 1. `[writable]` Signatory mint account. /// 2. `[writable]` Admin account. /// 3. `[writable]` Admin validation account. -/// 4. `[]` Timelock set account. -/// 5. `[]` Transfer authority -/// 6. `[]` Timelock program mint authority -/// 7. '[]` Token program id. +/// 4. `[writable]` Proposal state account. +/// 5. `[]` Proposal account. +/// 6. `[]` Transfer authority +/// 7. `[]` Governance program mint authority (pda of seed with Proposal key) +/// 8. '[]` Token program id. export const removeSignerInstruction = ( signatoryAccount: PublicKey, signatoryMintAccount: PublicKey, adminAccount: PublicKey, adminValidationAccount: PublicKey, - timelockSetAccount: PublicKey, + proposalAccount: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, ): TransactionInstruction => { @@ -31,7 +32,7 @@ export const removeSignerInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.RemoveSigner, + instruction: GovernanceInstruction.RemoveSigner, }, data, ); @@ -41,14 +42,14 @@ export const removeSignerInstruction = ( { pubkey: signatoryMintAccount, isSigner: false, isWritable: true }, { pubkey: adminAccount, isSigner: false, isWritable: true }, { pubkey: adminValidationAccount, isSigner: false, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: true }, + { pubkey: proposalAccount, isSigner: false, isWritable: true }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/sign.ts b/packages/governance/src/models/sign.ts similarity index 69% rename from packages/proposals/src/models/sign.ts rename to packages/governance/src/models/sign.ts index 54048e9..be28b58 100644 --- a/packages/proposals/src/models/sign.ts +++ b/packages/governance/src/models/sign.ts @@ -5,25 +5,25 @@ import { } from '@solana/web3.js'; import { utils } from '@oyster/common'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; /// [Requires Signatory token] -/// Burns signatory token, indicating you approve of moving this Timelock set from Draft state to Voting state. +/// Burns signatory token, indicating you approve of moving this Proposal from Draft state to Voting state. /// The last Signatory token to be burned moves the state to Voting. /// -/// 0. `[writable]` Timelock state account pub key. +/// 0. `[writable]` Proposal state account pub key. /// 1. `[writable]` Signatory account /// 2. `[writable]` Signatory mint account. -/// 3. `[]` Timelock set account pub key. +/// 3. `[]` Proposal account pub key. /// 4. `[]` Transfer authority -/// 5. `[]` Timelock mint authority -/// 6. `[]` Token program account. -/// 7. `[]` Clock sysvar. +/// 5. `[]` Governance mint authority (pda of seed Proposal key) +/// 7. `[]` Token program account. +/// 8. `[]` Clock sysvar. export const signInstruction = ( - timelockStateAccount: PublicKey, + proposalStateAccount: PublicKey, signatoryAccount: PublicKey, signatoryMintAccount: PublicKey, - timelockSetAccount: PublicKey, + proposalAccount: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, ): TransactionInstruction => { @@ -35,16 +35,16 @@ export const signInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.Sign, + instruction: GovernanceInstruction.Sign, }, data, ); const keys = [ - { pubkey: timelockStateAccount, isSigner: false, isWritable: true }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: true }, { pubkey: signatoryAccount, isSigner: false, isWritable: true }, { pubkey: signatoryMintAccount, isSigner: false, isWritable: true }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, @@ -52,7 +52,7 @@ export const signInstruction = ( ]; return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/vote.ts b/packages/governance/src/models/vote.ts similarity index 77% rename from packages/proposals/src/models/vote.ts rename to packages/governance/src/models/vote.ts index 3bbd3ec..beed2d9 100644 --- a/packages/proposals/src/models/vote.ts +++ b/packages/governance/src/models/vote.ts @@ -7,17 +7,17 @@ import { utils } from '@oyster/common'; import * as Layout from '../utils/layout'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; import BN from 'bn.js'; /// [Requires Voting tokens] -/// Burns voting tokens, indicating you approve and/or disapprove of running this set of transactions. If you tip the vote threshold, -/// then the transactions can begin to be run at their time slots when people click execute. +/// Burns voting tokens, indicating you approve and/or disapprove of running this set of transactions. If you tip the consensus, +/// then the transactions can begin to be run at their time slots when people click execute. You are then given yes and/or no tokens. /// /// 0. `[writable]` Governance voting record account. /// Can be uninitialized or initialized(if already used once in this proposal) -/// Must have address with PDA having seed tuple [timelock acct key, proposal key, your voting account key] -/// 1. `[writable]` Timelock state account. +/// Must have address with PDA having seed tuple [Governance acct key, proposal key, your voting account key] +/// 1. `[writable]` Proposal state account. /// 2. `[writable]` Your Voting account. /// 3. `[writable]` Your Yes-Voting account. /// 4. `[writable]` Your No-Voting account. @@ -25,15 +25,15 @@ import BN from 'bn.js'; /// 6. `[writable]` Yes Voting mint account. /// 7. `[writable]` No Voting mint account. /// 8. `[]` Source mint account -/// 9. `[]` Timelock set account. -/// 10. `[]` Timelock config account. +/// 9. `[]` Proposal account. +/// 10. `[]` Governance account. /// 12. `[]` Transfer authority -/// 13. `[]` Timelock program mint authority +/// 13. `[]` Governance program mint authority (pda of seed Proposal key) /// 14. `[]` Token program account. /// 15. `[]` Clock sysvar. export const voteInstruction = ( governanceVotingRecord: PublicKey, - timelockStateAccount: PublicKey, + proposalStateAccount: PublicKey, votingAccount: PublicKey, yesVotingAccount: PublicKey, noVotingAccount: PublicKey, @@ -41,8 +41,8 @@ export const voteInstruction = ( yesVotingMint: PublicKey, noVotingMint: PublicKey, sourceMint: PublicKey, - timelockSetAccount: PublicKey, - timelockConfig: PublicKey, + proposalAccount: PublicKey, + governance: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, yesVotingTokenAmount: number, @@ -60,7 +60,7 @@ export const voteInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.Vote, + instruction: GovernanceInstruction.Vote, yesVotingTokenAmount: new BN(yesVotingTokenAmount), noVotingTokenAmount: new BN(noVotingTokenAmount), }, @@ -69,7 +69,7 @@ export const voteInstruction = ( const keys = [ { pubkey: governanceVotingRecord, isSigner: false, isWritable: true }, - { pubkey: timelockStateAccount, isSigner: false, isWritable: true }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: true }, { pubkey: votingAccount, isSigner: false, isWritable: true }, { pubkey: yesVotingAccount, isSigner: false, isWritable: true }, { pubkey: noVotingAccount, isSigner: false, isWritable: true }, @@ -77,8 +77,8 @@ export const voteInstruction = ( { pubkey: yesVotingMint, isSigner: false, isWritable: true }, { pubkey: noVotingMint, isSigner: false, isWritable: true }, { pubkey: sourceMint, isSigner: false, isWritable: false }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, - { pubkey: timelockConfig, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, + { pubkey: governance, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, @@ -87,7 +87,7 @@ export const voteInstruction = ( return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/models/withdrawVotingTokens.ts b/packages/governance/src/models/withdrawVotingTokens.ts similarity index 78% rename from packages/proposals/src/models/withdrawVotingTokens.ts rename to packages/governance/src/models/withdrawVotingTokens.ts index f488e5d..6ed8a37 100644 --- a/packages/proposals/src/models/withdrawVotingTokens.ts +++ b/packages/governance/src/models/withdrawVotingTokens.ts @@ -3,24 +3,27 @@ import { utils } from '@oyster/common'; import * as Layout from '../utils/layout'; import * as BufferLayout from 'buffer-layout'; -import { TimelockInstruction } from './timelock'; +import { GovernanceInstruction } from './governance'; import BN from 'bn.js'; +/// [Requires voting tokens] +/// Withdraws voting tokens. +/// /// 0. `[writable]` Governance voting record account. See Vote docs for more detail. /// 1. `[writable]` Initialized Voting account from which to remove your voting tokens. /// 2. `[writable]` Initialized Yes Voting account from which to remove your voting tokens. /// 3. `[writable]` Initialized No Voting account from which to remove your voting tokens. /// 4. `[writable]` User token account that you wish your actual tokens to be returned to. -/// 5. `[writable]` Source holding account owned by the timelock that will has the actual tokens in escrow. -/// 6. `[writable]` Initialized Yes Voting dump account owned by timelock set to which to send your voting tokens. -/// 7. `[writable]` Initialized No Voting dump account owned by timelock set to which to send your voting tokens. +/// 5. `[writable]` Source holding account owned by the Governance that will has the actual tokens in escrow. +/// 6. `[writable]` Initialized Yes Voting dump account owned by Proposal to which to send your voting tokens. +/// 7. `[writable]` Initialized No Voting dump account owned by Proposal to which to send your voting tokens. /// 8. `[writable]` Voting mint account. /// 9. `[writable]` Yes Voting mint account. /// 10. `[writable]` No Voting mint account. -/// 11. `[]` Timelock state account. -/// 12. `[]` Timelock set account. +/// 11. `[]` Proposal state account. +/// 12. `[]` Proposal account. /// 13. `[]` Transfer authority -/// 14. `[]` Timelock program mint authority +/// 14. `[]` Governance program mint authority (pda of seed Proposal key) /// 15. `[]` Token program account. export const withdrawVotingTokensInstruction = ( governanceVotingRecord: PublicKey, @@ -34,8 +37,8 @@ export const withdrawVotingTokensInstruction = ( votingMint: PublicKey, yesVotingMint: PublicKey, noVotingMint: PublicKey, - timelockStateAccount: PublicKey, - timelockSetAccount: PublicKey, + proposalStateAccount: PublicKey, + proposalAccount: PublicKey, transferAuthority: PublicKey, mintAuthority: PublicKey, votingTokenAmount: number, @@ -51,7 +54,7 @@ export const withdrawVotingTokensInstruction = ( dataLayout.encode( { - instruction: TimelockInstruction.WithdrawVotingTokens, + instruction: GovernanceInstruction.WithdrawVotingTokens, votingTokenAmount: new BN(votingTokenAmount), }, data, @@ -69,8 +72,8 @@ export const withdrawVotingTokensInstruction = ( { pubkey: votingMint, isSigner: false, isWritable: true }, { pubkey: yesVotingMint, isSigner: false, isWritable: true }, { pubkey: noVotingMint, isSigner: false, isWritable: true }, - { pubkey: timelockStateAccount, isSigner: false, isWritable: false }, - { pubkey: timelockSetAccount, isSigner: false, isWritable: false }, + { pubkey: proposalStateAccount, isSigner: false, isWritable: false }, + { pubkey: proposalAccount, isSigner: false, isWritable: false }, { pubkey: transferAuthority, isSigner: true, isWritable: false }, { pubkey: mintAuthority, isSigner: false, isWritable: false }, { pubkey: PROGRAM_IDS.token, isSigner: false, isWritable: false }, @@ -78,7 +81,7 @@ export const withdrawVotingTokensInstruction = ( return new TransactionInstruction({ keys, - programId: PROGRAM_IDS.timelock.programId, + programId: PROGRAM_IDS.governance.programId, data, }); }; diff --git a/packages/proposals/src/react-app-env.d.ts b/packages/governance/src/react-app-env.d.ts similarity index 100% rename from packages/proposals/src/react-app-env.d.ts rename to packages/governance/src/react-app-env.d.ts diff --git a/packages/proposals/src/routes.tsx b/packages/governance/src/routes.tsx similarity index 100% rename from packages/proposals/src/routes.tsx rename to packages/governance/src/routes.tsx diff --git a/packages/proposals/src/serviceWorker.ts b/packages/governance/src/serviceWorker.ts similarity index 100% rename from packages/proposals/src/serviceWorker.ts rename to packages/governance/src/serviceWorker.ts diff --git a/packages/proposals/src/setupTests.ts b/packages/governance/src/setupTests.ts similarity index 100% rename from packages/proposals/src/setupTests.ts rename to packages/governance/src/setupTests.ts diff --git a/packages/proposals/src/types/buffer-layout.d.ts b/packages/governance/src/types/buffer-layout.d.ts similarity index 100% rename from packages/proposals/src/types/buffer-layout.d.ts rename to packages/governance/src/types/buffer-layout.d.ts diff --git a/packages/proposals/src/types/sol-wallet-adapter.d.ts b/packages/governance/src/types/sol-wallet-adapter.d.ts similarity index 100% rename from packages/proposals/src/types/sol-wallet-adapter.d.ts rename to packages/governance/src/types/sol-wallet-adapter.d.ts diff --git a/packages/proposals/src/utils/layout.ts b/packages/governance/src/utils/layout.ts similarity index 100% rename from packages/proposals/src/utils/layout.ts rename to packages/governance/src/utils/layout.ts diff --git a/packages/proposals/src/utils/lookups.ts b/packages/governance/src/utils/lookups.ts similarity index 95% rename from packages/proposals/src/utils/lookups.ts rename to packages/governance/src/utils/lookups.ts index d590767..3374961 100644 --- a/packages/proposals/src/utils/lookups.ts +++ b/packages/governance/src/utils/lookups.ts @@ -5,7 +5,7 @@ import { GovernanceVotingRecord, GovernanceVotingRecordLayout, GovernanceVotingRecordParser, -} from '../models/timelock'; +} from '../models/governance'; const MAX_LOOKUPS = 5000; export async function getGovernanceVotingRecords( @@ -25,7 +25,7 @@ export async function getGovernanceVotingRecords( id: 1, method: 'getProgramAccounts', params: [ - PROGRAM_IDS.timelock.programId.toBase58(), + PROGRAM_IDS.governance.programId.toBase58(), { commitment: 'single', filters: [ diff --git a/packages/proposals/src/utils/serialize.ts b/packages/governance/src/utils/serialize.ts similarity index 88% rename from packages/proposals/src/utils/serialize.ts rename to packages/governance/src/utils/serialize.ts index 8017f84..9fefc8c 100644 --- a/packages/proposals/src/utils/serialize.ts +++ b/packages/governance/src/utils/serialize.ts @@ -6,7 +6,7 @@ import { PublicKey, Message, } from '@solana/web3.js'; -import { GOVERNANCE_AUTHORITY_SEED, TimelockSet } from '../models/timelock'; +import { GOVERNANCE_AUTHORITY_SEED, Proposal } from '../models/governance'; export async function serializeInstruction({ connection, instr, @@ -14,7 +14,7 @@ export async function serializeInstruction({ }: { connection: Connection; instr: TransactionInstruction; - proposal: ParsedAccount; + proposal: ParsedAccount; }): Promise<{ base64: string; byteArray: Uint8Array }> { const PROGRAM_IDS = utils.programIds(); let instructionTransaction = new Transaction(); @@ -24,7 +24,7 @@ export async function serializeInstruction({ ).blockhash; const [authority] = await PublicKey.findProgramAddress( [Buffer.from(GOVERNANCE_AUTHORITY_SEED), proposal.pubkey.toBuffer()], - PROGRAM_IDS.timelock.programId, + PROGRAM_IDS.governance.programId, ); instructionTransaction.setSigners(authority); const msg: Message = instructionTransaction.compileMessage(); diff --git a/packages/proposals/src/actions/execute.ts b/packages/governance/src/utils/transactions.ts similarity index 57% rename from packages/proposals/src/actions/execute.ts rename to packages/governance/src/utils/transactions.ts index e48a180..3c10584 100644 --- a/packages/proposals/src/actions/execute.ts +++ b/packages/governance/src/utils/transactions.ts @@ -1,76 +1,6 @@ -import { - Account, - Connection, - Message, - PublicKey, - TransactionInstruction, -} from '@solana/web3.js'; -import { contexts, utils, ParsedAccount } from '@oyster/common'; +import { Message, PublicKey } from '@solana/web3.js'; -import { - TimelockSet, - TimelockState, - TimelockTransaction, -} from '../models/timelock'; -import { executeInstruction } from '../models/execute'; -import { LABELS } from '../constants'; -const { sendTransaction } = contexts.Connection; -const { notify } = utils; - -export const execute = async ( - connection: Connection, - wallet: any, - proposal: ParsedAccount, - state: ParsedAccount, - transaction: ParsedAccount, -) => { - let signers: Account[] = []; - let instructions: TransactionInstruction[] = []; - const actualMessage = decodeBufferIntoMessage(transaction.info.instruction); - const accountInfos = getAccountInfos(actualMessage); - - instructions.push( - executeInstruction( - transaction.pubkey, - state.pubkey, - proposal.pubkey, - actualMessage.accountKeys[actualMessage.instructions[0].programIdIndex], - proposal.info.config, - accountInfos, - ), - ); - - notify({ - message: LABELS.EXECUTING, - description: LABELS.PLEASE_WAIT, - type: 'warn', - }); - - try { - let tx = await sendTransaction( - connection, - wallet, - instructions, - signers, - true, - ); - - notify({ - message: LABELS.EXECUTED, - type: 'success', - description: LABELS.TRANSACTION + ` ${tx}`, - }); - } catch (ex) { - console.error(ex); - throw new Error(); - } -}; - -function decodeBufferIntoMessage(instruction: number[]): Message { - return Message.from(instruction); -} - -function getAccountInfos( +export function getMessageAccountInfos( actualMessage: Message, ): { pubkey: PublicKey; isSigner: boolean; isWritable: boolean }[] { console.log(actualMessage); diff --git a/packages/proposals/src/views/dashboard/index.tsx b/packages/governance/src/views/dashboard/index.tsx similarity index 93% rename from packages/proposals/src/views/dashboard/index.tsx rename to packages/governance/src/views/dashboard/index.tsx index 5bd00dc..e55a8e8 100644 --- a/packages/proposals/src/views/dashboard/index.tsx +++ b/packages/governance/src/views/dashboard/index.tsx @@ -4,7 +4,7 @@ import { GUTTER } from '../../constants'; import { contexts, hooks, ParsedAccount } from '@oyster/common'; import './style.less'; import { useProposals } from '../../contexts/proposals'; -import { TimelockSet } from '../../models/timelock'; +import { Proposal } from '../../models/governance'; import { Connection } from '@solana/web3.js'; import { WalletAdapter } from '@solana/wallet-base'; const { useWallet } = contexts.Wallet; @@ -38,7 +38,7 @@ function InnerDummyView({ }: { connection: Connection; wallet: WalletAdapter; - proposal: ParsedAccount; + proposal: ParsedAccount; }) { const sigAccount = useAccountByMint(proposal.info.signatoryMint); if (!sigAccount) return ; diff --git a/packages/proposals/src/views/dashboard/style.less b/packages/governance/src/views/dashboard/style.less similarity index 100% rename from packages/proposals/src/views/dashboard/style.less rename to packages/governance/src/views/dashboard/style.less diff --git a/packages/proposals/src/views/governance/index.tsx b/packages/governance/src/views/governance/index.tsx similarity index 87% rename from packages/proposals/src/views/governance/index.tsx rename to packages/governance/src/views/governance/index.tsx index fecaee1..7882914 100644 --- a/packages/proposals/src/views/governance/index.tsx +++ b/packages/governance/src/views/governance/index.tsx @@ -11,10 +11,10 @@ import { } from '@oyster/common'; import { ExecutionType, - TimelockConfig, - TimelockType, + Governance, + GovernanceType, VotingEntryRule, -} from '../../models/timelock'; +} from '../../models/governance'; import { PublicKey } from '@solana/web3.js'; import { Table } from 'antd'; import MintSourceTokens from '../../components/Proposal/MintSourceTokens'; @@ -40,9 +40,9 @@ const columns = [ }, { title: LABELS.PROPOSAL_TYPE, - dataIndex: 'timelockType', - key: 'timelockType', - render: (number: number) => {TimelockType[number]}, + dataIndex: 'governanceType', + key: 'governanceType', + render: (number: number) => {GovernanceType[number]}, }, { title: LABELS.VOTING_ENTRY_RULES, @@ -75,7 +75,7 @@ const columns = [ render: (key: PublicKey) => {key?.toBase58()}, }, { - title: LABELS.PROGRAM, + title: LABELS.PROGRAM_ID, dataIndex: 'program', key: 'program', render: (key: PublicKey) => {key.toBase58()}, @@ -85,11 +85,11 @@ const columns = [ title: LABELS.ACTIONS, dataIndex: 'config', key: 'config', - render: (config: ParsedAccount) => ( + render: (config: ParsedAccount) => ( <> - + {config.info.councilMint && ( - + )} ), @@ -133,7 +133,7 @@ export const GovernanceDashboard = () => { })), ); }); - }, [configs.length, myTokenAccts.join(',')]); + }, [configs.length, myTokenAccts.join(',')]); //eslint-disable-line return ; }; diff --git a/packages/proposals/src/views/governance/register.tsx b/packages/governance/src/views/governance/register.tsx similarity index 94% rename from packages/proposals/src/views/governance/register.tsx rename to packages/governance/src/views/governance/register.tsx index f78e8c9..f7a5eaa 100644 --- a/packages/proposals/src/views/governance/register.tsx +++ b/packages/governance/src/views/governance/register.tsx @@ -5,9 +5,9 @@ import { PublicKey } from '@solana/web3.js'; import { CONFIG_NAME_LENGTH, ExecutionType, - TimelockType, + GovernanceType, VotingEntryRule, -} from '../../models/timelock'; +} from '../../models/governance'; import { LABELS } from '../../constants'; import { contexts, utils, tryParseKey } from '@oyster/common'; import { registerProgramGovernance } from '../../actions/registerProgramGovernance'; @@ -68,7 +68,7 @@ export function NewForm({ const wallet = useWallet(); const connection = useConnection(); const onFinish = async (values: { - timelockType: TimelockType; + governanceType: GovernanceType; executionType: ExecutionType; voteThreshold: number; votingEntryRule: VotingEntryRule; @@ -119,8 +119,8 @@ export function NewForm({ return; } - const uninitializedConfig = { - timelockType: values.timelockType, + const uninitializedGovernance = { + governanceType: values.governanceType, executionType: values.executionType, voteThreshold: values.voteThreshold, votingEntryRule: values.votingEntryRule, @@ -140,7 +140,7 @@ export function NewForm({ const newConfig = await registerProgramGovernance( connection, wallet.wallet, - uninitializedConfig, + uninitializedGovernance, councilVisible, ); handleOk(newConfig); @@ -158,7 +158,7 @@ export function NewForm({ @@ -215,15 +215,13 @@ export function NewForm({ { const history = useHistory(); @@ -26,8 +26,8 @@ export const HomeView = () => { if (proposal.info.config.toBase58() === configKey) { acc.active = acc.active + - (state.info.status === TimelockStateStatus.Voting || - state.info.status === TimelockStateStatus.Draft + (state.info.status === ProposalStateStatus.Voting || + state.info.status === ProposalStateStatus.Draft ? 1 : 0); @@ -56,7 +56,7 @@ export const HomeView = () => { }); }); return newListData; - }, [configs, proposals]); + }, [configs, proposals, states]); return ( <> diff --git a/packages/proposals/src/views/home/style.less b/packages/governance/src/views/home/style.less similarity index 100% rename from packages/proposals/src/views/home/style.less rename to packages/governance/src/views/home/style.less diff --git a/packages/proposals/src/views/index.tsx b/packages/governance/src/views/index.tsx similarity index 100% rename from packages/proposals/src/views/index.tsx rename to packages/governance/src/views/index.tsx diff --git a/packages/proposals/src/views/proposal/index.tsx b/packages/governance/src/views/proposal/index.tsx similarity index 81% rename from packages/proposals/src/views/proposal/index.tsx rename to packages/governance/src/views/proposal/index.tsx index c7cfd28..710ebfe 100644 --- a/packages/proposals/src/views/proposal/index.tsx +++ b/packages/governance/src/views/proposal/index.tsx @@ -1,15 +1,15 @@ -import { Card, Col, Grid, Row, Spin, Statistic, Tabs } from 'antd'; +import { Card, Col, Row, Spin, Statistic, Tabs } from 'antd'; import React, { useMemo, useState } from 'react'; import { LABELS } from '../../constants'; import { ParsedAccount, TokenIcon } from '@oyster/common'; import { INSTRUCTION_LIMIT, - TimelockConfig, - TimelockSet, - TimelockState, - TimelockStateStatus, - TimelockTransaction, -} from '../../models/timelock'; + Governance, + Proposal, + ProposalState, + ProposalStateStatus, + GovernanceTransaction, +} from '../../models/governance'; import { useParams } from 'react-router-dom'; import ReactMarkdown from 'react-markdown'; import { useProposals } from '../../contexts/proposals'; @@ -30,11 +30,12 @@ import { VoterBubbleGraph } from '../../components/Proposal/VoterBubbleGraph'; import { VoterTable } from '../../components/Proposal/VoterTable'; const { TabPane } = Tabs; +// eslint-disable-next-line export const urlRegex = /[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/; const { useMint } = contexts.Accounts; const { useConnectionConfig } = contexts.Connection; const { useAccountByMint } = hooks; -const { useBreakpoint } = Grid; +//const { useBreakpoint } = Grid; export enum VoteType { Undecided = 'Undecided', @@ -46,8 +47,8 @@ export const ProposalView = () => { const context = useProposals(); const { id } = useParams<{ id: string }>(); const proposal = context.proposals[id]; - const timelockConfig = context.configs[proposal?.info.config.toBase58()]; - const timelockState = context.states[proposal?.info.state.toBase58()]; + const governance = context.configs[proposal?.info.config.toBase58()]; + const proposalState = context.states[proposal?.info.state.toBase58()]; const { endpoint } = useConnectionConfig(); const sigMint = useMint(proposal?.info.signatoryMint); const votingMint = useMint(proposal?.info.votingMint); @@ -68,8 +69,8 @@ export const ProposalView = () => { noVotingMint ? ( void; @@ -101,11 +102,11 @@ function useLoadGist({ setFailed: (b: boolean) => void; setContent: (b: string) => void; isGist: boolean; - timelockState: ParsedAccount; + proposalState: ParsedAccount; }) { useMemo(() => { if (loading) { - let toFetch = timelockState.info.descLink; + let toFetch = proposalState.info.descLink; const pieces = toFetch.match(urlRegex); if (isGist && pieces) { const justIdWithoutUser = pieces[1].split('/')[2]; @@ -134,7 +135,7 @@ function useLoadGist({ setLoading(false); }); } - }, [loading]); + }, [loading]); //eslint-disable-line } interface PartialGovernanceRecord { info: { yesCount: BN; noCount: BN; undecidedCount: BN }; @@ -155,6 +156,7 @@ function voterDisplayData( title: key, group: label, value: amount, + key: key, }); const undecidedData = [ @@ -198,51 +200,52 @@ function voterDisplayData( const data = [...undecidedData, ...yesData, ...noData].sort( (a, b) => b.value - a.value, ); + return data; } function InnerProposalView({ proposal, - timelockState, + proposalState, sigMint, votingMint, yesVotingMint, noVotingMint, instructions, - timelockConfig, + governance, sourceMint, votingDisplayData, endpoint, }: { - proposal: ParsedAccount; - timelockConfig: ParsedAccount; - timelockState: ParsedAccount; + proposal: ParsedAccount; + governance: ParsedAccount; + proposalState: ParsedAccount; sigMint: MintInfo; votingMint: MintInfo; yesVotingMint: MintInfo; noVotingMint: MintInfo; sourceMint: MintInfo; - instructions: Record>; + instructions: Record>; votingDisplayData: Array; endpoint: string; }) { const sigAccount = useAccountByMint(proposal.info.signatoryMint); const adminAccount = useAccountByMint(proposal.info.adminMint); - const instructionsForProposal: ParsedAccount[] = timelockState.info.timelockTransactions + const instructionsForProposal: ParsedAccount[] = proposalState.info.proposalTransactions .map(k => instructions[k.toBase58()]) .filter(k => k); - const isUrl = !!timelockState.info.descLink.match(urlRegex); + const isUrl = !!proposalState.info.descLink.match(urlRegex); const isGist = - !!timelockState.info.descLink.match(/gist/i) && - !!timelockState.info.descLink.match(/github/i); - const [content, setContent] = useState(timelockState.info.descLink); + !!proposalState.info.descLink.match(/gist/i) && + !!proposalState.info.descLink.match(/github/i); + const [content, setContent] = useState(proposalState.info.descLink); const [loading, setLoading] = useState(isUrl); const [failed, setFailed] = useState(false); const [msg, setMsg] = useState(''); const [width, setWidth] = useState(); const [height, setHeight] = useState(); - const breakpoint = useBreakpoint(); + // const breakpoint = useBreakpoint(); useLoadGist({ loading, @@ -251,7 +254,7 @@ function InnerProposalView({ setMsg, setContent, isGist, - timelockState, + proposalState: proposalState, }); return ( @@ -265,8 +268,8 @@ function InnerProposalView({ size={60} /> -

{timelockState.info.name}

- +

{proposalState.info.name}

+ @@ -274,36 +277,32 @@ function InnerProposalView({
{adminAccount && adminAccount.info.amount.toNumber() === 1 && - timelockState.info.status === TimelockStateStatus.Draft && ( - + proposalState.info.status === ProposalStateStatus.Draft && ( + )} {sigAccount && sigAccount.info.amount.toNumber() === 1 && - timelockState.info.status === TimelockStateStatus.Draft && ( - + proposalState.info.status === ProposalStateStatus.Draft && ( + )} - +
@@ -367,10 +366,10 @@ function InnerProposalView({ @@ -388,7 +387,7 @@ function InnerProposalView({ @@ -409,7 +408,7 @@ function InnerProposalView({

{LABELS.DESCRIPTION}:{' '} @@ -436,17 +435,17 @@ function InnerProposalView({ proposal={proposal} position={position + 1} instruction={instruction} - state={timelockState} + state={proposalState} /> ))} {instructionsForProposal.length < INSTRUCTION_LIMIT && - timelockState.info.status === TimelockStateStatus.Draft && ( + proposalState.info.status === ProposalStateStatus.Draft && (

@@ -462,13 +461,12 @@ function InnerProposalView({ } function getVotesRequired( - timelockConfig: ParsedAccount, + governance: ParsedAccount, sourceMint: MintInfo, ): number { - return timelockConfig.info.voteThreshold === 100 + return governance.info.voteThreshold === 100 ? sourceMint.supply.toNumber() : Math.ceil( - (timelockConfig.info.voteThreshold / 100) * - sourceMint.supply.toNumber(), + (governance.info.voteThreshold / 100) * sourceMint.supply.toNumber(), ); } diff --git a/packages/proposals/src/views/proposal/new.tsx b/packages/governance/src/views/proposal/new.tsx similarity index 95% rename from packages/proposals/src/views/proposal/new.tsx rename to packages/governance/src/views/proposal/new.tsx index 8da7ca9..6e6b118 100644 --- a/packages/proposals/src/views/proposal/new.tsx +++ b/packages/governance/src/views/proposal/new.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Button, ButtonProps, Modal, Radio } from 'antd'; import { Form, Input, Select } from 'antd'; import { Account } from '@solana/web3.js'; -import { DESC_SIZE, NAME_SIZE } from '../../models/timelock'; +import { DESC_SIZE, NAME_SIZE } from '../../models/governance'; import { LABELS } from '../../constants'; import { contexts, utils } from '@oyster/common'; import { createProposal } from '../../actions/createProposal'; @@ -74,9 +74,9 @@ export function NewForm({ name: string; proposalMintType: string; description: string; - timelockConfigKey: string; + governanceKey: string; }) => { - const config = context.configs[values.timelockConfigKey]; + const config = context.configs[values.governanceKey]; if ( values.proposalMintType === ProposalMintType.Council && @@ -132,7 +132,7 @@ export function NewForm({ diff --git a/packages/proposals/src/views/proposal/style.less b/packages/governance/src/views/proposal/style.less similarity index 100% rename from packages/proposals/src/views/proposal/style.less rename to packages/governance/src/views/proposal/style.less diff --git a/packages/proposals/src/views/proposals/index.tsx b/packages/governance/src/views/proposals/index.tsx similarity index 98% rename from packages/proposals/src/views/proposals/index.tsx rename to packages/governance/src/views/proposals/index.tsx index cd221fb..2b7d06c 100644 --- a/packages/proposals/src/views/proposals/index.tsx +++ b/packages/governance/src/views/proposals/index.tsx @@ -45,7 +45,7 @@ export const ProposalsView = () => { }); }); return newListData; - }, [proposals]); + }, [proposals, id, mint, states]); return (