Skip to content

Commit

Permalink
add bonk plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
0xShuk committed Nov 7, 2024
1 parent 54acd3e commit e630cd2
Show file tree
Hide file tree
Showing 16 changed files with 6,701 additions and 12 deletions.
172 changes: 172 additions & 0 deletions BonkVotePlugin/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { Provider, BN, Program } from "@coral-xyz/anchor";
import { Keypair, PublicKey, TransactionInstruction } from "@solana/web3.js";
import idl from "./idl.json";
import tokenIdl from "./token-idl.json";
import {BonkPlugin} from "./type";
import { Client } from "@solana/governance-program-library";
import { fetchRealmByPubkey } from "@hooks/queries/realm";
import { TokenVoter } from "./token-type";
import { bonkRegistrarKey, bonkSdrKey, bonkVwrKey, tokenVoterKey, tokenVwrKey } from "./utils";
import { SplTokenStaking,stakingIdl } from "./stake";
import { VoterWeightAction, getTokenOwnerRecordAddress } from "@solana/spl-governance";
import { BONK_PLUGIN_PK } from "@constants/plugins";

export class BonkClient extends Client<BonkPlugin> {
readonly requiresInputVoterWeight = true
private tokenPlugin: Program<TokenVoter>
private splTokenStaking: Program<SplTokenStaking>

constructor(
public program: Program<BonkPlugin>,
tokenVoterProgram: Program<TokenVoter>,
splTokenProgram: Program<SplTokenStaking>
) {
super(program)
this.tokenPlugin = tokenVoterProgram
this.splTokenStaking = splTokenProgram
}

private async fetchSdrs(
voter: PublicKey,
stakePool: PublicKey
) {
const sdrs = await this.splTokenStaking.account.stakeDepositReceipt.all([
{
memcmp: {
offset: 8,
bytes: voter.toBase58(),
}
},
{
memcmp: {
offset: 72,
bytes: stakePool.toBase58(),
},
}
])

const activeSdrs = sdrs.filter(sdr =>
sdr.account.depositTimestamp.add(sdr.account.lockupDuration).toNumber() > Date.now() /1000
)

return activeSdrs
}

async calculateMaxVoterWeight(
_realm: PublicKey,
_mint: PublicKey
): Promise<BN | null> {
const { result: realm } = await fetchRealmByPubkey(
this.program.provider.connection,
_realm
)

return realm?.account.config?.communityMintMaxVoteWeightSource.value ?? null // TODO this code should not actually be called because this is not a max voter weight plugin
}


async calculateVoterWeight(
voter: PublicKey,
realm: PublicKey,
mint: PublicKey
): Promise<BN | null> {
try {
console.log("I have been called")
const bonkRegistrarAddress = bonkRegistrarKey(realm, mint, this.program.programId)
const bonkRegistrar = await this.program.account.registrar.fetch(bonkRegistrarAddress)

const tokenVoterAddress = tokenVoterKey(realm, mint, voter, this.tokenPlugin.programId)[0]
const tokenVoterAccount = await this.tokenPlugin.account.voter.fetch(tokenVoterAddress)
const depositedTokens = tokenVoterAccount.deposits[0].amountDepositedNative
const activeSdrs = await this.fetchSdrs(voter, bonkRegistrar.stakePool)
const sdrBalance = activeSdrs.reduce((a,b) => a.add(b.account.depositAmount), new BN(0))
return depositedTokens.add(sdrBalance)
} catch(e) {
console.log(e)
return null
}
}

async updateVoterWeightRecord(
voter: PublicKey,
realm: PublicKey,
mint: PublicKey,
action?: VoterWeightAction,
//inputRecordCallback?: (() => Promise<PublicKey>) | undefined
): Promise<{
pre: TransactionInstruction[]
post?: TransactionInstruction[] | undefined
}> {
const tokenVwrAddress = tokenVwrKey(realm, mint, voter, this.tokenPlugin.programId)[0]
const bonkVwrAddresss = bonkVwrKey(realm, mint, voter, this.program.programId)[0]
const sdrAddress = bonkSdrKey(bonkVwrAddresss, this.program.programId)[0]
const bonkRegistrarAddress = bonkRegistrarKey(realm, mint, this.program.programId)
const bonkRegistrar = await this.program.account.registrar.fetch(bonkRegistrarAddress)
const tokenOwnerRecord = await getTokenOwnerRecordAddress(
bonkRegistrar.governanceProgramId, realm, mint, voter
)

const proposal = Keypair.generate().publicKey
const governance = Keypair.generate().publicKey

const activeSdrs = await this.fetchSdrs(voter, bonkRegistrar.stakePool)
const remainingAccounts = activeSdrs.map(sdr => ({
pubkey: sdr.publicKey,
isWritable: false,
isSigner: false
}))

const bonkUpdateIx = await this.program.methods.updateVoterWeightRecord(
activeSdrs.length,
proposal,
{createProposal: {}}
).accounts({
registrar: bonkRegistrarAddress,
voterWeightRecord: bonkVwrAddresss,
inputVoterWeight: tokenVwrAddress,
governance,
proposal,
voterAuthority: voter,
voterTokenOwnerRecord: tokenOwnerRecord,
stakeDepositRecord: sdrAddress
})
.remainingAccounts(remainingAccounts)
.instruction()

return {pre: [bonkUpdateIx]}
}

// NO-OP
async createMaxVoterWeightRecord(): Promise<TransactionInstruction | null> {
return null
}

// NO-OP
async updateMaxVoterWeightRecord(): Promise<TransactionInstruction | null> {
return null
}

static async connect(
provider: Provider,
programId = new PublicKey(BONK_PLUGIN_PK),
) {
const DEFAULT_TOKEN_VOTER_PROGRAMID = new PublicKey("HA99cuBQCCzZu1zuHN2qBxo2FBo1cxNLwKkdt6Prhy8v")
const DEFAULT_SPL_STAKING_PROGRAMID = new PublicKey("STAKEkKzbdeKkqzKpLkNQD3SUuLgshDKCD7U8duxAbB")
console.log(programId.toBase58(), "Main kayah")
return new BonkClient(
new Program<BonkPlugin>(idl as BonkPlugin, programId, provider),
new Program<TokenVoter>(tokenIdl as TokenVoter, DEFAULT_TOKEN_VOTER_PROGRAMID, provider),
new Program<SplTokenStaking>(stakingIdl as SplTokenStaking, DEFAULT_SPL_STAKING_PROGRAMID, provider)
)
}

async createVoterWeightRecord(
voter: PublicKey,
realm: PublicKey,
mint: PublicKey
): Promise<TransactionInstruction | null> {
return null
}

}

67 changes: 67 additions & 0 deletions BonkVotePlugin/components/BalanceCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { GovernancePowerTitle } from "@components/TokenBalance/TokenBalanceCardWrapper"
import { TokenDeposit } from "@components/TokenBalance/TokenDeposit"
import { BN } from "@coral-xyz/anchor"
import { useRealmCommunityMintInfoQuery, useRealmCouncilMintInfoQuery } from "@hooks/queries/mintInfo"
import { useRealmQuery } from "@hooks/queries/realm"
import { useRealmVoterWeightPlugins } from "@hooks/useRealmVoterWeightPlugins"
import useWalletOnePointOh from "@hooks/useWalletOnePointOh"
import { GoverningTokenRole } from "@solana/spl-governance"

const BonkBalanceCard = () => {
const mint = useRealmCommunityMintInfoQuery().data?.result
const councilMint = useRealmCouncilMintInfoQuery().data?.result
const realm = useRealmQuery().data?.result

const wallet = useWalletOnePointOh()
const connected = !!wallet?.connected
const {
ownVoterWeight: communityOwnVoterWeight,
} = useRealmVoterWeightPlugins('community')
const councilDepositVisible = realm?.account.config.councilMint !== undefined

return (
<>
{mint ? (
<div className={`${`w-full gap-8 md:gap-12`}`}>
<GovernancePowerTitle />
{!connected && (
<div className={'text-xs text-white/50 mt-8'}>
Connect your wallet to see governance power
</div>
)}
<div className="w-full">
{
communityOwnVoterWeight &&
<div className="">
<div className="flex flex-row items-center gap-x-2">
<h3>Bonk Power:</h3>
<h3 className="">
{communityOwnVoterWeight.value?.div(new BN(10**mint.decimals)).toNumber()}.
{communityOwnVoterWeight.value?.mod(new BN(10**mint.decimals)).toNumber()} {' '}
</h3>
</div>
<div className="text-orange text-sm mb-4">
<a href="https://bonkdao.com">Kindly visit bonkdao.com to adjust governing power</a>
</div>
</div>
}
{councilDepositVisible && (
<TokenDeposit
mint={councilMint}
tokenRole={GoverningTokenRole.Council}
inAccountDetails={true}
/>
)}
</div>
</div>
) : (
<>
<div className="h-12 mb-4 rounded-lg animate-pulse bg-bkg-3" />
<div className="h-10 rounded-lg animate-pulse bg-bkg-3" />
</>
)}
</>
)
}

export default BonkBalanceCard
Loading

0 comments on commit e630cd2

Please sign in to comment.