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

Commit f0957ef

Browse files
authored
Release v1 code review (#40)
* chore: validate realm address against registrar * chore: validate token owner address against VoterWeightRecord * chore: validate token owner address against VoterWeightRecord * chore: Update CastNftVote comment * chore: Update CastNftVote comments * chore: use owner and executable constraints * chore: remove unnecessary mut account flag * chore: add governance account comments * chore: add NftVoteRecord seeds validation comment * chore: remove redundant spl-token dependency * chore: add missing log_version() * chore: update IDL
1 parent 3b811a1 commit f0957ef

17 files changed

+146
-43
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"arrayref",
55
"itertools",
66
"Keypair",
7+
"lamports",
78
"Metaplex",
89
"Metas",
910
"Pubkey",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solana/governance-program-library",
3-
"version": "0.14.0",
3+
"version": "0.15.0",
44
"description": "Client for Governance Program Library which is a set of extensions for Solana's spl-governance program.",
55
"author": "Solana Maintainers <[email protected]>",
66
"license": "MIT",

programs/nft-voter/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,4 @@ spl-token = { version = "3.3", features = [ "no-entrypoint" ] }
2929
[dev-dependencies]
3030
borsh = "0.9.1"
3131
solana-sdk = "1.9.5"
32-
solana-program-test = "1.9.5"
33-
spl-token = { version = "^3.3.0", features = ["no-entrypoint"] }
32+
solana-program-test = "1.9.5"

programs/nft-voter/src/error.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ pub enum NftVoterError {
55
#[msg("Invalid Realm Authority")]
66
InvalidRealmAuthority,
77

8-
#[msg("Invalid Registrar Realm")]
9-
InvalidRegistrarRealm,
8+
#[msg("Invalid Realm for Registrar")]
9+
InvalidRealmForRegistrar,
1010

1111
#[msg("Invalid Collection Size")]
1212
InvalidCollectionSize,
@@ -26,8 +26,8 @@ pub enum NftVoterError {
2626
#[msg("Invalid VoterWeightRecord Mint")]
2727
InvalidVoterWeightRecordMint,
2828

29-
#[msg("Invalid VoterWeightRecord Owner")]
30-
InvalidVoterWeightRecordOwner,
29+
#[msg("Invalid TokenOwner for VoterWeightRecord")]
30+
InvalidTokenOwnerForVoterWeightRecord,
3131

3232
#[msg("Collection must be verified")]
3333
CollectionMustBeVerified,

programs/nft-voter/src/instructions/cast_nft_vote.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ use crate::error::NftVoterError;
77

88
/// Casts NFT vote. The NFTs used for voting are tracked using NftVoteRecord accounts
99
/// This instruction updates VoterWeightRecord which is valid for the current Slot and the target Proposal only
10-
/// and hance the instruction has to be executed inside the same transaction as spl-gov CastVote
10+
/// and hance the instruction has to be executed inside the same transaction as spl-gov.CastVote
11+
///
12+
/// CastNftVote instruction and NftVoteRecord are not directional. They don't record vote choice (ex Yes/No)
13+
/// VoteChoice is recorded by spl-gov in VoteRecord and this CastNftVote only tracks voting NFTs
14+
///
1115
#[derive(Accounts)]
1216
#[instruction(proposal: Pubkey)]
1317
pub struct CastNftVote<'info> {
@@ -21,14 +25,13 @@ pub struct CastNftVote<'info> {
2125
2226
constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint
2327
@ NftVoterError::InvalidVoterWeightRecordMint,
24-
25-
constraint = voter_weight_record.governing_token_owner == governing_token_owner.key()
26-
@ NftVoterError::InvalidVoterWeightRecordOwner,
2728
)]
2829
pub voter_weight_record: Account<'info, VoterWeightRecord>,
2930

3031
/// The token owner who casts the vote
31-
#[account(mut)]
32+
#[account(
33+
address = voter_weight_record.governing_token_owner @ NftVoterError::InvalidTokenOwnerForVoterWeightRecord
34+
)]
3235
pub governing_token_owner: Signer<'info>,
3336

3437
/// The account which pays for the transaction
@@ -64,6 +67,8 @@ pub fn cast_nft_vote<'a,'b,'c,'info>(ctx: Context<'a,'b,'c,'info,CastNftVote<'in
6467
voter_weight = voter_weight.checked_add(nft_vote_weight as u64).unwrap();
6568

6669
// Create NFT vote record to ensure the same NFT hasn't been already used for voting
70+
// Note: The correct PDA of the NftVoteRecord is validated in create_and_serialize_account_signed
71+
// It ensures the NftVoteRecord is for ('nft-vote-record',proposal,nft_mint) seeds
6772
require!(
6873
nft_vote_record_info.data_is_empty(),
6974
NftVoterError::NftAlreadyVoted

programs/nft-voter/src/instructions/configure_collection.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use crate::{error::NftVoterError};
1818
#[derive(Accounts)]
1919
pub struct ConfigureCollection<'info> {
2020
/// Registrar for which we configure this Collection
21-
#[account(mut,
22-
constraint = registrar.realm == realm.key()
23-
@ NftVoterError::InvalidRegistrarRealm
24-
)]
21+
#[account(mut)]
2522
pub registrar: Account<'info, Registrar>,
2623

24+
#[account(
25+
address = registrar.realm @ NftVoterError::InvalidRealmForRegistrar,
26+
owner = registrar.governance_program_id
27+
)]
2728
/// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id
2829
pub realm: UncheckedAccount<'info>,
2930

programs/nft-voter/src/instructions/create_max_voter_weight_record.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ pub struct CreateMaxVoterWeightRecord<'info> {
2020

2121
/// The program id of the spl-governance program the realm belongs to
2222
/// CHECK: Can be any instance of spl-governance and it's not known at the compilation time
23+
#[account(executable)]
2324
pub governance_program_id: UncheckedAccount<'info>,
2425

26+
#[account(owner = governance_program_id.key())]
2527
/// CHECK: Owned by spl-governance instance specified in governance_program_id
2628
pub realm: UncheckedAccount<'info>,
2729

programs/nft-voter/src/instructions/create_registrar.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct CreateRegistrar<'info> {
2323

2424
/// The program id of the spl-governance program the realm belongs to
2525
/// CHECK: Can be any instance of spl-governance and it's not known at the compilation time
26+
#[account(executable)]
2627
pub governance_program_id: UncheckedAccount<'info>,
2728

2829
/// An spl-governance Realm
@@ -32,6 +33,7 @@ pub struct CreateRegistrar<'info> {
3233
/// - governing_token_mint must be the community or council mint
3334
/// - realm_authority is realm.authority
3435
/// CHECK: Owned by spl-governance instance specified in governance_program_id
36+
#[account(owner = governance_program_id.key())]
3537
pub realm: UncheckedAccount<'info>,
3638

3739
/// Either the realm community mint or the council mint.

programs/nft-voter/src/instructions/create_voter_weight_record.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ pub struct CreateVoterWeightRecord<'info> {
2222

2323
/// The program id of the spl-governance program the realm belongs to
2424
/// CHECK: Can be any instance of spl-governance and it's not known at the compilation time
25+
#[account(executable)]
2526
pub governance_program_id: UncheckedAccount<'info>,
2627

2728
/// CHECK: Owned by spl-governance instance specified in governance_program_id
29+
#[account(owner = governance_program_id.key())]
2830
pub realm: UncheckedAccount<'info>,
2931

3032
/// Either the realm community mint or the council mint.

programs/nft-voter/src/instructions/relinquish_nft_vote.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,28 @@ pub struct RelinquishNftVote<'info> {
2020
2121
constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint
2222
@ NftVoterError::InvalidVoterWeightRecordMint,
23-
24-
constraint = voter_weight_record.governing_token_owner == governing_token_owner.key()
25-
@ NftVoterError::InvalidVoterWeightRecordOwner,
2623
)]
2724
pub voter_weight_record: Account<'info, VoterWeightRecord>,
2825

2926
/// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id
27+
/// Governance account the Proposal is for
28+
#[account(owner = registrar.governance_program_id)]
3029
pub governance: UncheckedAccount<'info>,
3130

3231
/// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id
32+
#[account(owner = registrar.governance_program_id)]
3333
pub proposal: UncheckedAccount<'info>,
3434

3535
/// The token owner who cast the original vote
36-
#[account(mut)]
36+
#[account(
37+
address = voter_weight_record.governing_token_owner @ NftVoterError::InvalidTokenOwnerForVoterWeightRecord
38+
)]
3739
pub governing_token_owner: Signer<'info>,
3840

3941
/// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id
42+
/// The account is used to validate that it doesn't exist and if it doesn't then Anchor owner check throws error
43+
/// The check is disabled here and performed inside the instruction
44+
/// #[account(owner = registrar.governance_program_id)]
4045
pub vote_record: UncheckedAccount<'info>,
4146

4247
/// CHECK: The beneficiary who receives lamports from the disposed NftVoterRecord accounts can be any account

0 commit comments

Comments
 (0)