mirror of https://github.com/certusone/oyster.git
Governance: future proofing for v2 (#124)
* chore: update Governance account * chore: update Proposal account * chore: Update ProposalInstruction account * chore: Update Realm account * chore: update TokenOwnerRecord account * fix: add spill address to upgrade instruction * fix: display units for hold up time * chore: update program id
This commit is contained in:
parent
7f60b40d7a
commit
778265c0d6
|
@ -67,7 +67,7 @@ export const PROGRAM_IDS = [
|
||||||
{
|
{
|
||||||
name: 'mainnet-beta',
|
name: 'mainnet-beta',
|
||||||
governance: () => ({
|
governance: () => ({
|
||||||
programId: new PublicKey('GovergMfhoNZePj4v86rLXZSN4DeFSLmvKEgWCch1Zuu'),
|
programId: new PublicKey('GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw'),
|
||||||
}),
|
}),
|
||||||
wormhole: () => ({
|
wormhole: () => ({
|
||||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||||
|
@ -88,7 +88,7 @@ export const PROGRAM_IDS = [
|
||||||
{
|
{
|
||||||
name: 'testnet',
|
name: 'testnet',
|
||||||
governance: () => ({
|
governance: () => ({
|
||||||
programId: new PublicKey('GovergMfhoNZePj4v86rLXZSN4DeFSLmvKEgWCch1Zuu'),
|
programId: new PublicKey('GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw'),
|
||||||
}),
|
}),
|
||||||
wormhole: () => ({
|
wormhole: () => ({
|
||||||
pubkey: new PublicKey('5gQf5AUhAgWYgUCt9ouShm9H7dzzXUsLdssYwe5krKhg'),
|
pubkey: new PublicKey('5gQf5AUhAgWYgUCt9ouShm9H7dzzXUsLdssYwe5krKhg'),
|
||||||
|
@ -107,7 +107,7 @@ export const PROGRAM_IDS = [
|
||||||
{
|
{
|
||||||
name: 'devnet',
|
name: 'devnet',
|
||||||
governance: () => ({
|
governance: () => ({
|
||||||
programId: new PublicKey('GovergMfhoNZePj4v86rLXZSN4DeFSLmvKEgWCch1Zuu'),
|
programId: new PublicKey('GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw'),
|
||||||
}),
|
}),
|
||||||
wormhole: () => ({
|
wormhole: () => ({
|
||||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||||
|
@ -125,7 +125,7 @@ export const PROGRAM_IDS = [
|
||||||
{
|
{
|
||||||
name: 'localnet',
|
name: 'localnet',
|
||||||
governance: () => ({
|
governance: () => ({
|
||||||
programId: new PublicKey('GovergMfhoNZePj4v86rLXZSN4DeFSLmvKEgWCch1Zuu'),
|
programId: new PublicKey('GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw'),
|
||||||
}),
|
}),
|
||||||
wormhole: () => ({
|
wormhole: () => ({
|
||||||
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
pubkey: new PublicKey('WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC'),
|
||||||
|
|
|
@ -33,7 +33,7 @@ export function RealmDepositBadge({
|
||||||
)}`}
|
)}`}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{communityTokenOwnerRecord && councilTokenOwnerRecord && ', '}
|
{communityTokenOwnerRecord && councilTokenOwnerRecord && ' | '}
|
||||||
{councilTokenOwnerRecord && (
|
{councilTokenOwnerRecord && (
|
||||||
<span>
|
<span>
|
||||||
{`council tokens: ${formatTokenAmount(
|
{`council tokens: ${formatTokenAmount(
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { PublicKey } from '@solana/web3.js';
|
import { PublicKey } from '@solana/web3.js';
|
||||||
import BN from 'bn.js';
|
import BN from 'bn.js';
|
||||||
import { utils } from '@oyster/common';
|
import { utils, constants } from '@oyster/common';
|
||||||
|
|
||||||
|
const { ZERO } = constants;
|
||||||
|
|
||||||
/// Seed prefix for Governance Program PDAs
|
/// Seed prefix for Governance Program PDAs
|
||||||
export const GOVERNANCE_PROGRAM_SEED = 'governance';
|
export const GOVERNANCE_PROGRAM_SEED = 'governance';
|
||||||
|
@ -58,21 +60,45 @@ export function getAccountTypes(accountClass: GovernanceAccountClass) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum VoteThresholdPercentageType {
|
||||||
|
YesVote,
|
||||||
|
Quorum,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum VoteWeightSource {
|
||||||
|
Deposit,
|
||||||
|
Snapshot,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum InstructionExecutionStatus {
|
||||||
|
Success,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum InstructionExecutionFlags {
|
||||||
|
Ordered,
|
||||||
|
UseTransaction,
|
||||||
|
}
|
||||||
|
|
||||||
export class Realm {
|
export class Realm {
|
||||||
accountType = GovernanceAccountType.Realm;
|
accountType = GovernanceAccountType.Realm;
|
||||||
|
|
||||||
communityMint: PublicKey;
|
communityMint: PublicKey;
|
||||||
|
|
||||||
|
reserved: BN;
|
||||||
|
|
||||||
councilMint: PublicKey | undefined;
|
councilMint: PublicKey | undefined;
|
||||||
|
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
communityMint: PublicKey;
|
communityMint: PublicKey;
|
||||||
|
reserved: BN;
|
||||||
councilMint: PublicKey | undefined;
|
councilMint: PublicKey | undefined;
|
||||||
name: string;
|
name: string;
|
||||||
}) {
|
}) {
|
||||||
this.communityMint = args.communityMint;
|
this.communityMint = args.communityMint;
|
||||||
|
this.reserved = args.reserved;
|
||||||
this.councilMint = args.councilMint;
|
this.councilMint = args.councilMint;
|
||||||
this.name = args.name;
|
this.name = args.name;
|
||||||
}
|
}
|
||||||
|
@ -81,31 +107,42 @@ export class Realm {
|
||||||
export class GovernanceConfig {
|
export class GovernanceConfig {
|
||||||
realm: PublicKey;
|
realm: PublicKey;
|
||||||
governedAccount: PublicKey;
|
governedAccount: PublicKey;
|
||||||
yesVoteThresholdPercentage: number;
|
voteThresholdPercentageType: VoteThresholdPercentageType;
|
||||||
minTokensToCreateProposal: number;
|
voteThresholdPercentage: number;
|
||||||
|
minTokensToCreateProposal: BN;
|
||||||
minInstructionHoldUpTime: number;
|
minInstructionHoldUpTime: number;
|
||||||
maxVotingTime: number;
|
maxVotingTime: number;
|
||||||
|
voteWeightSource: VoteWeightSource;
|
||||||
|
proposalCoolOffTime: number;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
realm: PublicKey;
|
realm: PublicKey;
|
||||||
governedAccount: PublicKey;
|
governedAccount: PublicKey;
|
||||||
yesVoteThresholdPercentage: number;
|
voteThresholdPercentageType?: VoteThresholdPercentageType;
|
||||||
minTokensToCreateProposal: number;
|
voteThresholdPercentage: number;
|
||||||
|
minTokensToCreateProposal: BN;
|
||||||
minInstructionHoldUpTime: number;
|
minInstructionHoldUpTime: number;
|
||||||
maxVotingTime: number;
|
maxVotingTime: number;
|
||||||
|
voteWeightSource?: VoteWeightSource;
|
||||||
|
proposalCoolOffTime?: number;
|
||||||
}) {
|
}) {
|
||||||
this.realm = args.realm;
|
this.realm = args.realm;
|
||||||
this.governedAccount = args.governedAccount;
|
this.governedAccount = args.governedAccount;
|
||||||
this.yesVoteThresholdPercentage = args.yesVoteThresholdPercentage;
|
this.voteThresholdPercentageType =
|
||||||
|
args.voteThresholdPercentageType ?? VoteThresholdPercentageType.YesVote;
|
||||||
|
this.voteThresholdPercentage = args.voteThresholdPercentage;
|
||||||
this.minTokensToCreateProposal = args.minTokensToCreateProposal;
|
this.minTokensToCreateProposal = args.minTokensToCreateProposal;
|
||||||
this.minInstructionHoldUpTime = args.minInstructionHoldUpTime;
|
this.minInstructionHoldUpTime = args.minInstructionHoldUpTime;
|
||||||
this.maxVotingTime = args.maxVotingTime;
|
this.maxVotingTime = args.maxVotingTime;
|
||||||
|
this.voteWeightSource = args.voteWeightSource ?? VoteWeightSource.Deposit;
|
||||||
|
this.proposalCoolOffTime = args.proposalCoolOffTime ?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Governance {
|
export class Governance {
|
||||||
accountType: GovernanceAccountType;
|
accountType: GovernanceAccountType;
|
||||||
config: GovernanceConfig;
|
config: GovernanceConfig;
|
||||||
|
reserved: BN;
|
||||||
proposalCount: number;
|
proposalCount: number;
|
||||||
|
|
||||||
isProgramGovernance() {
|
isProgramGovernance() {
|
||||||
|
@ -127,10 +164,12 @@ export class Governance {
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
accountType: number;
|
accountType: number;
|
||||||
config: GovernanceConfig;
|
config: GovernanceConfig;
|
||||||
|
reserved?: BN;
|
||||||
proposalCount: number;
|
proposalCount: number;
|
||||||
}) {
|
}) {
|
||||||
this.accountType = args.accountType;
|
this.accountType = args.accountType;
|
||||||
this.config = args.config;
|
this.config = args.config;
|
||||||
|
this.reserved = args.reserved ?? ZERO;
|
||||||
this.proposalCount = args.proposalCount;
|
this.proposalCount = args.proposalCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,12 +185,14 @@ export class TokenOwnerRecord {
|
||||||
|
|
||||||
governingTokenDepositAmount: BN;
|
governingTokenDepositAmount: BN;
|
||||||
|
|
||||||
governanceDelegate?: PublicKey;
|
|
||||||
|
|
||||||
unrelinquishedVotesCount: number;
|
unrelinquishedVotesCount: number;
|
||||||
|
|
||||||
totalVotesCount: number;
|
totalVotesCount: number;
|
||||||
|
|
||||||
|
reserved: BN;
|
||||||
|
|
||||||
|
governanceDelegate?: PublicKey;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
realm: PublicKey;
|
realm: PublicKey;
|
||||||
governingTokenMint: PublicKey;
|
governingTokenMint: PublicKey;
|
||||||
|
@ -159,6 +200,7 @@ export class TokenOwnerRecord {
|
||||||
governingTokenDepositAmount: BN;
|
governingTokenDepositAmount: BN;
|
||||||
unrelinquishedVotesCount: number;
|
unrelinquishedVotesCount: number;
|
||||||
totalVotesCount: number;
|
totalVotesCount: number;
|
||||||
|
reserved: BN;
|
||||||
}) {
|
}) {
|
||||||
this.realm = args.realm;
|
this.realm = args.realm;
|
||||||
this.governingTokenMint = args.governingTokenMint;
|
this.governingTokenMint = args.governingTokenMint;
|
||||||
|
@ -166,6 +208,7 @@ export class TokenOwnerRecord {
|
||||||
this.governingTokenDepositAmount = args.governingTokenDepositAmount;
|
this.governingTokenDepositAmount = args.governingTokenDepositAmount;
|
||||||
this.unrelinquishedVotesCount = args.unrelinquishedVotesCount;
|
this.unrelinquishedVotesCount = args.unrelinquishedVotesCount;
|
||||||
this.totalVotesCount = args.totalVotesCount;
|
this.totalVotesCount = args.totalVotesCount;
|
||||||
|
this.reserved = args.reserved;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,31 +265,35 @@ export class Proposal {
|
||||||
|
|
||||||
signatoriesSignedOffCount: number;
|
signatoriesSignedOffCount: number;
|
||||||
|
|
||||||
descriptionLink: string;
|
|
||||||
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
yesVotesCount: BN;
|
yesVotesCount: BN;
|
||||||
|
|
||||||
noVotesCount: BN;
|
noVotesCount: BN;
|
||||||
|
|
||||||
|
instructionsExecutedCount: number;
|
||||||
|
|
||||||
|
instructionsCount: number;
|
||||||
|
|
||||||
|
instructionsNextIndex: number;
|
||||||
|
|
||||||
draftAt: BN;
|
draftAt: BN;
|
||||||
|
|
||||||
signingOffAt: BN | null;
|
signingOffAt: BN | null;
|
||||||
|
|
||||||
votingAt: BN | null;
|
votingAt: BN | null;
|
||||||
|
|
||||||
|
votingAtSlot: BN | null;
|
||||||
|
|
||||||
votingCompletedAt: BN | null;
|
votingCompletedAt: BN | null;
|
||||||
|
|
||||||
executingAt: BN | null;
|
executingAt: BN | null;
|
||||||
|
|
||||||
closedAt: BN | null;
|
closedAt: BN | null;
|
||||||
|
|
||||||
instructionsExecutedCount: number;
|
executionFlags: InstructionExecutionFlags | null;
|
||||||
|
|
||||||
instructionsCount: number;
|
name: string;
|
||||||
|
|
||||||
instructionsNextIndex: number;
|
descriptionLink: string;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
governance: PublicKey;
|
governance: PublicKey;
|
||||||
|
@ -262,12 +309,14 @@ export class Proposal {
|
||||||
draftAt: BN;
|
draftAt: BN;
|
||||||
signingOffAt: BN | null;
|
signingOffAt: BN | null;
|
||||||
votingAt: BN | null;
|
votingAt: BN | null;
|
||||||
|
votingAtSlot: BN | null;
|
||||||
votingCompletedAt: BN | null;
|
votingCompletedAt: BN | null;
|
||||||
executingAt: BN | null;
|
executingAt: BN | null;
|
||||||
closedAt: BN | null;
|
closedAt: BN | null;
|
||||||
instructionsExecutedCount: number;
|
instructionsExecutedCount: number;
|
||||||
instructionsCount: number;
|
instructionsCount: number;
|
||||||
instructionsNextIndex: number;
|
instructionsNextIndex: number;
|
||||||
|
executionFlags: InstructionExecutionFlags;
|
||||||
}) {
|
}) {
|
||||||
this.governance = args.governance;
|
this.governance = args.governance;
|
||||||
this.governingTokenMint = args.governingTokenMint;
|
this.governingTokenMint = args.governingTokenMint;
|
||||||
|
@ -282,12 +331,14 @@ export class Proposal {
|
||||||
this.draftAt = args.draftAt;
|
this.draftAt = args.draftAt;
|
||||||
this.signingOffAt = args.signingOffAt;
|
this.signingOffAt = args.signingOffAt;
|
||||||
this.votingAt = args.votingAt;
|
this.votingAt = args.votingAt;
|
||||||
|
this.votingAtSlot = args.votingAtSlot;
|
||||||
this.votingCompletedAt = args.votingCompletedAt;
|
this.votingCompletedAt = args.votingCompletedAt;
|
||||||
this.executingAt = args.executingAt;
|
this.executingAt = args.executingAt;
|
||||||
this.closedAt = args.closedAt;
|
this.closedAt = args.closedAt;
|
||||||
this.instructionsExecutedCount = args.instructionsExecutedCount;
|
this.instructionsExecutedCount = args.instructionsExecutedCount;
|
||||||
this.instructionsCount = args.instructionsCount;
|
this.instructionsCount = args.instructionsCount;
|
||||||
this.instructionsNextIndex = args.instructionsNextIndex;
|
this.instructionsNextIndex = args.instructionsNextIndex;
|
||||||
|
this.executionFlags = args.executionFlags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,19 +442,25 @@ export class InstructionData {
|
||||||
export class ProposalInstruction {
|
export class ProposalInstruction {
|
||||||
accountType = GovernanceAccountType.ProposalInstruction;
|
accountType = GovernanceAccountType.ProposalInstruction;
|
||||||
proposal: PublicKey;
|
proposal: PublicKey;
|
||||||
|
instructionIndex: number;
|
||||||
holdUpTime: number;
|
holdUpTime: number;
|
||||||
instruction: InstructionData;
|
instruction: InstructionData;
|
||||||
executedAt: BN | null;
|
executedAt: BN | null;
|
||||||
|
executionStatus: InstructionExecutionStatus | null;
|
||||||
|
|
||||||
constructor(args: {
|
constructor(args: {
|
||||||
proposal: PublicKey;
|
proposal: PublicKey;
|
||||||
|
instructionIndex: number;
|
||||||
holdUpTime: number;
|
holdUpTime: number;
|
||||||
instruction: InstructionData;
|
instruction: InstructionData;
|
||||||
executedAt: BN | null;
|
executedAt: BN | null;
|
||||||
|
executionStatus: InstructionExecutionStatus | null;
|
||||||
}) {
|
}) {
|
||||||
this.proposal = args.proposal;
|
this.proposal = args.proposal;
|
||||||
|
this.instructionIndex = args.instructionIndex;
|
||||||
this.holdUpTime = args.holdUpTime;
|
this.holdUpTime = args.holdUpTime;
|
||||||
this.instruction = args.instruction;
|
this.instruction = args.instruction;
|
||||||
this.executedAt = args.executedAt;
|
this.executedAt = args.executedAt;
|
||||||
|
this.executionStatus = args.executionStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,11 @@ export const GovernanceError: Record<number, string> = [
|
||||||
"Provided upgrade authority doesn't match current program upgrade authority", // InvalidUpgradeAuthority
|
"Provided upgrade authority doesn't match current program upgrade authority", // InvalidUpgradeAuthority
|
||||||
'Current program upgrade authority must sign transaction', // UpgradeAuthorityMustSign
|
'Current program upgrade authority must sign transaction', // UpgradeAuthorityMustSign
|
||||||
'Given program is not upgradable', //ProgramNotUpgradable
|
'Given program is not upgradable', //ProgramNotUpgradable
|
||||||
|
'Invalid token owner', //InvalidTokenOwner
|
||||||
|
'Current token owner must sign transaction', // TokenOwnerMustSign
|
||||||
|
'Given VoteThresholdPercentageType is not supported', //VoteThresholdPercentageTypeNotSupported
|
||||||
|
'Given VoteWeightSource is not supported', //VoteWeightSourceNotSupported
|
||||||
|
'Proposal cool off time is not supported', // ProposalCoolOffTimeNotSupported
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getTransactionErrorMsg(error: SendTransactionError) {
|
export function getTransactionErrorMsg(error: SendTransactionError) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ export async function createUpgradeInstruction(
|
||||||
programId: PublicKey,
|
programId: PublicKey,
|
||||||
bufferAddress: PublicKey,
|
bufferAddress: PublicKey,
|
||||||
governance: PublicKey,
|
governance: PublicKey,
|
||||||
|
spillAddress: PublicKey,
|
||||||
) {
|
) {
|
||||||
const PROGRAM_IDS = utils.programIds();
|
const PROGRAM_IDS = utils.programIds();
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ export async function createUpgradeInstruction(
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
pubkey: governance,
|
pubkey: spillAddress,
|
||||||
isWritable: true,
|
isWritable: true,
|
||||||
isSigner: false,
|
isSigner: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -259,6 +259,7 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
fields: [
|
fields: [
|
||||||
['accountType', 'u8'],
|
['accountType', 'u8'],
|
||||||
['communityMint', 'pubkey'],
|
['communityMint', 'pubkey'],
|
||||||
|
['reserved', 'u64'],
|
||||||
['councilMint', { kind: 'option', type: 'pubkey' }],
|
['councilMint', { kind: 'option', type: 'pubkey' }],
|
||||||
['name', 'string'],
|
['name', 'string'],
|
||||||
],
|
],
|
||||||
|
@ -271,6 +272,7 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
fields: [
|
fields: [
|
||||||
['accountType', 'u8'],
|
['accountType', 'u8'],
|
||||||
['config', GovernanceConfig],
|
['config', GovernanceConfig],
|
||||||
|
['reserved', 'u64'],
|
||||||
['proposalCount', 'u32'],
|
['proposalCount', 'u32'],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -282,10 +284,13 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
fields: [
|
fields: [
|
||||||
['realm', 'pubkey'],
|
['realm', 'pubkey'],
|
||||||
['governedAccount', 'pubkey'],
|
['governedAccount', 'pubkey'],
|
||||||
['yesVoteThresholdPercentage', 'u8'],
|
['voteThresholdPercentageType', 'u8'],
|
||||||
['minTokensToCreateProposal', 'u16'],
|
['voteThresholdPercentage', 'u8'],
|
||||||
|
['minTokensToCreateProposal', 'u64'],
|
||||||
['minInstructionHoldUpTime', 'u32'],
|
['minInstructionHoldUpTime', 'u32'],
|
||||||
['maxVotingTime', 'u32'],
|
['maxVotingTime', 'u32'],
|
||||||
|
['voteWeightSource', 'u8'],
|
||||||
|
['proposalCoolOffTime', 'u32'],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -299,9 +304,10 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
['governingTokenMint', 'pubkey'],
|
['governingTokenMint', 'pubkey'],
|
||||||
['governingTokenOwner', 'pubkey'],
|
['governingTokenOwner', 'pubkey'],
|
||||||
['governingTokenDepositAmount', 'u64'],
|
['governingTokenDepositAmount', 'u64'],
|
||||||
['governanceDelegate', { kind: 'option', type: 'pubkey' }],
|
|
||||||
['unrelinquishedVotesCount', 'u32'],
|
['unrelinquishedVotesCount', 'u32'],
|
||||||
['totalVotesCount', 'u32'],
|
['totalVotesCount', 'u32'],
|
||||||
|
['reserved', 'u64'],
|
||||||
|
['governanceDelegate', { kind: 'option', type: 'pubkey' }],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -317,19 +323,21 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
['tokenOwnerRecord', 'pubkey'],
|
['tokenOwnerRecord', 'pubkey'],
|
||||||
['signatoriesCount', 'u8'],
|
['signatoriesCount', 'u8'],
|
||||||
['signatoriesSignedOffCount', 'u8'],
|
['signatoriesSignedOffCount', 'u8'],
|
||||||
['descriptionLink', 'string'],
|
|
||||||
['name', 'string'],
|
|
||||||
['yesVotesCount', 'u64'],
|
['yesVotesCount', 'u64'],
|
||||||
['noVotesCount', 'u64'],
|
['noVotesCount', 'u64'],
|
||||||
['draftAt', 'u64'],
|
|
||||||
['signingOffAt', { kind: 'option', type: 'u64' }],
|
|
||||||
['votingAt', { kind: 'option', type: 'u64' }],
|
|
||||||
['votingCompletedAt', { kind: 'option', type: 'u64' }],
|
|
||||||
['executingAt', { kind: 'option', type: 'u64' }],
|
|
||||||
['closedAt', { kind: 'option', type: 'u64' }],
|
|
||||||
['instructionsExecutedCount', 'u16'],
|
['instructionsExecutedCount', 'u16'],
|
||||||
['instructionsCount', 'u16'],
|
['instructionsCount', 'u16'],
|
||||||
['instructionsNextIndex', 'u16'],
|
['instructionsNextIndex', 'u16'],
|
||||||
|
['draftAt', 'u64'],
|
||||||
|
['signingOffAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['votingAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['votingAtSlot', { kind: 'option', type: 'u64' }],
|
||||||
|
['votingCompletedAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['executingAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['closedAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['executionFlags', { kind: 'option', type: 'u8' }],
|
||||||
|
['name', 'string'],
|
||||||
|
['descriptionLink', 'string'],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -375,9 +383,11 @@ export const GOVERNANCE_SCHEMA = new Map<any, any>([
|
||||||
fields: [
|
fields: [
|
||||||
['accountType', 'u8'],
|
['accountType', 'u8'],
|
||||||
['proposal', 'pubkey'],
|
['proposal', 'pubkey'],
|
||||||
|
['instructionIndex', 'u16'],
|
||||||
['holdUpTime', 'u32'],
|
['holdUpTime', 'u32'],
|
||||||
['instruction', InstructionData],
|
['instruction', InstructionData],
|
||||||
['executedAt', { kind: 'option', type: 'u64' }],
|
['executedAt', { kind: 'option', type: 'u64' }],
|
||||||
|
['executionStatus', { kind: 'option', type: 'u8' }],
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -466,10 +466,10 @@ function getMinRequiredYesVoteScore(
|
||||||
governingTokenMint: MintInfo,
|
governingTokenMint: MintInfo,
|
||||||
): string {
|
): string {
|
||||||
const minVotes =
|
const minVotes =
|
||||||
governance.info.config.yesVoteThresholdPercentage === 100
|
governance.info.config.voteThresholdPercentage === 100
|
||||||
? governingTokenMint.supply
|
? governingTokenMint.supply
|
||||||
: governingTokenMint.supply
|
: governingTokenMint.supply
|
||||||
.mul(new BN(governance.info.config.yesVoteThresholdPercentage))
|
.mul(new BN(governance.info.config.voteThresholdPercentage))
|
||||||
.div(new BN(100));
|
.div(new BN(100));
|
||||||
|
|
||||||
return new BigNumber(minVotes.toString())
|
return new BigNumber(minVotes.toString())
|
||||||
|
|
|
@ -76,7 +76,7 @@ export function InstructionCard({
|
||||||
<>
|
<>
|
||||||
<p>{`${LABELS.INSTRUCTION}: ${instructionDetails.dataBase64}`}</p>
|
<p>{`${LABELS.INSTRUCTION}: ${instructionDetails.dataBase64}`}</p>
|
||||||
<p>
|
<p>
|
||||||
{LABELS.HOLD_UP_TIME_DAYS}: {instruction.info.holdUpTime}
|
{LABELS.HOLD_UP_TIME_DAYS}: {instruction.info.holdUpTime / 86400}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { PlusCircleOutlined } from '@ant-design/icons';
|
import { PlusCircleOutlined } from '@ant-design/icons';
|
||||||
import { ExplorerLink, ParsedAccount, utils } from '@oyster/common';
|
import { ExplorerLink, ParsedAccount, utils, contexts } from '@oyster/common';
|
||||||
import { Token } from '@solana/spl-token';
|
import { Token } from '@solana/spl-token';
|
||||||
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
import { PublicKey, TransactionInstruction } from '@solana/web3.js';
|
||||||
import {
|
import {
|
||||||
|
@ -18,7 +18,8 @@ import { AccountFormItem } from '../../../components/AccountFormItem/accountForm
|
||||||
import { Governance } from '../../../models/accounts';
|
import { Governance } from '../../../models/accounts';
|
||||||
import { createUpgradeInstruction } from '../../../models/sdkInstructions';
|
import { createUpgradeInstruction } from '../../../models/sdkInstructions';
|
||||||
import { serializeInstructionToBase64 } from '../../../models/serialisation';
|
import { serializeInstructionToBase64 } from '../../../models/serialisation';
|
||||||
import { formDefaults, formVerticalLayout } from '../../../tools/forms';
|
import { formDefaults } from '../../../tools/forms';
|
||||||
|
const { useWallet } = contexts.Wallet;
|
||||||
|
|
||||||
export default function InstructionInput({
|
export default function InstructionInput({
|
||||||
governance,
|
governance,
|
||||||
|
@ -116,17 +117,24 @@ const UpgradeProgramForm = ({
|
||||||
governance: ParsedAccount<Governance>;
|
governance: ParsedAccount<Governance>;
|
||||||
onCreateInstruction: (instruction: TransactionInstruction) => void;
|
onCreateInstruction: (instruction: TransactionInstruction) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const { wallet } = useWallet();
|
||||||
|
|
||||||
|
if (!wallet?.publicKey) {
|
||||||
|
return <div>Wallet not connected</div>;
|
||||||
|
}
|
||||||
|
|
||||||
const onCreate = async ({ bufferAddress }: { bufferAddress: string }) => {
|
const onCreate = async ({ bufferAddress }: { bufferAddress: string }) => {
|
||||||
const upgradeIx = await createUpgradeInstruction(
|
const upgradeIx = await createUpgradeInstruction(
|
||||||
governance.info.config.governedAccount,
|
governance.info.config.governedAccount,
|
||||||
new PublicKey(bufferAddress),
|
new PublicKey(bufferAddress),
|
||||||
governance.pubkey,
|
governance.pubkey,
|
||||||
|
wallet.publicKey!,
|
||||||
);
|
);
|
||||||
onCreateInstruction(upgradeIx);
|
onCreateInstruction(upgradeIx);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...formVerticalLayout} form={form} onFinish={onCreate}>
|
<Form {...formDefaults} form={form} onFinish={onCreate}>
|
||||||
<Form.Item label="program id">
|
<Form.Item label="program id">
|
||||||
<ExplorerLink
|
<ExplorerLink
|
||||||
address={governance.info.config.governedAccount}
|
address={governance.info.config.governedAccount}
|
||||||
|
@ -136,6 +144,9 @@ const UpgradeProgramForm = ({
|
||||||
<Form.Item label="upgrade authority (governance account)">
|
<Form.Item label="upgrade authority (governance account)">
|
||||||
<ExplorerLink address={governance.pubkey} type="address" />
|
<ExplorerLink address={governance.pubkey} type="address" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label="spill account (wallet)">
|
||||||
|
<ExplorerLink address={wallet.publicKey} type="address" />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="bufferAddress"
|
name="bufferAddress"
|
||||||
label="buffer address"
|
label="buffer address"
|
||||||
|
@ -179,7 +190,7 @@ const MintToForm = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
{...formVerticalLayout}
|
{...formDefaults}
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={onCreate}
|
onFinish={onCreate}
|
||||||
initialValues={{ amount: 1 }}
|
initialValues={{ amount: 1 }}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { useProposalAuthority } from '../../../hooks/apiHooks';
|
||||||
import { insertInstruction } from '../../../actions/insertInstruction';
|
import { insertInstruction } from '../../../actions/insertInstruction';
|
||||||
import '../style.less';
|
import '../style.less';
|
||||||
|
|
||||||
import { formVerticalLayout } from '../../../tools/forms';
|
import { formDefaults } from '../../../tools/forms';
|
||||||
import InstructionInput from './InstructionInput';
|
import InstructionInput from './InstructionInput';
|
||||||
|
|
||||||
const { useWallet } = contexts.Wallet;
|
const { useWallet } = contexts.Wallet;
|
||||||
|
@ -47,7 +47,7 @@ export function NewInstructionCard({
|
||||||
proposal,
|
proposal,
|
||||||
proposalAuthority!.pubkey,
|
proposalAuthority!.pubkey,
|
||||||
index,
|
index,
|
||||||
values.holdUpTime,
|
values.holdUpTime * 86400,
|
||||||
values.instruction,
|
values.instruction,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -57,18 +57,20 @@ export function NewInstructionCard({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const minHoldUpTime = governance.info.config.minInstructionHoldUpTime / 86400;
|
||||||
|
|
||||||
return !proposalAuthority ? null : (
|
return !proposalAuthority ? null : (
|
||||||
<Card
|
<Card
|
||||||
title="New Instruction"
|
title="New Instruction"
|
||||||
actions={[<SaveOutlined key="save" onClick={form.submit} />]}
|
actions={[<SaveOutlined key="save" onClick={form.submit} />]}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
{...formVerticalLayout}
|
{...formDefaults}
|
||||||
form={form}
|
form={form}
|
||||||
name="control-hooks"
|
name="control-hooks"
|
||||||
onFinish={onFinish}
|
onFinish={onFinish}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
holdUpTime: governance.info.config.minInstructionHoldUpTime,
|
holdUpTime: minHoldUpTime,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
@ -76,15 +78,12 @@ export function NewInstructionCard({
|
||||||
label={LABELS.HOLD_UP_TIME_DAYS}
|
label={LABELS.HOLD_UP_TIME_DAYS}
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<InputNumber
|
<InputNumber min={minHoldUpTime} />
|
||||||
maxLength={64}
|
|
||||||
min={governance.info.config.minInstructionHoldUpTime}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="instruction"
|
name="instruction"
|
||||||
label="Instruction"
|
label="instruction"
|
||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<InstructionInput governance={governance}></InstructionInput>
|
<InstructionInput governance={governance}></InstructionInput>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { useKeyParam } from '../../hooks/useKeyParam';
|
||||||
import { ModalFormAction } from '../../components/ModalFormAction/modalFormAction';
|
import { ModalFormAction } from '../../components/ModalFormAction/modalFormAction';
|
||||||
|
|
||||||
import { AccountFormItem } from '../../components/AccountFormItem/accountFormItem';
|
import { AccountFormItem } from '../../components/AccountFormItem/accountFormItem';
|
||||||
|
import BN from 'bn.js';
|
||||||
|
|
||||||
const { useWallet } = contexts.Wallet;
|
const { useWallet } = contexts.Wallet;
|
||||||
const { useConnection } = contexts.Connection;
|
const { useConnection } = contexts.Connection;
|
||||||
|
@ -42,8 +43,8 @@ export function RegisterGovernance({
|
||||||
const config = new GovernanceConfig({
|
const config = new GovernanceConfig({
|
||||||
realm: realmKey,
|
realm: realmKey,
|
||||||
governedAccount: new PublicKey(values.governedAccountAddress),
|
governedAccount: new PublicKey(values.governedAccountAddress),
|
||||||
yesVoteThresholdPercentage: values.yesVoteThresholdPercentage,
|
voteThresholdPercentage: values.yesVoteThresholdPercentage,
|
||||||
minTokensToCreateProposal: values.minTokensToCreateProposal,
|
minTokensToCreateProposal: new BN(values.minTokensToCreateProposal),
|
||||||
minInstructionHoldUpTime: values.minInstructionHoldUpTime * 86400,
|
minInstructionHoldUpTime: values.minInstructionHoldUpTime * 86400,
|
||||||
maxVotingTime: values.maxVotingTime * 86400,
|
maxVotingTime: values.maxVotingTime * 86400,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue