mirror of https://github.com/certusone/oyster.git
Merge remote-tracking branch 'origin/main' into feature/m
This commit is contained in:
commit
3891bdcc47
|
@ -8,6 +8,6 @@
|
|||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"prettier.prettierPath": ".vscode/pnpify/prettier/index.js",
|
||||
"cSpell.words": [
|
||||
"Timelock"
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports = {
|
|||
webpack: {
|
||||
configure: (webpackConfig, { env, paths }) => {
|
||||
paths.appBuild = webpackConfig.output.path = path.resolve(
|
||||
'./../../build/proposals',
|
||||
'./../../build/governance',
|
||||
);
|
||||
return webpackConfig;
|
||||
},
|
|
@ -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": {
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 216 KiB |
|
@ -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<TimelockSet>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
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);
|
|
@ -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<TimelockSet>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
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(
|
|
@ -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<TimelockConfig>,
|
||||
governance: ParsedAccount<Governance>,
|
||||
): Promise<Account> => {
|
||||
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<TimelockConfig>,
|
||||
governance: ParsedAccount<Governance>,
|
||||
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,
|
||||
);
|
|
@ -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<TimelockSet>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
existingVoteAccount: PublicKey | undefined,
|
||||
existingYesVoteAccount: PublicKey | undefined,
|
||||
existingNoVoteAccount: PublicKey | undefined,
|
||||
sourceAccount: PublicKey,
|
||||
timelockConfig: ParsedAccount<TimelockConfig>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
governance: ParsedAccount<Governance>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
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,
|
|
@ -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<Proposal>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
transaction: ParsedAccount<GovernanceTransaction>,
|
||||
) => {
|
||||
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);
|
||||
}
|
|
@ -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<TimelockConfig>,
|
||||
governance: ParsedAccount<Governance>,
|
||||
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,
|
||||
[],
|
|
@ -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<TimelockConfig>,
|
||||
uninitializedGovernance: Partial<Governance>,
|
||||
useCouncil: boolean,
|
||||
): Promise<PublicKey> => {
|
||||
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();
|
|
@ -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<TimelockSet>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
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(
|
|
@ -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<TimelockSet>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
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(
|
|
@ -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<TimelockSet>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
proposal: ParsedAccount<Proposal>,
|
||||
state: ParsedAccount<ProposalState>,
|
||||
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];
|
||||
|
|
@ -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<any | null>(
|
||||
null,
|
||||
);
|
||||
export const CannonContext = React.createContext<any | null>(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 (
|
||||
<CannonContext.Provider value={world} children={children} />
|
||||
);
|
||||
return <CannonContext.Provider value={world} children={children} />;
|
||||
}
|
||||
|
||||
// Custom hook to maintain a world physics body
|
||||
export function useCannon({ ...props }, fn: any, deps = []) {
|
||||
const ref = useRef<any>()
|
||||
const ref = useRef<any>();
|
||||
// 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;
|
||||
}
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
@ -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 (
|
||||
<Breadcrumb.Item key={url}>
|
||||
<Link to={url}>{breadcrumbNameMap[url]}</Link>
|
||||
</Breadcrumb.Item>
|
||||
);
|
||||
});
|
||||
const breadcrumbItems = [
|
||||
<Breadcrumb.Item key="home">
|
||||
<Link to="/">Home</Link>
|
||||
</Breadcrumb.Item>,
|
||||
].concat(extraBreadcrumbItems);
|
||||
//const pathSnippets = location.pathname.split('/').filter(i => i);
|
||||
// const extraBreadcrumbItems = pathSnippets.map((_, index) => {
|
||||
// const url = `/${pathSnippets.slice(0, index + 1).join('/')}`;
|
||||
// return (
|
||||
// <Breadcrumb.Item key={url}>
|
||||
// <Link to={url}>{breadcrumbNameMap[url]}</Link>
|
||||
// </Breadcrumb.Item>
|
||||
// );
|
||||
// });
|
||||
|
||||
// const breadcrumbItems = [
|
||||
// <Breadcrumb.Item key="home">
|
||||
// <Link to="/">Home</Link>
|
||||
// </Breadcrumb.Item>,
|
||||
// ].concat(extraBreadcrumbItems);
|
||||
|
||||
// TODO: add breadcrumb
|
||||
|
|
@ -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<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
}) {
|
||||
const wallet = useWallet();
|
||||
const connection = useConnection();
|
|
@ -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<TimelockTransaction>;
|
||||
proposal: ParsedAccount<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
instruction: ParsedAccount<GovernanceTransaction>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
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<string, JSX.Element> = {
|
||||
info: (
|
||||
<Meta
|
||||
title={'Program: TODO'}
|
||||
title={`${LABELS.PROGRAM_ID}: ${instructionDetails.instructionProgramID}`}
|
||||
description={
|
||||
<>
|
||||
<p>Instruction: TODO</p>
|
||||
<p>{`${LABELS.INSTRUCTION}: ${instructionDetails.instructionData}`}</p>
|
||||
<p>
|
||||
{LABELS.DELAY}: {instruction.info.slot.toNumber()}
|
||||
</p>
|
||||
|
@ -93,9 +106,9 @@ function PlayStatusButton({
|
|||
setPlaying,
|
||||
instruction,
|
||||
}: {
|
||||
proposal: ParsedAccount<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
instruction: ParsedAccount<TimelockTransaction>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
instruction: ParsedAccount<GovernanceTransaction>;
|
||||
playing: Playstate;
|
||||
setPlaying: React.Dispatch<React.SetStateAction<Playstate>>;
|
||||
}) {
|
||||
|
@ -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 (
|
||||
<a onClick={run}>
|
||||
<Button onClick={run}>
|
||||
<PlayCircleOutlined style={{ color: 'green' }} key="play" />
|
||||
</a>
|
||||
</Button>
|
||||
);
|
||||
else if (playing === Playstate.Playing)
|
||||
return <LoadingOutlined style={{ color: 'orange' }} key="loading" />;
|
||||
else if (playing === Playstate.Error)
|
||||
return (
|
||||
<a onClick={run}>
|
||||
<Button onClick={run}>
|
||||
<RedoOutlined style={{ color: 'orange' }} key="play" />
|
||||
</a>
|
||||
</Button>
|
||||
);
|
||||
else return <CheckCircleOutlined style={{ color: 'green' }} key="played" />;
|
||||
}
|
|
@ -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<TimelockConfig>;
|
||||
governance: ParsedAccount<Governance>;
|
||||
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,
|
|
@ -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<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
config: ParsedAccount<TimelockConfig>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
config: ParsedAccount<Governance>;
|
||||
position: number;
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
|
@ -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<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
}) {
|
||||
const wallet = useWallet();
|
||||
const connection = useConnection();
|
|
@ -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<TimelockState>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
children?: any;
|
||||
}) {
|
||||
const status = state.info.status;
|
||||
|
@ -19,19 +19,19 @@ export function StateBadgeRibbon({
|
|||
return (
|
||||
<Badge.Ribbon
|
||||
style={{ backgroundColor: color }}
|
||||
text={TimelockStateStatus[status]}
|
||||
text={ProposalStateStatus[status]}
|
||||
>
|
||||
{children}
|
||||
</Badge.Ribbon>
|
||||
);
|
||||
}
|
||||
|
||||
export function StateBadge({ state }: { state: ParsedAccount<TimelockState> }) {
|
||||
export function StateBadge({ state }: { state: ParsedAccount<ProposalState> }) {
|
||||
const status = state.info.status;
|
||||
let color = STATE_COLOR[status];
|
||||
return (
|
||||
<Tag color={color} style={{ borderWidth: 0 }}>
|
||||
{TimelockStateStatus[status]}
|
||||
{ProposalStateStatus[status]}
|
||||
</Tag>
|
||||
);
|
||||
}
|
|
@ -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<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
timelockConfig: ParsedAccount<TimelockConfig>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
governance: ParsedAccount<Governance>;
|
||||
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,
|
|
@ -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<VoterDisplayData>) => {
|
||||
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<VoterDisplayData>) => {
|
||||
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 (
|
||||
<div
|
|
@ -2,11 +2,10 @@ import { ParsedAccount } from '@oyster/common';
|
|||
import { Button, Col, Modal, Row } from 'antd';
|
||||
import React from 'react';
|
||||
import {
|
||||
TimelockConfig,
|
||||
TimelockSet,
|
||||
TimelockState,
|
||||
TimelockStateStatus,
|
||||
} from '../../models/timelock';
|
||||
Proposal,
|
||||
ProposalState,
|
||||
ProposalStateStatus,
|
||||
} from '../../models/governance';
|
||||
import { LABELS } from '../../constants';
|
||||
import { withdrawVotingTokens } from '../../actions/withdrawVotingTokens';
|
||||
import { contexts, hooks } from '@oyster/common';
|
||||
|
@ -21,9 +20,8 @@ export function WithdrawVote({
|
|||
proposal,
|
||||
state,
|
||||
}: {
|
||||
proposal: ParsedAccount<TimelockSet>;
|
||||
state: ParsedAccount<TimelockState>;
|
||||
timelockConfig: ParsedAccount<TimelockConfig>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
state: ParsedAccount<ProposalState>;
|
||||
}) {
|
||||
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,
|
|
@ -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',
|
|
@ -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<string, ParsedAccount<TimelockSet>>;
|
||||
transactions: Record<string, ParsedAccount<TimelockTransaction>>;
|
||||
states: Record<string, ParsedAccount<TimelockState>>;
|
||||
configs: Record<string, ParsedAccount<TimelockConfig>>;
|
||||
proposals: Record<string, ParsedAccount<Proposal>>;
|
||||
transactions: Record<string, ParsedAccount<GovernanceTransaction>>;
|
||||
states: Record<string, ParsedAccount<ProposalState>>;
|
||||
configs: Record<string, ParsedAccount<Governance>>;
|
||||
}
|
||||
|
||||
export const ProposalsContext = React.createContext<ProposalsContextState | null>(
|
||||
|
@ -82,49 +82,47 @@ function useSetupProposalsCache({
|
|||
setStates: React.Dispatch<React.SetStateAction<{}>>;
|
||||
setConfigs: React.Dispatch<React.SetStateAction<{}>>;
|
||||
}) {
|
||||
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<Buffer>[][]) => {
|
||||
const newProposals: Record<string, ParsedAccount<TimelockSet>> = {};
|
||||
const newProposals: Record<string, ParsedAccount<Proposal>> = {};
|
||||
const newTransactions: Record<
|
||||
string,
|
||||
ParsedAccount<TimelockTransaction>
|
||||
ParsedAccount<GovernanceTransaction>
|
||||
> = {};
|
||||
const newStates: Record<string, ParsedAccount<TimelockState>> = {};
|
||||
const newConfigs: Record<string, ParsedAccount<TimelockConfig>> = {};
|
||||
const newStates: Record<string, ParsedAccount<ProposalState>> = {};
|
||||
const newConfigs: Record<string, ParsedAccount<Governance>> = {};
|
||||
|
||||
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<TimelockSet>;
|
||||
case ProposalLayout.span:
|
||||
cache.add(a.pubkey, a.account, ProposalParser);
|
||||
cached = cache.get(a.pubkey) as ParsedAccount<Proposal>;
|
||||
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<TimelockTransaction>;
|
||||
) as ParsedAccount<GovernanceTransaction>;
|
||||
newTransactions[a.pubkey.toBase58()] = cached;
|
||||
break;
|
||||
case TimelockConfigLayout.span:
|
||||
cache.add(a.pubkey, a.account, TimelockConfigParser);
|
||||
cached = cache.get(a.pubkey) as ParsedAccount<TimelockConfig>;
|
||||
case GovernanceLayout.span:
|
||||
cache.add(a.pubkey, a.account, GovernanceParser);
|
||||
cached = cache.get(a.pubkey) as ParsedAccount<Governance>;
|
||||
newConfigs[a.pubkey.toBase58()] = cached;
|
||||
break;
|
||||
case TimelockStateLayout.span:
|
||||
cache.add(a.pubkey, a.account, TimelockStateParser);
|
||||
cached = cache.get(a.pubkey) as ParsedAccount<TimelockState>;
|
||||
case ProposalStateLayout.span:
|
||||
cache.add(a.pubkey, a.account, ProposalStateParser);
|
||||
cached = cache.get(a.pubkey) as ParsedAccount<ProposalState>;
|
||||
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<TimelockSet>;
|
||||
case ProposalLayout.span:
|
||||
cached = cache.get(info.accountId) as ParsedAccount<Proposal>;
|
||||
break;
|
||||
case CustomSingleSignerTimelockTransactionLayout.span:
|
||||
case CustomSingleSignerTransactionLayout.span:
|
||||
cached = cache.get(
|
||||
pubkey,
|
||||
) as ParsedAccount<CustomSingleSignerTimelockTransaction>;
|
||||
info.accountId,
|
||||
) as ParsedAccount<CustomSingleSignerTransaction>;
|
||||
break;
|
||||
case TimelockConfigLayout.span:
|
||||
cached = cache.get(
|
||||
pubkey,
|
||||
) as ParsedAccount<TimelockConfig>;
|
||||
case GovernanceLayout.span:
|
||||
cached = cache.get(info.accountId) as ParsedAccount<Governance>;
|
||||
break;
|
||||
case TimelockStateLayout.span:
|
||||
case ProposalStateLayout.span:
|
||||
cached = cache.get(
|
||||
pubkey,
|
||||
) as ParsedAccount<TimelockState>;
|
||||
info.accountId,
|
||||
) as ParsedAccount<ProposalState>;
|
||||
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);
|
|
@ -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
|
||||
) {
|
|
@ -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",
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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<string, string> = {
|
||||
[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<Buffer>,
|
||||
) => {
|
||||
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<Buffer>,
|
||||
) => {
|
||||
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<Buffer>,
|
||||
) => {
|
||||
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<Buffer>,
|
||||
) => {
|
||||
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,
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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,
|
||||
});
|
||||
};
|
|
@ -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: [
|
|
@ -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<TimelockSet>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
}): 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();
|
|
@ -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<TimelockSet>,
|
||||
state: ParsedAccount<TimelockState>,
|
||||
transaction: ParsedAccount<TimelockTransaction>,
|
||||
) => {
|
||||
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);
|
|
@ -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<TimelockSet>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
}) {
|
||||
const sigAccount = useAccountByMint(proposal.info.signatoryMint);
|
||||
if (!sigAccount) return <Spin />;
|
|
@ -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) => <span>{TimelockType[number]}</span>,
|
||||
dataIndex: 'governanceType',
|
||||
key: 'governanceType',
|
||||
render: (number: number) => <span>{GovernanceType[number]}</span>,
|
||||
},
|
||||
{
|
||||
title: LABELS.VOTING_ENTRY_RULES,
|
||||
|
@ -75,7 +75,7 @@ const columns = [
|
|||
render: (key: PublicKey) => <span>{key?.toBase58()}</span>,
|
||||
},
|
||||
{
|
||||
title: LABELS.PROGRAM,
|
||||
title: LABELS.PROGRAM_ID,
|
||||
dataIndex: 'program',
|
||||
key: 'program',
|
||||
render: (key: PublicKey) => <span>{key.toBase58()}</span>,
|
||||
|
@ -85,11 +85,11 @@ const columns = [
|
|||
title: LABELS.ACTIONS,
|
||||
dataIndex: 'config',
|
||||
key: 'config',
|
||||
render: (config: ParsedAccount<TimelockConfig>) => (
|
||||
render: (config: ParsedAccount<Governance>) => (
|
||||
<>
|
||||
<MintSourceTokens timelockConfig={config} useGovernance={true} />
|
||||
<MintSourceTokens governance={config} useGovernance={true} />
|
||||
{config.info.councilMint && (
|
||||
<MintSourceTokens timelockConfig={config} useGovernance={false} />
|
||||
<MintSourceTokens governance={config} useGovernance={false} />
|
||||
)}
|
||||
</>
|
||||
),
|
||||
|
@ -133,7 +133,7 @@ export const GovernanceDashboard = () => {
|
|||
})),
|
||||
);
|
||||
});
|
||||
}, [configs.length, myTokenAccts.join(',')]);
|
||||
}, [configs.length, myTokenAccts.join(',')]); //eslint-disable-line
|
||||
|
||||
return <Table columns={columns} dataSource={data} />;
|
||||
};
|
|
@ -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({
|
|||
</Form.Item>
|
||||
<Form.Item
|
||||
name="program"
|
||||
label={LABELS.PROGRAM}
|
||||
label={LABELS.PROGRAM_ID}
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input />
|
||||
|
@ -215,15 +215,13 @@ export function NewForm({
|
|||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="timelockType"
|
||||
name="governanceType"
|
||||
label={LABELS.PROPOSAL_TYPE}
|
||||
rules={[{ required: true }]}
|
||||
initialValue={TimelockType.CustomSingleSignerV1}
|
||||
initialValue={GovernanceType.Governance}
|
||||
>
|
||||
<Select placeholder={LABELS.SELECT_PROPOSAL_TYPE}>
|
||||
<Option value={TimelockType.CustomSingleSignerV1}>
|
||||
Single Signer
|
||||
</Option>
|
||||
<Option value={GovernanceType.Governance}>Single Signer</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
|
@ -6,7 +6,7 @@ import { TokenIcon, useWallet } from '@oyster/common';
|
|||
import { Background } from './../../components/Background';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { RegisterGovernanceMenuItem } from '../governance/register';
|
||||
import { TimelockStateStatus } from '../../models/timelock';
|
||||
import { ProposalStateStatus } from '../../models/governance';
|
||||
|
||||
export const HomeView = () => {
|
||||
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 (
|
||||
<>
|
|
@ -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 ? (
|
||||
<InnerProposalView
|
||||
proposal={proposal}
|
||||
timelockState={timelockState}
|
||||
timelockConfig={timelockConfig}
|
||||
proposalState={proposalState}
|
||||
governance={governance}
|
||||
sourceMint={sourceMint}
|
||||
votingMint={votingMint}
|
||||
yesVotingMint={yesVotingMint}
|
||||
|
@ -93,7 +94,7 @@ function useLoadGist({
|
|||
setMsg,
|
||||
setContent,
|
||||
isGist,
|
||||
timelockState,
|
||||
proposalState,
|
||||
}: {
|
||||
loading: boolean;
|
||||
setLoading: (b: boolean) => void;
|
||||
|
@ -101,11 +102,11 @@ function useLoadGist({
|
|||
setFailed: (b: boolean) => void;
|
||||
setContent: (b: string) => void;
|
||||
isGist: boolean;
|
||||
timelockState: ParsedAccount<TimelockState>;
|
||||
proposalState: ParsedAccount<ProposalState>;
|
||||
}) {
|
||||
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<TimelockSet>;
|
||||
timelockConfig: ParsedAccount<TimelockConfig>;
|
||||
timelockState: ParsedAccount<TimelockState>;
|
||||
proposal: ParsedAccount<Proposal>;
|
||||
governance: ParsedAccount<Governance>;
|
||||
proposalState: ParsedAccount<ProposalState>;
|
||||
sigMint: MintInfo;
|
||||
votingMint: MintInfo;
|
||||
yesVotingMint: MintInfo;
|
||||
noVotingMint: MintInfo;
|
||||
sourceMint: MintInfo;
|
||||
instructions: Record<string, ParsedAccount<TimelockTransaction>>;
|
||||
instructions: Record<string, ParsedAccount<GovernanceTransaction>>;
|
||||
votingDisplayData: Array<VoterDisplayData>;
|
||||
endpoint: string;
|
||||
}) {
|
||||
const sigAccount = useAccountByMint(proposal.info.signatoryMint);
|
||||
const adminAccount = useAccountByMint(proposal.info.adminMint);
|
||||
|
||||
const instructionsForProposal: ParsedAccount<TimelockTransaction>[] = timelockState.info.timelockTransactions
|
||||
const instructionsForProposal: ParsedAccount<GovernanceTransaction>[] = 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<number>();
|
||||
const [height, setHeight] = useState<number>();
|
||||
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}
|
||||
/>
|
||||
<Col>
|
||||
<h1>{timelockState.info.name}</h1>
|
||||
<StateBadge state={timelockState} />
|
||||
<h1>{proposalState.info.name}</h1>
|
||||
<StateBadge state={proposalState} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
|
@ -274,36 +277,32 @@ function InnerProposalView({
|
|||
<div className="proposal-actions">
|
||||
{adminAccount &&
|
||||
adminAccount.info.amount.toNumber() === 1 &&
|
||||
timelockState.info.status === TimelockStateStatus.Draft && (
|
||||
<AddSigners proposal={proposal} state={timelockState} />
|
||||
proposalState.info.status === ProposalStateStatus.Draft && (
|
||||
<AddSigners proposal={proposal} state={proposalState} />
|
||||
)}
|
||||
{sigAccount &&
|
||||
sigAccount.info.amount.toNumber() === 1 &&
|
||||
timelockState.info.status === TimelockStateStatus.Draft && (
|
||||
<SignButton proposal={proposal} state={timelockState} />
|
||||
proposalState.info.status === ProposalStateStatus.Draft && (
|
||||
<SignButton proposal={proposal} state={proposalState} />
|
||||
)}
|
||||
<MintSourceTokens
|
||||
timelockConfig={timelockConfig}
|
||||
governance={governance}
|
||||
useGovernance={
|
||||
proposal.info.sourceMint.toBase58() ===
|
||||
timelockConfig.info.governanceMint.toBase58()
|
||||
governance.info.governanceMint.toBase58()
|
||||
}
|
||||
/>
|
||||
<WithdrawVote
|
||||
timelockConfig={timelockConfig}
|
||||
proposal={proposal}
|
||||
state={timelockState}
|
||||
/>
|
||||
<WithdrawVote proposal={proposal} state={proposalState} />
|
||||
<Vote
|
||||
timelockConfig={timelockConfig}
|
||||
governance={governance}
|
||||
proposal={proposal}
|
||||
state={timelockState}
|
||||
state={proposalState}
|
||||
yeahVote={true}
|
||||
/>
|
||||
<Vote
|
||||
timelockConfig={timelockConfig}
|
||||
governance={governance}
|
||||
proposal={proposal}
|
||||
state={timelockState}
|
||||
state={proposalState}
|
||||
yeahVote={false}
|
||||
/>
|
||||
</div>
|
||||
|
@ -367,10 +366,10 @@ function InnerProposalView({
|
|||
<Statistic
|
||||
title={LABELS.SIG_GIVEN}
|
||||
value={
|
||||
timelockState.info.totalSigningTokensMinted.toNumber() -
|
||||
proposalState.info.totalSigningTokensMinted.toNumber() -
|
||||
sigMint.supply.toNumber()
|
||||
}
|
||||
suffix={`/ ${timelockState.info.totalSigningTokensMinted.toNumber()}`}
|
||||
suffix={`/ ${proposalState.info.totalSigningTokensMinted.toNumber()}`}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
@ -388,7 +387,7 @@ function InnerProposalView({
|
|||
<Statistic
|
||||
valueStyle={{ color: 'green' }}
|
||||
title={LABELS.VOTES_REQUIRED}
|
||||
value={getVotesRequired(timelockConfig, sourceMint)}
|
||||
value={getVotesRequired(governance, sourceMint)}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
@ -409,7 +408,7 @@ function InnerProposalView({
|
|||
<p>
|
||||
{LABELS.DESCRIPTION}:{' '}
|
||||
<a
|
||||
href={timelockState.info.descLink}
|
||||
href={proposalState.info.descLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
@ -436,17 +435,17 @@ function InnerProposalView({
|
|||
proposal={proposal}
|
||||
position={position + 1}
|
||||
instruction={instruction}
|
||||
state={timelockState}
|
||||
state={proposalState}
|
||||
/>
|
||||
</Col>
|
||||
))}
|
||||
{instructionsForProposal.length < INSTRUCTION_LIMIT &&
|
||||
timelockState.info.status === TimelockStateStatus.Draft && (
|
||||
proposalState.info.status === ProposalStateStatus.Draft && (
|
||||
<Col xs={24} sm={24} md={12} lg={8}>
|
||||
<NewInstructionCard
|
||||
proposal={proposal}
|
||||
state={timelockState}
|
||||
config={timelockConfig}
|
||||
state={proposalState}
|
||||
config={governance}
|
||||
position={instructionsForProposal.length}
|
||||
/>
|
||||
</Col>
|
||||
|
@ -462,13 +461,12 @@ function InnerProposalView({
|
|||
}
|
||||
|
||||
function getVotesRequired(
|
||||
timelockConfig: ParsedAccount<TimelockConfig>,
|
||||
governance: ParsedAccount<Governance>,
|
||||
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(),
|
||||
);
|
||||
}
|
|
@ -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({
|
|||
<Input maxLength={DESC_SIZE} placeholder={LABELS.GIST_PLACEHOLDER} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="timelockConfigKey"
|
||||
name="governanceKey"
|
||||
label={LABELS.CONFIG}
|
||||
rules={[{ required: true }]}
|
||||
>
|
|
@ -45,7 +45,7 @@ export const ProposalsView = () => {
|
|||
});
|
||||
});
|
||||
return newListData;
|
||||
}, [proposals]);
|
||||
}, [proposals, id, mint, states]);
|
||||
|
||||
return (
|
||||
<Row
|
|
@ -3,6 +3,6 @@ import React from 'react';
|
|||
if (process.env.NODE_ENV === 'development') {
|
||||
const whyDidYouRender = require('@welldone-software/why-did-you-render');
|
||||
whyDidYouRender(React, {
|
||||
trackAllPureComponents: true,
|
||||
trackAllPureComponents: false,
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue