Skip to content

Commit

Permalink
feat: create election's governance (#388)
Browse files Browse the repository at this point in the history
* CHeckpoint

* Continue

* Continue

* Cleanup

* Bump program version

* Cleanup

* Continue

* Continue

* add comment
  • Loading branch information
guibescos authored Feb 21, 2024
1 parent d104cff commit 9037f96
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
50 changes: 50 additions & 0 deletions frontend/pages/create_election_governance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { NextPage } from 'next'
import Layout from '../components/Layout'
import SEO from '../components/SEO'
import { StakeAccount } from '@pythnetwork/staking'
import { useEffect, useState } from 'react'
import toast from 'react-hot-toast'
import { capitalizeFirstLetter } from 'utils/capitalizeFirstLetter'
import { useStakeConnection } from 'hooks/useStakeConnection'
import { useStakeAccounts } from 'hooks/useStakeAccounts'

const CreateElectionGovernance: NextPage = () => {
const { data: stakeConnection } = useStakeConnection()
const { data: stakeAccounts } = useStakeAccounts()
const [selectedStakeAccount, setSelectStakeAccount] = useState<StakeAccount>()

useEffect(() => {
if (stakeAccounts && stakeAccounts.length > 0)
setSelectStakeAccount(stakeAccounts[0])
}, [stakeAccounts])

const createElectionGovernance = async () => {
if (stakeConnection && selectedStakeAccount)
try {
await stakeConnection.createElectionGovernance(selectedStakeAccount)
toast.success('Successfully created election governance')
} catch (err) {
toast.error(capitalizeFirstLetter(err.message))
}
}

return (
<Layout>
<SEO title={'Create election governance'} />
{stakeConnection ? (
<p>
<button
className="rounded-full p-2 hover:bg-hoverGray"
onClick={() => createElectionGovernance()}
>
Click to approve
</button>
</p>
) : (
<p className="p-2 hover:bg-hoverGray"> Please connect wallet</p>
)}
</Layout>
)
}

export default CreateElectionGovernance
66 changes: 66 additions & 0 deletions staking/app/StakeConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ import { batchInstructions } from "./transaction";
import { PythBalance } from "./pythBalance";
import {
getTokenOwnerRecordAddress,
GovernanceConfig,
PROGRAM_VERSION,
PROGRAM_VERSION_V2,
VoteThreshold,
VoteThresholdType,
VoteTipping,
withCreateGovernance,
withCreateTokenOwnerRecord,
} from "@solana/spl-governance";
import {
EPOCH_DURATION,
GOVERNANCE_ADDRESS,
REALM_ID,
STAKING_ADDRESS,
WALLET_TESTER_ADDRESS,
} from "./constants";
Expand Down Expand Up @@ -1068,6 +1076,64 @@ export class StakeConnection {
timeOfFirstStake,
};
}

// This is a helper to create the election governance from the UI.
// The address is hardcoded so it can only be run once.
public async createElectionGovernance(stakeAccount: StakeAccount) {
const governanceConfig = new GovernanceConfig({
communityVoteThreshold: new VoteThreshold({
type: VoteThresholdType.YesVotePercentage,
value: 1, // 1%, irrelevant since the proposals won't be executed
}),
minCommunityTokensToCreateProposal: new BN(
wasm.Constants.MAX_VOTER_WEIGHT().toString()
).div(new BN(20000)), // 0.5 basis points of the staked supply
minInstructionHoldUpTime: 0, // irrelevant since the proposals won't be executed
baseVotingTime: EPOCH_DURATION, // Is equal to 1 Pyth epoch
communityVoteTipping: VoteTipping.Disabled, // Let it run for the full duration
minCouncilTokensToCreateProposal: new BN(1), // Not used since we don't have a council

// V3
councilVoteThreshold: new VoteThreshold({
type: VoteThresholdType.Disabled,
}),
councilVetoVoteThreshold: new VoteThreshold({
type: VoteThresholdType.Disabled,
}),
communityVetoVoteThreshold: new VoteThreshold({
type: VoteThresholdType.Disabled,
}),
councilVoteTipping: VoteTipping.Disabled, // Not used since we don't have a council
votingCoolOffTime: 0,
depositExemptProposalCount: 100,
});

const tx = new Transaction();

const { voterWeightAccount, maxVoterWeightRecord } =
await this.withUpdateVoterWeight(tx.instructions, stakeAccount, {
createGovernance: {},
});
await withCreateGovernance(
tx.instructions,
GOVERNANCE_ADDRESS(),
PROGRAM_VERSION,
REALM_ID,
new PublicKey("6oXTdojyfDS8m5VtTaYB9xRCxpKGSvKJFndLUPV3V3wT"), // this seed is the authority of the pythian multisig
governanceConfig,
await getTokenOwnerRecordAddress(
GOVERNANCE_ADDRESS(),
REALM_ID,
this.config.pythTokenMint,
this.userPublicKey()
),
this.userPublicKey(),
this.userPublicKey(),
voterWeightAccount
);

await this.provider.sendAndConfirm(tx);
}
}

export interface BalanceSummary {
Expand Down

0 comments on commit 9037f96

Please sign in to comment.