Skip to content
This repository has been archived by the owner on Feb 9, 2025. It is now read-only.

Commit

Permalink
add discriminator and lock check for StakeDepositReceipt
Browse files Browse the repository at this point in the history
  • Loading branch information
0xShuk committed Oct 27, 2024
1 parent b13b845 commit e58bc14
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 30 deletions.
4 changes: 2 additions & 2 deletions programs/bonk-plugin/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ pub enum BonkPluginError {
InvalidTokenOwnerForVoterWeightRecord,
#[msg("The owner of the receipt does not match")]
VoterDoesNotOwnDepositReceipt,
#[msg("The stake deposit receipt is not owned by the expected program")]
InvalidStakeReceiptOwner,
#[msg("The deposit receipt was already provided")]
DuplicatedReceiptDetected,
#[msg("The stake deposit receipt has already expired")]
ExpiredStakeDepositReceipt,
#[msg("The stake deposit receipt will expire before proposal")]
InvalidStakeDuration,
#[msg("The stake deposit receipts count does not match")]
Expand Down
7 changes: 3 additions & 4 deletions programs/bonk-plugin/src/instructions/create_registrar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ pub struct CreateRegistrar<'info> {

/// CHECK: Owned by SPL Staking Program
#[account(
owner = SPL_TOKEN_STAKING_PROGRAM_ID
)]
owner = SPL_TOKEN_STAKING_PROGRAM_ID,
)]
pub stake_pool: AccountInfo<'info>,

pub governing_token_mint: Account<'info, Mint>,
Expand Down Expand Up @@ -70,8 +70,7 @@ pub fn create_registrar_handler(ctx: Context<CreateRegistrar>) -> Result<()> {
&registrar.governing_token_mint,
)?;

let stake_pool_account_info = &mut &**ctx.accounts.stake_pool.try_borrow_mut_data()?;
let stake_pool: StakePool = StakePool::deserialize(stake_pool_account_info)?;
let stake_pool = StakePool::deserialize_checked(&ctx.accounts.stake_pool)?;

require!(
realm.authority.unwrap() == ctx.accounts.realm_authority.key(),
Expand Down
31 changes: 16 additions & 15 deletions programs/bonk-plugin/src/state/registrar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use {
super::VoterWeightAction,
crate::{
error::BonkPluginError, id, state::VoterWeightRecord,
utils::stake_deposit_receipt::StakeDepositReceipt, SPL_TOKEN_STAKING_PROGRAM_ID,
utils::stake_deposit_receipt::StakeDepositReceipt,
},
anchor_lang::prelude::*,
solana_program::pubkey::Pubkey,
Expand Down Expand Up @@ -100,16 +100,9 @@ pub fn resolve_stake_deposit_weight(
BonkPluginError::MaximumDepositsReached
);

// The stake deposit receipt account must be owned by the SPL Token Staking Program
require_keys_eq!(
*stake_deposit_receipt_info.owner,
SPL_TOKEN_STAKING_PROGRAM_ID,
BonkPluginError::InvalidStakeReceiptOwner
);

let stake_deposit_receipt_buf = &mut &**stake_deposit_receipt_info.try_borrow_mut_data()?;
let stake_deposit_receipt: StakeDepositReceipt =
StakeDepositReceipt::deserialize(stake_deposit_receipt_buf)?;
StakeDepositReceipt::deserialize_checked(stake_deposit_receipt_info)?;

let stake_deposit_receipt_key = stake_deposit_receipt_info.key();

// voter_weight_record.governing_token_owner must be the owner of the stake deposit
Expand All @@ -133,6 +126,19 @@ pub fn resolve_stake_deposit_weight(

unique_stake_deposit_receipts.push(stake_deposit_receipt_key);

let stake_deposit_end_time = stake_deposit_receipt
.deposit_timestamp
.checked_add(stake_deposit_receipt.lockup_duration as i64)
.unwrap();

let current_timestamp = Clock::get()?.unix_timestamp;

require_gt!(
stake_deposit_end_time,
current_timestamp,
BonkPluginError::ExpiredStakeDepositReceipt
);

if action == VoterWeightAction::CastVote {
if let Some(proposal_info) = proposal_info {
require_keys_eq!(
Expand All @@ -141,11 +147,6 @@ pub fn resolve_stake_deposit_weight(
BonkPluginError::ActionTargetMismatch
);

let stake_deposit_end_time = stake_deposit_receipt
.deposit_timestamp
.checked_add(stake_deposit_receipt.lockup_duration as i64)
.unwrap();

let proposal_end_time =
resolve_proposal_end_time(registrar, proposal_info, governance_info)?;

Expand Down
31 changes: 31 additions & 0 deletions programs/bonk-plugin/src/utils/stake_deposit_receipt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use anchor_lang::prelude::*;

use crate::SPL_TOKEN_STAKING_PROGRAM_ID;

#[repr(C)]
#[derive(AnchorDeserialize, Debug)]
pub struct StakeDepositReceipt {
Expand All @@ -22,3 +24,32 @@ pub struct StakeDepositReceipt {
/// the StakedPool reward_pools property.
pub claimed_amounts: [u128; 10],
}

impl StakeDepositReceipt {
pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [210, 98, 254, 196, 151, 68, 235, 0];

pub fn deserialize_checked(
stake_deposit_receipt_account_info: &AccountInfo
) -> Result<Self> {
if stake_deposit_receipt_account_info.owner != &SPL_TOKEN_STAKING_PROGRAM_ID {
return Err(
anchor_lang::error!(anchor_lang::error::ErrorCode::AccountOwnedByWrongProgram)
.with_account_name("StakeDepositReceipt")
);
}

let stake_deposit_receipt_data = &stake_deposit_receipt_account_info.try_borrow_data()?;
let mut data = &mut stake_deposit_receipt_data.as_ref();

let stake_deposit_receipt = Self::try_from_slice(&mut data)?;

if stake_deposit_receipt.discriminator.to_le_bytes() != Self::ACCOUNT_DISCRIMINATOR {
return Err(
anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch)
.with_account_name("StakeDepositReceipt")
);
}

Ok(stake_deposit_receipt)
}
}
22 changes: 22 additions & 0 deletions programs/bonk-plugin/src/utils/stake_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,25 @@ pub struct RewardPool {
pub last_amount: u64,
_padding0: [u8; 8],
}

impl StakePool {
pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [121, 34, 206, 21, 79, 127, 255, 28];

pub fn deserialize_checked(
stake_pool_account_info: &AccountInfo
) -> Result<Self> {
let stake_pool_data = &stake_pool_account_info.try_borrow_data()?;
let mut data = &mut stake_pool_data.as_ref();

let stake_pool = Self::try_from_slice(&mut data)?;

if stake_pool.discriminator.to_le_bytes() != Self::ACCOUNT_DISCRIMINATOR {
return Err(
anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch)
.with_account_name("StakePool")
);
}

Ok(stake_pool)
}
}
20 changes: 11 additions & 9 deletions tests/bonk-plugin/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import idl from "../../target/idl/bonk_plugin.json";
import {StakeIdl, stakeIdl} from "./stake-idl";
import { GovernanceConfig, SplGovernance } from "governance-idl-sdk";
import secret from "../../../../sol/id.json";
import { Connection, Transaction, sendAndConfirmTransaction } from "@solana/web3.js";
import { Connection, Transaction, sendAndConfirmTransaction, clusterApiUrl } from "@solana/web3.js";
import { token } from "@coral-xyz/anchor/dist/cjs/utils";

const connection = new anchor.web3.Connection(anchor.web3.clusterApiUrl("devnet"));
const web3Connection = new Connection(anchor.web3.clusterApiUrl("devnet"));
const web3Connection = new Connection(clusterApiUrl("devnet"));
const keypair = anchor.web3.Keypair.fromSecretKey(Uint8Array.from(secret));
const wallet = new anchor.Wallet(keypair);

Expand All @@ -22,12 +22,13 @@ describe("bonk-plugin", () => {
const governanceProgramId = new anchor.web3.PublicKey("GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw")
const realm = new anchor.web3.PublicKey("A2MqSD5iEqTjBkTg9naHoS5x1YLhQemrJTcBEFXoasph")
const stakePool = new anchor.web3.PublicKey("9YbGRA8qfDeJuonKJuZYzDXcRVyB2B6cMPCWpTeC1eRL")
//8TPev5NsgJoViPrRUXp7F1HjUhmHDjzknG4i82FPVWkT
const governingTokenMint = new anchor.web3.PublicKey("6WddAU5ryy4BSNWqNPM3LsPYcirKY2ax7U2yfkzwe1kq")
const governingTokenOwner = wallet.publicKey
const previousVoterWeightPluginProgramId = new anchor.web3.PublicKey("BUsq2cFH6cmfYcoveaf52BkPaXUW3ZhTUnFybyaJrtkN")

const governanceKey = new anchor.web3.PublicKey("GyzFPcYaG6wfoi7Y3jLxAvXZWDR3nNqni1cJxkTSQHuq")
const proposalKey = new anchor.web3.PublicKey("2YX24vU9DzPjFzPPtoonJRYqGnYDe4xdULg5RKXhmYgS")
const proposalKey = new anchor.web3.PublicKey("AmGnTWwrJSszBgtRTA3j4pRL6o9GNsBuEQj3UY85AQwB")
const ownerAta = token.associatedAddress({mint: governingTokenMint, owner: keypair.publicKey})
const stakeMintToken = new anchor.web3.PublicKey("J5d7DVTTdGj7KcDtuFWL3322rasxHjpHhUmEzqFLHjuB")
const vaultAta = "5DpomEty6Rgpe46wu8dyCs8bQviFJdo2yRbxBBxH8NbM"
Expand Down Expand Up @@ -109,7 +110,6 @@ describe("bonk-plugin", () => {
// 12,
// 13,
// 14,
16
].map(i => {
const [stakeDepositReceipt] = anchor.web3.PublicKey.findProgramAddressSync(
[
Expand All @@ -127,8 +127,9 @@ describe("bonk-plugin", () => {
const remainingAccounts = stakeDepositReceipts.map(address => (
{pubkey: address, isSigner: false, isWritable: false}
))
// const remainingAccounts = [{pubkey: stakePool, isSigner: false, isWritable: false}]

xit("Is initializes registrar!", async () => {
it("Is initializes registrar!", async () => {
try {
const tx = await program.methods.createRegistrar()
.accounts({
Expand All @@ -137,7 +138,7 @@ describe("bonk-plugin", () => {
stakePool,
governingTokenMint,
realmAuthority: keypair.publicKey,
previousVoterWeightPluginProgramId
previousVoterWeightPluginProgramId: null
})
.instruction();

Expand All @@ -157,6 +158,7 @@ describe("bonk-plugin", () => {
governingTokenOwner
)
.accountsPartial({
voterWeightRecord,
registrar,
stakeDepositRecord
})
Expand All @@ -168,7 +170,7 @@ describe("bonk-plugin", () => {
// console.log("Your transaction signature", tx);
})

it("updates voter weight record", async() => {
xit("updates voter weight record", async() => {
const updateVwrIx = await program.methods.updateVoterWeightRecord(
stakeDepositReceipts.length,
proposalKey,
Expand All @@ -179,7 +181,7 @@ describe("bonk-plugin", () => {
voterWeightRecord,
inputVoterWeight,
governance: governanceKey,
proposal: null,
proposal: proposalKey,
voterAuthority: keypair.publicKey,
voterTokenOwnerRecord: tokenOwnerRecord,
})
Expand Down Expand Up @@ -208,7 +210,7 @@ describe("bonk-plugin", () => {
console.log(registrarInfo)
})

it("fetches Voter Weight Record", async() => {
xit("fetches Voter Weight Record", async() => {
const vwrInfo = await program.account.voterWeightRecord.fetch(voterWeightRecord)
console.log(vwrInfo)
console.log("THe current power is: ", vwrInfo.voterWeight.toNumber())
Expand Down

0 comments on commit e58bc14

Please sign in to comment.