From 0529118fa5288423e509dd35c6b6f511ad2f8b73 Mon Sep 17 00:00:00 2001 From: Tony Boyle <81017245+tonyboylehub@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:06:29 +0100 Subject: [PATCH 01/18] initial commit --- Cargo.lock | 64 + programs/core-voter/Cargo.toml | 35 + programs/core-voter/Xargo.toml | 2 + programs/core-voter/src/error.rs | 76 + .../src/instructions/cast_nft_vote.rs | 144 ++ .../src/instructions/configure_collection.rs | 114 ++ .../create_max_voter_weight_record.rs | 57 + .../src/instructions/create_registrar.rs | 81 + .../create_voter_weight_record.rs | 63 + programs/core-voter/src/instructions/mod.rs | 20 + .../src/instructions/relinquish_nft_vote.rs | 149 ++ .../update_voter_weight_record.rs | 76 + programs/core-voter/src/lib.rs | 69 + .../core-voter/src/state/collection_config.rs | 28 + programs/core-voter/src/state/idl_types.rs | 17 + .../src/state/max_voter_weight_record.rs | 96 ++ programs/core-voter/src/state/mod.rs | 15 + .../core-voter/src/state/nft_vote_record.rs | 84 + programs/core-voter/src/state/registrar.rs | 171 ++ .../src/state/voter_weight_record.rs | 110 ++ programs/core-voter/src/tools/anchor.rs | 1 + programs/core-voter/src/tools/governance.rs | 19 + programs/core-voter/src/tools/mod.rs | 4 + programs/core-voter/src/tools/spl_token.rs | 15 + .../core-voter/src/tools/token_metadata.rs | 32 + programs/core-voter/tests/cast_nft_vote.rs | 1370 +++++++++++++++++ .../core-voter/tests/configure_collection.rs | 413 +++++ .../tests/create_max_voter_weight_record.rs | 127 ++ programs/core-voter/tests/create_registrar.rs | 156 ++ .../tests/create_voter_weight_record.rs | 127 ++ .../tests/fixtures/mpl_token_metadata.so | Bin 0 -> 693904 bytes .../tests/fixtures/spl_governance.so | Bin 0 -> 673864 bytes .../tests/program_test/governance_test.rs | 432 ++++++ programs/core-voter/tests/program_test/mod.rs | 5 + .../tests/program_test/nft_voter_test.rs | 597 +++++++ .../tests/program_test/program_test_bench.rs | 328 ++++ .../tests/program_test/token_metadata_test.rs | 253 +++ .../core-voter/tests/program_test/tools.rs | 93 ++ .../core-voter/tests/relinquish_nft_vote.rs | 649 ++++++++ .../tests/update_voter_weight_record.rs | 575 +++++++ 40 files changed, 6667 insertions(+) create mode 100644 programs/core-voter/Cargo.toml create mode 100644 programs/core-voter/Xargo.toml create mode 100644 programs/core-voter/src/error.rs create mode 100644 programs/core-voter/src/instructions/cast_nft_vote.rs create mode 100644 programs/core-voter/src/instructions/configure_collection.rs create mode 100644 programs/core-voter/src/instructions/create_max_voter_weight_record.rs create mode 100644 programs/core-voter/src/instructions/create_registrar.rs create mode 100644 programs/core-voter/src/instructions/create_voter_weight_record.rs create mode 100644 programs/core-voter/src/instructions/mod.rs create mode 100644 programs/core-voter/src/instructions/relinquish_nft_vote.rs create mode 100644 programs/core-voter/src/instructions/update_voter_weight_record.rs create mode 100644 programs/core-voter/src/lib.rs create mode 100644 programs/core-voter/src/state/collection_config.rs create mode 100644 programs/core-voter/src/state/idl_types.rs create mode 100644 programs/core-voter/src/state/max_voter_weight_record.rs create mode 100644 programs/core-voter/src/state/mod.rs create mode 100644 programs/core-voter/src/state/nft_vote_record.rs create mode 100644 programs/core-voter/src/state/registrar.rs create mode 100644 programs/core-voter/src/state/voter_weight_record.rs create mode 100644 programs/core-voter/src/tools/anchor.rs create mode 100644 programs/core-voter/src/tools/governance.rs create mode 100644 programs/core-voter/src/tools/mod.rs create mode 100644 programs/core-voter/src/tools/spl_token.rs create mode 100644 programs/core-voter/src/tools/token_metadata.rs create mode 100644 programs/core-voter/tests/cast_nft_vote.rs create mode 100644 programs/core-voter/tests/configure_collection.rs create mode 100644 programs/core-voter/tests/create_max_voter_weight_record.rs create mode 100644 programs/core-voter/tests/create_registrar.rs create mode 100644 programs/core-voter/tests/create_voter_weight_record.rs create mode 100644 programs/core-voter/tests/fixtures/mpl_token_metadata.so create mode 100755 programs/core-voter/tests/fixtures/spl_governance.so create mode 100644 programs/core-voter/tests/program_test/governance_test.rs create mode 100644 programs/core-voter/tests/program_test/mod.rs create mode 100644 programs/core-voter/tests/program_test/nft_voter_test.rs create mode 100644 programs/core-voter/tests/program_test/program_test_bench.rs create mode 100644 programs/core-voter/tests/program_test/token_metadata_test.rs create mode 100644 programs/core-voter/tests/program_test/tools.rs create mode 100644 programs/core-voter/tests/relinquish_nft_vote.rs create mode 100644 programs/core-voter/tests/update_voter_weight_record.rs diff --git a/Cargo.lock b/Cargo.lock index 1b111da7..97b34a10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -632,6 +632,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -1814,6 +1820,25 @@ dependencies = [ "spl-token", ] +[[package]] +name = "gpl-core-voter" +version = "0.2.2" +dependencies = [ + "anchor-lang", + "anchor-spl", + "arrayref", + "borsh 0.10.3", + "itertools", + "mpl-core", + "mpl-token-metadata", + "solana-program", + "solana-program-test", + "solana-sdk", + "spl-governance", + "spl-governance-tools", + "spl-token", +] + [[package]] name = "gpl-nft-voter" version = "0.2.2" @@ -2499,6 +2524,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "mpl-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d4f516cd9daae872182a50850ab6d5588667e71152d49b0729a32830036b83" +dependencies = [ + "base64 0.22.1", + "borsh 0.10.3", + "modular-bitfield", + "num-derive 0.3.3", + "num-traits", + "rmp-serde", + "serde_json", + "solana-program", + "thiserror", +] + [[package]] name = "mpl-token-metadata" version = "4.1.2" @@ -3387,6 +3429,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rpassword" version = "7.3.1" diff --git a/programs/core-voter/Cargo.toml b/programs/core-voter/Cargo.toml new file mode 100644 index 00000000..cd09dbfd --- /dev/null +++ b/programs/core-voter/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "gpl-core-voter" +version = "0.2.2" +description = "SPL Governance addin implementing Metaplex Core NFT Asset based governance" +license = "Apache-2.0" +edition = "2018" + +[lib] +crate-type = ["cdylib", "lib"] +name = "gpl_nft_voter" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] + +[dependencies] +arrayref = "0.3.6" +anchor-lang = { version = "0.30.1", features = ["init-if-needed"] } +anchor-spl = { version = "0.30.1", features = ["token"] } +itertools = "0.10.2" +mpl-token-metadata = "^4.1.2" +mpl-core = "0.7.1" +solana-program = "1.18.18" +spl-governance = { version = "4.0", features = ["no-entrypoint"] } +spl-governance-tools = "0.1.4" +spl-token = { version = "4.0", features = [ "no-entrypoint" ] } + +[dev-dependencies] +borsh = "0.10.3" +solana-sdk = "1.18.18" +solana-program-test = "1.18.18" \ No newline at end of file diff --git a/programs/core-voter/Xargo.toml b/programs/core-voter/Xargo.toml new file mode 100644 index 00000000..475fb71e --- /dev/null +++ b/programs/core-voter/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/programs/core-voter/src/error.rs b/programs/core-voter/src/error.rs new file mode 100644 index 00000000..ab01160e --- /dev/null +++ b/programs/core-voter/src/error.rs @@ -0,0 +1,76 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum NftVoterError { + #[msg("Invalid Realm Authority")] + InvalidRealmAuthority, + + #[msg("Invalid Realm for Registrar")] + InvalidRealmForRegistrar, + + #[msg("Invalid Collection Size")] + InvalidCollectionSize, + + #[msg("Invalid MaxVoterWeightRecord Realm")] + InvalidMaxVoterWeightRecordRealm, + + #[msg("Invalid MaxVoterWeightRecord Mint")] + InvalidMaxVoterWeightRecordMint, + + #[msg("CastVote Is Not Allowed")] + CastVoteIsNotAllowed, + + #[msg("Invalid VoterWeightRecord Realm")] + InvalidVoterWeightRecordRealm, + + #[msg("Invalid VoterWeightRecord Mint")] + InvalidVoterWeightRecordMint, + + #[msg("Invalid TokenOwner for VoterWeightRecord")] + InvalidTokenOwnerForVoterWeightRecord, + + #[msg("Collection must be verified")] + CollectionMustBeVerified, + + #[msg("Voter does not own NFT")] + VoterDoesNotOwnNft, + + #[msg("Collection not found")] + CollectionNotFound, + + #[msg("Missing Metadata collection")] + MissingMetadataCollection, + + #[msg("Token Metadata doesn't match")] + TokenMetadataDoesNotMatch, + + #[msg("Invalid account owner")] + InvalidAccountOwner, + + #[msg("Invalid token metadata account")] + InvalidTokenMetadataAccount, + + #[msg("Duplicated NFT detected")] + DuplicatedNftDetected, + + #[msg("Invalid NFT amount")] + InvalidNftAmount, + + #[msg("NFT already voted")] + NftAlreadyVoted, + + #[msg("Invalid Proposal for NftVoteRecord")] + InvalidProposalForNftVoteRecord, + + #[msg("Invalid TokenOwner for NftVoteRecord")] + InvalidTokenOwnerForNftVoteRecord, + + #[msg("VoteRecord must be withdrawn")] + VoteRecordMustBeWithdrawn, + + #[msg("Invalid VoteRecord for NftVoteRecord")] + InvalidVoteRecordForNftVoteRecord, + + #[msg("VoterWeightRecord must be expired")] + VoterWeightRecordMustBeExpired, +} diff --git a/programs/core-voter/src/instructions/cast_nft_vote.rs b/programs/core-voter/src/instructions/cast_nft_vote.rs new file mode 100644 index 00000000..c869deb7 --- /dev/null +++ b/programs/core-voter/src/instructions/cast_nft_vote.rs @@ -0,0 +1,144 @@ +use crate::error::NftVoterError; +use crate::{id, state::*}; +use anchor_lang::prelude::*; +use anchor_lang::Accounts; +use itertools::Itertools; +use spl_governance_tools::account::create_and_serialize_account_signed; + +/// Casts NFT vote. The NFTs used for voting are tracked using NftVoteRecord accounts +/// This instruction updates VoterWeightRecord which is valid for the current Slot and the target Proposal only +/// and hance the instruction has to be executed inside the same transaction as spl-gov.CastVote +/// +/// CastNftVote is accumulative and can be invoked using several transactions if voter owns more than 5 NFTs to calculate total voter_weight +/// In this scenario only the last CastNftVote should be bundled with spl-gov.CastVote in the same transaction +/// +/// CastNftVote instruction and NftVoteRecord are not directional. They don't record vote choice (ex Yes/No) +/// VoteChoice is recorded by spl-gov in VoteRecord and this CastNftVote only tracks voting NFTs +/// +#[derive(Accounts)] +#[instruction(proposal: Pubkey)] +pub struct CastNftVote<'info> { + /// The NFT voting registrar + pub registrar: Account<'info, Registrar>, + + #[account( + mut, + constraint = voter_weight_record.realm == registrar.realm + @ NftVoterError::InvalidVoterWeightRecordRealm, + + constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ NftVoterError::InvalidVoterWeightRecordMint, + )] + pub voter_weight_record: Account<'info, VoterWeightRecord>, + + /// TokenOwnerRecord of the voter who casts the vote + #[account( + owner = registrar.governance_program_id + )] + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + voter_token_owner_record: UncheckedAccount<'info>, + + /// Authority of the voter who casts the vote + /// It can be either governing_token_owner or its delegate and must sign this instruction + pub voter_authority: Signer<'info>, + + /// The account which pays for the transaction + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +/// Casts vote with the NFT +pub fn cast_nft_vote<'a, 'b, 'c, 'info>( + ctx: Context<'a, 'b, 'c, 'info, CastNftVote<'info>>, + proposal: Pubkey, +) -> Result<()> { + let registrar = &ctx.accounts.registrar; + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + let governing_token_owner = resolve_governing_token_owner( + registrar, + &ctx.accounts.voter_token_owner_record, + &ctx.accounts.voter_authority, + voter_weight_record, + )?; + + let mut voter_weight = 0u64; + + // Ensure all voting nfts in the batch are unique + let mut unique_nft_mints = vec![]; + + let rent = Rent::get()?; + + for (nft_info, nft_metadata_info, nft_vote_record_info) in + ctx.remaining_accounts.iter().tuples() + { + let (nft_vote_weight, nft_mint) = resolve_nft_vote_weight_and_mint( + registrar, + &governing_token_owner, + nft_info, + nft_metadata_info, + &mut unique_nft_mints, + )?; + + voter_weight = voter_weight.checked_add(nft_vote_weight as u64).unwrap(); + + // Create NFT vote record to ensure the same NFT hasn't been already used for voting + // Note: The correct PDA of the NftVoteRecord is validated in create_and_serialize_account_signed + // It ensures the NftVoteRecord is for ('nft-vote-record',proposal,nft_mint) seeds + require!( + nft_vote_record_info.data_is_empty(), + NftVoterError::NftAlreadyVoted + ); + + // Note: proposal.governing_token_mint must match voter_weight_record.governing_token_mint + // We don't verify it here because spl-gov does the check in cast_vote + // and it would reject voter_weight_record if governing_token_mint doesn't match + + // Note: Once the NFT plugin is enabled the governing_token_mint is used only as identity + // for the voting population and the tokens of that mint are no longer used + let nft_vote_record = NftVoteRecord { + account_discriminator: NftVoteRecord::ACCOUNT_DISCRIMINATOR, + proposal, + nft_mint, + governing_token_owner, + reserved: [0; 8], + }; + + // Anchor doesn't natively support dynamic account creation using remaining_accounts + // and we have to take it on the manual drive + create_and_serialize_account_signed( + &ctx.accounts.payer.to_account_info(), + nft_vote_record_info, + &nft_vote_record, + &get_nft_vote_record_seeds(&proposal, &nft_mint), + &id(), + &ctx.accounts.system_program.to_account_info(), + &rent, + 0, + )?; + } + + if voter_weight_record.weight_action_target == Some(proposal) + && voter_weight_record.weight_action == Some(VoterWeightAction::CastVote) + { + // If cast_nft_vote is called for the same proposal then we keep accumulating the weight + // this way cast_nft_vote can be called multiple times in different transactions to allow voting with any number of NFTs + voter_weight_record.voter_weight = voter_weight_record + .voter_weight + .checked_add(voter_weight) + .unwrap(); + } else { + voter_weight_record.voter_weight = voter_weight; + } + + // The record is only valid as of the current slot + voter_weight_record.voter_weight_expiry = Some(Clock::get()?.slot); + + // The record is only valid for casting vote on the given Proposal + voter_weight_record.weight_action = Some(VoterWeightAction::CastVote); + voter_weight_record.weight_action_target = Some(proposal); + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/configure_collection.rs b/programs/core-voter/src/instructions/configure_collection.rs new file mode 100644 index 00000000..c217718f --- /dev/null +++ b/programs/core-voter/src/instructions/configure_collection.rs @@ -0,0 +1,114 @@ +use anchor_lang::{ + account, + prelude::{Context, Signer}, + Accounts, +}; + +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use spl_governance::state::realm; + +use crate::error::NftVoterError; +use crate::state::{max_voter_weight_record::MaxVoterWeightRecord, CollectionConfig, Registrar}; + +/// Configures NFT voting collection which defines what NFTs can be used for governances +/// and what weight they have +/// The instruction updates MaxVoterWeightRecord which is used by spl-gov to determine max voting power +/// used to calculate voting quorum +#[derive(Accounts)] +pub struct ConfigureCollection<'info> { + /// Registrar for which we configure this Collection + #[account(mut)] + pub registrar: Account<'info, Registrar>, + + #[account( + address = registrar.realm @ NftVoterError::InvalidRealmForRegistrar, + owner = registrar.governance_program_id + )] + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + pub realm: UncheckedAccount<'info>, + + /// Authority of the Realm must sign and match Realm.authority + pub realm_authority: Signer<'info>, + + // Collection which is going to be used for voting + pub collection: Account<'info, Mint>, + + #[account( + mut, + constraint = max_voter_weight_record.realm == registrar.realm + @ NftVoterError::InvalidMaxVoterWeightRecordRealm, + + constraint = max_voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ NftVoterError::InvalidMaxVoterWeightRecordMint, + )] + pub max_voter_weight_record: Account<'info, MaxVoterWeightRecord>, +} + +pub fn configure_collection( + ctx: Context, + weight: u64, + size: u32, +) -> Result<()> { + require!(size > 0, NftVoterError::InvalidCollectionSize); + + let registrar = &mut ctx.accounts.registrar; + + let realm = realm::get_realm_data_for_governing_token_mint( + ®istrar.governance_program_id, + &ctx.accounts.realm, + ®istrar.governing_token_mint, + )?; + + require!( + realm.authority.unwrap() == ctx.accounts.realm_authority.key(), + NftVoterError::InvalidRealmAuthority + ); + + // spl-gov doesn't track voting_proposal_count any longer and we can't enforce the check here + // It's not ideal but acceptable. The proper solution would require proposal queuing in spl-gov + // + // Changes to the collections config can accidentally tip the scales for outstanding proposals and hence we disallow it + // if realm.voting_proposal_count > 0 { + // return err!(NftVoterError::CannotConfigureCollectionWithVotingProposals); + // } + + let collection = &ctx.accounts.collection; + + let collection_config = CollectionConfig { + collection: collection.key(), + weight, + reserved: [0; 8], + size, + }; + + let collection_idx = registrar + .collection_configs + .iter() + .position(|cc| cc.collection == collection.key()); + + if let Some(collection_idx) = collection_idx { + registrar.collection_configs[collection_idx] = collection_config; + } else { + // Note: In the current runtime version push() would throw an error if we exceed + // max_collections specified when the Registrar was created + registrar.collection_configs.push(collection_config); + } + + // TODO: if weight == 0 then remove the collection from config + // Currently if weight is set to 0 then the collection won't be removed but it won't have any governance power + + // Update MaxVoterWeightRecord based on max voting power of the collections + let max_voter_weight_record = &mut ctx.accounts.max_voter_weight_record; + + max_voter_weight_record.max_voter_weight = registrar + .collection_configs + .iter() + .try_fold(0u64, |sum, cc| sum.checked_add(cc.get_max_weight())) + .unwrap(); + + // The weight never expires and only changes when collections are configured + max_voter_weight_record.max_voter_weight_expiry = None; + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/create_max_voter_weight_record.rs b/programs/core-voter/src/instructions/create_max_voter_weight_record.rs new file mode 100644 index 00000000..0749fd4e --- /dev/null +++ b/programs/core-voter/src/instructions/create_max_voter_weight_record.rs @@ -0,0 +1,57 @@ +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use spl_governance::state::realm; + +use crate::state::max_voter_weight_record::MaxVoterWeightRecord; + +/// Creates MaxVoterWeightRecord used by spl-gov +/// This instruction should only be executed once per realm/governing_token_mint to create the account +#[derive(Accounts)] +pub struct CreateMaxVoterWeightRecord<'info> { + #[account( + init, + seeds = [ b"max-voter-weight-record".as_ref(), + realm.key().as_ref(), + realm_governing_token_mint.key().as_ref()], + bump, + payer = payer, + space = MaxVoterWeightRecord::get_space() + )] + pub max_voter_weight_record: Account<'info, MaxVoterWeightRecord>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + #[account(owner = governance_program_id.key())] + /// CHECK: Owned by spl-governance instance specified in governance_program_id + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + pub realm_governing_token_mint: Account<'info, Mint>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +pub fn create_max_voter_weight_record(ctx: Context) -> Result<()> { + // Deserialize the Realm to validate it + let _realm = realm::get_realm_data_for_governing_token_mint( + &ctx.accounts.governance_program_id.key(), + &ctx.accounts.realm, + &ctx.accounts.realm_governing_token_mint.key(), + )?; + + let max_voter_weight_record = &mut ctx.accounts.max_voter_weight_record; + + max_voter_weight_record.realm = ctx.accounts.realm.key(); + max_voter_weight_record.governing_token_mint = ctx.accounts.realm_governing_token_mint.key(); + + // Set expiry to expired + max_voter_weight_record.max_voter_weight_expiry = Some(0); + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/create_registrar.rs b/programs/core-voter/src/instructions/create_registrar.rs new file mode 100644 index 00000000..efaa29f8 --- /dev/null +++ b/programs/core-voter/src/instructions/create_registrar.rs @@ -0,0 +1,81 @@ +use crate::error::NftVoterError; +use crate::state::*; +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use spl_governance::state::realm; + +/// Creates Registrar storing NFT governance configuration for spl-gov Realm +/// This instruction should only be executed once per realm/governing_token_mint to create the account +#[derive(Accounts)] +#[instruction(max_collections: u8)] +pub struct CreateRegistrar<'info> { + /// The NFT voting Registrar + /// There can only be a single registrar per governance Realm and governing mint of the Realm + #[account( + init, + seeds = [b"registrar".as_ref(),realm.key().as_ref(), governing_token_mint.key().as_ref()], + bump, + payer = payer, + space = Registrar::get_space(max_collections) + )] + pub registrar: Account<'info, Registrar>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + /// An spl-governance Realm + /// + /// Realm is validated in the instruction: + /// - Realm is owned by the governance_program_id + /// - governing_token_mint must be the community or council mint + /// - realm_authority is realm.authority + /// CHECK: Owned by spl-governance instance specified in governance_program_id + #[account(owner = governance_program_id.key())] + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + /// It must match Realm.community_mint or Realm.config.council_mint + /// + /// Note: Once the NFT plugin is enabled the governing_token_mint is used only as identity + /// for the voting population and the tokens of that are no longer used + pub governing_token_mint: Account<'info, Mint>, + + /// realm_authority must sign and match Realm.authority + pub realm_authority: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +/// Creates a new Registrar which stores NFT voting configuration for given Realm +/// +/// To use the registrar, call ConfigureCollection to register NFT collections that may be +/// used for governance +/// +/// max_collections is used allocate account size for the maximum number of governing NFT collections +/// Note: Once Solana runtime supports account resizing the max value won't be required +pub fn create_registrar(ctx: Context, _max_collections: u8) -> Result<()> { + let registrar = &mut ctx.accounts.registrar; + registrar.governance_program_id = ctx.accounts.governance_program_id.key(); + registrar.realm = ctx.accounts.realm.key(); + registrar.governing_token_mint = ctx.accounts.governing_token_mint.key(); + + // Verify that realm_authority is the expected authority of the Realm + // and that the mint matches one of the realm mints too + let realm = realm::get_realm_data_for_governing_token_mint( + ®istrar.governance_program_id, + &ctx.accounts.realm, + ®istrar.governing_token_mint, + )?; + + require!( + realm.authority.unwrap() == ctx.accounts.realm_authority.key(), + NftVoterError::InvalidRealmAuthority + ); + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/create_voter_weight_record.rs b/programs/core-voter/src/instructions/create_voter_weight_record.rs new file mode 100644 index 00000000..d1ef66db --- /dev/null +++ b/programs/core-voter/src/instructions/create_voter_weight_record.rs @@ -0,0 +1,63 @@ +use crate::state::*; +use anchor_lang::prelude::*; +use anchor_spl::token::Mint; +use spl_governance::state::realm; + +/// Creates VoterWeightRecord used by spl-gov +/// This instruction should only be executed once per realm/governing_token_mint/governing_token_owner +/// to create the account +#[derive(Accounts)] +#[instruction(governing_token_owner: Pubkey)] +pub struct CreateVoterWeightRecord<'info> { + #[account( + init, + seeds = [ b"voter-weight-record".as_ref(), + realm.key().as_ref(), + realm_governing_token_mint.key().as_ref(), + governing_token_owner.as_ref()], + bump, + payer = payer, + space = VoterWeightRecord::get_space() + )] + pub voter_weight_record: Account<'info, VoterWeightRecord>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + /// CHECK: Owned by spl-governance instance specified in governance_program_id + #[account(owner = governance_program_id.key())] + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + pub realm_governing_token_mint: Account<'info, Mint>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +pub fn create_voter_weight_record( + ctx: Context, + governing_token_owner: Pubkey, +) -> Result<()> { + // Deserialize the Realm to validate it + let _realm = realm::get_realm_data_for_governing_token_mint( + &ctx.accounts.governance_program_id.key(), + &ctx.accounts.realm, + &ctx.accounts.realm_governing_token_mint.key(), + )?; + + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + voter_weight_record.realm = ctx.accounts.realm.key(); + voter_weight_record.governing_token_mint = ctx.accounts.realm_governing_token_mint.key(); + voter_weight_record.governing_token_owner = governing_token_owner; + + // Set expiry to expired + voter_weight_record.voter_weight_expiry = Some(0); + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/mod.rs b/programs/core-voter/src/instructions/mod.rs new file mode 100644 index 00000000..518677c5 --- /dev/null +++ b/programs/core-voter/src/instructions/mod.rs @@ -0,0 +1,20 @@ +pub use configure_collection::*; +mod configure_collection; + +pub use create_registrar::*; +mod create_registrar; + +pub use create_voter_weight_record::*; +mod create_voter_weight_record; + +pub use create_max_voter_weight_record::*; +mod create_max_voter_weight_record; + +pub use update_voter_weight_record::*; +mod update_voter_weight_record; + +pub use relinquish_nft_vote::*; +mod relinquish_nft_vote; + +pub use cast_nft_vote::*; +mod cast_nft_vote; diff --git a/programs/core-voter/src/instructions/relinquish_nft_vote.rs b/programs/core-voter/src/instructions/relinquish_nft_vote.rs new file mode 100644 index 00000000..f395b45c --- /dev/null +++ b/programs/core-voter/src/instructions/relinquish_nft_vote.rs @@ -0,0 +1,149 @@ +use crate::error::NftVoterError; +use crate::state::*; +use crate::state::{get_nft_vote_record_data_for_proposal_and_token_owner, Registrar}; +use crate::tools::governance::get_vote_record_address; +use anchor_lang::prelude::*; +use spl_governance::state::{enums::ProposalState, governance, proposal}; +use spl_governance_tools::account::dispose_account; + +/// Disposes NftVoteRecord and recovers the rent from the accounts +/// It can only be executed when voting on the target Proposal ended or voter withdrew vote from the Proposal +/// +/// Note: If a voter votes with NFT and transfers the token then in the current version of the program the new owner can't withdraw the vote +/// In order to support that scenario a change in spl-governance is needed +/// It would have to support revoke_vote instruction which would take as input VoteWeightRecord with the following values: +/// weight_action: RevokeVote, weight_action_target: VoteRecord, voter_weight: sum(previous owner NFT weight) +/// The instruction would decrease the previous voter total VoteRecord.voter_weight by the provided VoteWeightRecord.voter_weight +/// Once the spl-governance instruction is supported then nft-voter plugin should implement revoke_nft_vote instruction +/// to supply the required VoteWeightRecord and delete relevant NftVoteRecords +#[derive(Accounts)] +pub struct RelinquishNftVote<'info> { + /// The NFT voting Registrar + pub registrar: Account<'info, Registrar>, + + #[account( + mut, + constraint = voter_weight_record.realm == registrar.realm + @ NftVoterError::InvalidVoterWeightRecordRealm, + + constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ NftVoterError::InvalidVoterWeightRecordMint, + )] + pub voter_weight_record: Account<'info, VoterWeightRecord>, + + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + /// Governance account the Proposal is for + #[account(owner = registrar.governance_program_id)] + pub governance: UncheckedAccount<'info>, + + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + #[account(owner = registrar.governance_program_id)] + pub proposal: UncheckedAccount<'info>, + + /// TokenOwnerRecord of the voter who cast the original vote + #[account( + owner = registrar.governance_program_id + )] + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + voter_token_owner_record: UncheckedAccount<'info>, + + /// Authority of the voter who cast the original vote + /// It can be either governing_token_owner or its delegate and must sign this instruction + pub voter_authority: Signer<'info>, + + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + /// The account is used to validate that it doesn't exist and if it doesn't then Anchor owner check throws error + /// The check is disabled here and performed inside the instruction + /// #[account(owner = registrar.governance_program_id)] + pub vote_record: UncheckedAccount<'info>, + + /// CHECK: The beneficiary who receives lamports from the disposed NftVoterRecord accounts can be any account + #[account(mut)] + pub beneficiary: UncheckedAccount<'info>, +} + +pub fn relinquish_nft_vote(ctx: Context) -> Result<()> { + let registrar = &ctx.accounts.registrar; + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + let governing_token_owner = resolve_governing_token_owner( + registrar, + &ctx.accounts.voter_token_owner_record, + &ctx.accounts.voter_authority, + voter_weight_record, + )?; + + // Ensure the Governance belongs to Registrar.realm and is owned by Registrar.governance_program_id + let _governance = governance::get_governance_data_for_realm( + ®istrar.governance_program_id, + &ctx.accounts.governance, + ®istrar.realm, + )?; + + // Ensure the Proposal belongs to Governance from Registrar.realm and Registrar.governing_token_mint and is owned by Registrar.governance_program_id + let proposal = proposal::get_proposal_data_for_governance_and_governing_mint( + ®istrar.governance_program_id, + &ctx.accounts.proposal, + &ctx.accounts.governance.key(), + ®istrar.governing_token_mint, + )?; + + // If the Proposal is still in Voting state then we can only Relinquish the NFT votes if the Vote was withdrawn in spl-gov first + // When vote is withdrawn in spl-gov then VoteRecord is disposed and we have to assert it doesn't exist + // + // If the Proposal is in any other state then we can dispose NftVoteRecords without any additional Proposal checks + if proposal.state == ProposalState::Voting { + let vote_record_info = &ctx.accounts.vote_record.to_account_info(); + + // Ensure the given VoteRecord address matches the expected PDA + let vote_record_key = get_vote_record_address( + ®istrar.governance_program_id, + ®istrar.realm, + ®istrar.governing_token_mint, + &governing_token_owner, + &ctx.accounts.proposal.key(), + ); + + require!( + vote_record_key == vote_record_info.key(), + NftVoterError::InvalidVoteRecordForNftVoteRecord + ); + + require!( + // VoteRecord doesn't exist if data is empty or account_type is 0 when the account was disposed in the same Tx + vote_record_info.data_is_empty() || vote_record_info.try_borrow_data().unwrap()[0] == 0, + NftVoterError::VoteRecordMustBeWithdrawn + ); + } + + // Prevent relinquishing NftVoteRecords within the VoterWeightRecord expiration period + // It's needed when multiple stacked voter-weight plugins are used + // Without the assertion the following vector of attack exists + // 1) nft-voter.cast_nft_vote() + // 2) voter-weight-plugin.cast_vote() + // 3) nft-voter.relinquish_nft_vote() + // 4) spl-gov.cast_vote() -> spl-gov uses VoterWeightRecord provided by voter-weight-plugin in step 2) while the nft vote is withdrawn and could be used to vote again + if voter_weight_record.voter_weight_expiry >= Some(Clock::get()?.slot) { + return err!(NftVoterError::VoterWeightRecordMustBeExpired); + } + + // Dispose all NftVoteRecords + for nft_vote_record_info in ctx.remaining_accounts.iter() { + // Ensure NftVoteRecord is for the given Proposal and TokenOwner + let _nft_vote_record = get_nft_vote_record_data_for_proposal_and_token_owner( + nft_vote_record_info, + &ctx.accounts.proposal.key(), + &governing_token_owner, + )?; + + dispose_account(nft_vote_record_info, &ctx.accounts.beneficiary)?; + } + + // Reset VoterWeightRecord and set expiry to expired to prevent it from being used + voter_weight_record.voter_weight = 0; + voter_weight_record.voter_weight_expiry = Some(0); + + voter_weight_record.weight_action_target = None; + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/update_voter_weight_record.rs b/programs/core-voter/src/instructions/update_voter_weight_record.rs new file mode 100644 index 00000000..43145e2a --- /dev/null +++ b/programs/core-voter/src/instructions/update_voter_weight_record.rs @@ -0,0 +1,76 @@ +use crate::error::NftVoterError; +use crate::state::*; +use anchor_lang::prelude::*; +use itertools::Itertools; + +/// Updates VoterWeightRecord to evaluate governance power for non voting use cases: CreateProposal, CreateGovernance etc... +/// This instruction updates VoterWeightRecord which is valid for the current Slot and the given target action only +/// and hance the instruction has to be executed inside the same transaction as the corresponding spl-gov instruction +/// +/// Note: UpdateVoterWeight is not cumulative the same way as CastNftVote and hence voter_weight for non voting scenarios +/// can only be used with max 5 NFTs due to Solana transaction size limit +/// It could be supported in future version by introducing bookkeeping accounts to track the NFTs +/// which were already used to calculate the total weight +#[derive(Accounts)] +#[instruction(voter_weight_action:VoterWeightAction)] +pub struct UpdateVoterWeightRecord<'info> { + /// The NFT voting Registrar + pub registrar: Account<'info, Registrar>, + + #[account( + mut, + constraint = voter_weight_record.realm == registrar.realm + @ NftVoterError::InvalidVoterWeightRecordRealm, + + constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ NftVoterError::InvalidVoterWeightRecordMint, + )] + pub voter_weight_record: Account<'info, VoterWeightRecord>, +} + +pub fn update_voter_weight_record( + ctx: Context, + voter_weight_action: VoterWeightAction, +) -> Result<()> { + let registrar = &ctx.accounts.registrar; + let governing_token_owner = &ctx.accounts.voter_weight_record.governing_token_owner; + + match voter_weight_action { + // voter_weight for CastVote action can't be evaluated using this instruction + VoterWeightAction::CastVote => return err!(NftVoterError::CastVoteIsNotAllowed), + VoterWeightAction::CommentProposal + | VoterWeightAction::CreateGovernance + | VoterWeightAction::CreateProposal + | VoterWeightAction::SignOffProposal => {} + } + + let mut voter_weight = 0u64; + + // Ensure all nfts are unique + let mut unique_nft_mints = vec![]; + + for (nft_info, nft_metadata_info) in ctx.remaining_accounts.iter().tuples() { + let (nft_vote_weight, _) = resolve_nft_vote_weight_and_mint( + registrar, + governing_token_owner, + nft_info, + nft_metadata_info, + &mut unique_nft_mints, + )?; + + voter_weight = voter_weight.checked_add(nft_vote_weight as u64).unwrap(); + } + + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + voter_weight_record.voter_weight = voter_weight; + + // Record is only valid as of the current slot + voter_weight_record.voter_weight_expiry = Some(Clock::get()?.slot); + + // Set the action to make it specific and prevent being used for voting + voter_weight_record.weight_action = Some(voter_weight_action); + voter_weight_record.weight_action_target = None; + + Ok(()) +} diff --git a/programs/core-voter/src/lib.rs b/programs/core-voter/src/lib.rs new file mode 100644 index 00000000..fcd118fe --- /dev/null +++ b/programs/core-voter/src/lib.rs @@ -0,0 +1,69 @@ +use anchor_lang::prelude::*; + +pub mod error; + +mod instructions; +use instructions::*; + +pub mod state; + +pub mod tools; + +use crate::state::*; + +declare_id!("GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw"); + +#[program] +pub mod nft_voter { + + use crate::state::VoterWeightAction; + + use super::*; + pub fn create_registrar(ctx: Context, max_collections: u8) -> Result<()> { + log_version(); + instructions::create_registrar(ctx, max_collections) + } + pub fn create_voter_weight_record( + ctx: Context, + governing_token_owner: Pubkey, + ) -> Result<()> { + log_version(); + instructions::create_voter_weight_record(ctx, governing_token_owner) + } + pub fn create_max_voter_weight_record(ctx: Context) -> Result<()> { + log_version(); + instructions::create_max_voter_weight_record(ctx) + } + pub fn update_voter_weight_record( + ctx: Context, + voter_weight_action: VoterWeightAction, + ) -> Result<()> { + log_version(); + instructions::update_voter_weight_record(ctx, voter_weight_action) + } + pub fn relinquish_nft_vote(ctx: Context) -> Result<()> { + log_version(); + instructions::relinquish_nft_vote(ctx) + } + pub fn configure_collection( + ctx: Context, + weight: u64, + size: u32, + ) -> Result<()> { + log_version(); + instructions::configure_collection(ctx, weight, size) + } + + pub fn cast_nft_vote<'a, 'b, 'c, 'info>( + ctx: Context<'a, 'b, 'c, 'info, CastNftVote<'info>>, + proposal: Pubkey, + ) -> Result<()> { + log_version(); + instructions::cast_nft_vote(ctx, proposal) + } +} + +fn log_version() { + // TODO: Check if Anchor allows to log it before instruction is deserialized + msg!("VERSION:{:?}", env!("CARGO_PKG_VERSION")); +} diff --git a/programs/core-voter/src/state/collection_config.rs b/programs/core-voter/src/state/collection_config.rs new file mode 100644 index 00000000..56cd7e4e --- /dev/null +++ b/programs/core-voter/src/state/collection_config.rs @@ -0,0 +1,28 @@ +use anchor_lang::prelude::*; + +/// Configuration of an NFT collection used for governance power +#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq, Default)] +pub struct CollectionConfig { + /// The NFT collection used for governance + pub collection: Pubkey, + + /// The size of the NFT collection used to calculate max voter weight + /// Note: At the moment the size is not captured on Metaplex accounts + /// and it has to be manually updated on the Registrar + pub size: u32, + + /// Governance power weight of the collection + /// Each NFT in the collection has governance power = 1 * weight + /// Note: The weight is scaled accordingly to the governing_token_mint decimals + /// Ex: if the the mint has 2 decimal places then weight of 1 should be stored as 100 + pub weight: u64, + + /// Reserved for future upgrades + pub reserved: [u8; 8], +} + +impl CollectionConfig { + pub fn get_max_weight(&self) -> u64 { + (self.size as u64).checked_mul(self.weight).unwrap() + } +} diff --git a/programs/core-voter/src/state/idl_types.rs b/programs/core-voter/src/state/idl_types.rs new file mode 100644 index 00000000..06a57aa7 --- /dev/null +++ b/programs/core-voter/src/state/idl_types.rs @@ -0,0 +1,17 @@ +//! IDL only types which are required in IDL but not exported automatically by Anchor +use anchor_lang::prelude::*; + +/// NftVoteRecord exported to IDL without account_discriminator +/// TODO: Once we can support these accounts in Anchor via remaining_accounts then it should be possible to remove it +#[account] +pub struct NftVoteRecord { + /// Proposal which was voted on + pub proposal: Pubkey, + + /// The mint of the NFT which was used for the vote + pub nft_mint: Pubkey, + + /// The voter who casted this vote + /// It's a Realm member pubkey corresponding to TokenOwnerRecord.governing_token_owner + pub governing_token_owner: Pubkey, +} diff --git a/programs/core-voter/src/state/max_voter_weight_record.rs b/programs/core-voter/src/state/max_voter_weight_record.rs new file mode 100644 index 00000000..66ac8da7 --- /dev/null +++ b/programs/core-voter/src/state/max_voter_weight_record.rs @@ -0,0 +1,96 @@ +use crate::id; +use crate::tools::anchor::DISCRIMINATOR_SIZE; +use anchor_lang::prelude::Pubkey; +use anchor_lang::prelude::*; +use solana_program::pubkey::PUBKEY_BYTES; + +/// MaxVoterWeightRecord account as defined in spl-governance-addin-api +/// It's redefined here without account_discriminator for Anchor to treat it as native account +/// +/// The account is used as an api interface to provide max voting power to the governance program from external addin contracts +#[account] +#[derive(Debug, PartialEq)] +pub struct MaxVoterWeightRecord { + /// The Realm the MaxVoterWeightRecord belongs to + pub realm: Pubkey, + + /// Governing Token Mint the MaxVoterWeightRecord is associated with + /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + // The mint here is to link the record to either community or council mint of the realm + pub governing_token_mint: Pubkey, + + /// Max voter weight + /// The max voter weight provided by the addin for the given realm and governing_token_mint + pub max_voter_weight: u64, + + /// The slot when the max voting weight expires + /// It should be set to None if the weight never expires + /// If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set + /// As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction + /// and the expiry set to the current slot to provide up to date weight + pub max_voter_weight_expiry: Option, + + /// Reserved space for future versions + pub reserved: [u8; 8], +} + +impl Default for MaxVoterWeightRecord { + fn default() -> Self { + Self { + realm: Default::default(), + governing_token_mint: Default::default(), + max_voter_weight: Default::default(), + max_voter_weight_expiry: Some(0), + reserved: Default::default(), + } + } +} + +impl MaxVoterWeightRecord { + pub fn get_space() -> usize { + DISCRIMINATOR_SIZE + PUBKEY_BYTES * 2 + 8 + 1 + 8 + 8 + } +} + +/// Returns MaxVoterWeightRecord PDA seeds +pub fn get_max_voter_weight_record_seeds<'a>( + realm: &'a Pubkey, + governing_token_mint: &'a Pubkey, +) -> [&'a [u8]; 3] { + [ + b"max-voter-weight-record", + realm.as_ref(), + governing_token_mint.as_ref(), + ] +} + +/// Returns MaxVoterWeightRecord PDA address +pub fn get_max_voter_weight_record_address( + realm: &Pubkey, + governing_token_mint: &Pubkey, +) -> Pubkey { + Pubkey::find_program_address( + &get_max_voter_weight_record_seeds(realm, governing_token_mint), + &id(), + ) + .0 +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_get_space() { + // Arrange + let expected_space = MaxVoterWeightRecord::get_space(); + + // Act + let actual_space = + DISCRIMINATOR_SIZE + MaxVoterWeightRecord::default().try_to_vec().unwrap().len(); + + // Assert + assert_eq!(expected_space, actual_space); + } +} diff --git a/programs/core-voter/src/state/mod.rs b/programs/core-voter/src/state/mod.rs new file mode 100644 index 00000000..4084a580 --- /dev/null +++ b/programs/core-voter/src/state/mod.rs @@ -0,0 +1,15 @@ +pub use registrar::*; +pub mod registrar; + +pub use collection_config::*; +pub mod collection_config; + +pub use nft_vote_record::*; +pub mod nft_vote_record; + +pub mod max_voter_weight_record; + +pub use voter_weight_record::*; +pub mod voter_weight_record; + +pub mod idl_types; diff --git a/programs/core-voter/src/state/nft_vote_record.rs b/programs/core-voter/src/state/nft_vote_record.rs new file mode 100644 index 00000000..25fcf101 --- /dev/null +++ b/programs/core-voter/src/state/nft_vote_record.rs @@ -0,0 +1,84 @@ +use anchor_lang::prelude::*; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use solana_program::program_pack::IsInitialized; + +use spl_governance_tools::account::{get_account_data, AccountMaxSize}; + +use crate::{error::NftVoterError, id}; + +/// Vote record indicating the given NFT voted on the Proposal +/// The PDA of the record is ["nft-vote-record",proposal,nft_mint] +/// It guarantees uniques and ensures the same NFT can't vote twice +#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +pub struct NftVoteRecord { + /// NftVoteRecord discriminator sha256("account:NftVoteRecord")[..8] + /// Note: The discriminator is used explicitly because NftVoteRecords + /// are created and consumed dynamically using remaining_accounts + /// and Anchor doesn't really support this scenario without going through lots of hoops + /// Once Anchor has better support for the scenario it shouldn't be necessary + pub account_discriminator: [u8; 8], + + /// Proposal which was voted on + pub proposal: Pubkey, + + /// The mint of the NFT which was used for the vote + pub nft_mint: Pubkey, + + /// The voter who casted this vote + /// It's a Realm member pubkey corresponding to TokenOwnerRecord.governing_token_owner + pub governing_token_owner: Pubkey, + + /// Reserved for future upgrades + pub reserved: [u8; 8], +} + +impl NftVoteRecord { + /// sha256("account:NftVoteRecord")[..8] + pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [137, 6, 55, 139, 251, 126, 254, 99]; +} + +impl AccountMaxSize for NftVoteRecord {} + +impl IsInitialized for NftVoteRecord { + fn is_initialized(&self) -> bool { + self.account_discriminator == NftVoteRecord::ACCOUNT_DISCRIMINATOR + } +} + +/// Returns NftVoteRecord PDA seeds +pub fn get_nft_vote_record_seeds<'a>(proposal: &'a Pubkey, nft_mint: &'a Pubkey) -> [&'a [u8]; 3] { + [b"nft-vote-record", proposal.as_ref(), nft_mint.as_ref()] +} + +/// Returns NftVoteRecord PDA address +pub fn get_nft_vote_record_address(proposal: &Pubkey, nft_mint: &Pubkey) -> Pubkey { + Pubkey::find_program_address(&get_nft_vote_record_seeds(proposal, nft_mint), &id()).0 +} + +/// Deserializes account and checks owner program +pub fn get_nft_vote_record_data(nft_vote_record_info: &AccountInfo) -> Result { + Ok(get_account_data::( + &id(), + nft_vote_record_info, + )?) +} + +pub fn get_nft_vote_record_data_for_proposal_and_token_owner( + nft_vote_record_info: &AccountInfo, + proposal: &Pubkey, + governing_token_owner: &Pubkey, +) -> Result { + let nft_vote_record = get_nft_vote_record_data(nft_vote_record_info)?; + + require!( + nft_vote_record.proposal == *proposal, + NftVoterError::InvalidProposalForNftVoteRecord + ); + + require!( + nft_vote_record.governing_token_owner == *governing_token_owner, + NftVoterError::InvalidTokenOwnerForNftVoteRecord + ); + + Ok(nft_vote_record) +} diff --git a/programs/core-voter/src/state/registrar.rs b/programs/core-voter/src/state/registrar.rs new file mode 100644 index 00000000..a6479c57 --- /dev/null +++ b/programs/core-voter/src/state/registrar.rs @@ -0,0 +1,171 @@ +use crate::{ + error::NftVoterError, + id, + state::{CollectionConfig, VoterWeightRecord}, + tools::{ + anchor::DISCRIMINATOR_SIZE, spl_token::get_spl_token_amount, + token_metadata::get_token_metadata_for_mint, + }, +}; +use anchor_lang::prelude::*; +use solana_program::pubkey::PUBKEY_BYTES; +use spl_governance::state::token_owner_record; +use spl_governance::tools::spl_token::{get_spl_token_mint, get_spl_token_owner}; + +/// Registrar which stores NFT voting configuration for the given Realm +#[account] +#[derive(Debug, PartialEq)] +pub struct Registrar { + /// spl-governance program the Realm belongs to + pub governance_program_id: Pubkey, + + /// Realm of the Registrar + pub realm: Pubkey, + + /// Governing token mint the Registrar is for + /// It can either be the Community or the Council mint of the Realm + /// When the plugin is used the mint is only used as identity of the governing power (voting population) + /// and the actual token of the mint is not used + pub governing_token_mint: Pubkey, + + /// MPL Collection used for voting + pub collection_configs: Vec, + + /// Reserved for future upgrades + pub reserved: [u8; 128], +} + +impl Registrar { + pub fn get_space(max_collections: u8) -> usize { + DISCRIMINATOR_SIZE + + PUBKEY_BYTES * 3 + + 4 + + max_collections as usize * (PUBKEY_BYTES + 4 + 8 + 8) + + 128 + } +} + +/// Returns Registrar PDA seeds +pub fn get_registrar_seeds<'a>( + realm: &'a Pubkey, + governing_token_mint: &'a Pubkey, +) -> [&'a [u8]; 3] { + [b"registrar", realm.as_ref(), governing_token_mint.as_ref()] +} + +/// Returns Registrar PDA address +pub fn get_registrar_address(realm: &Pubkey, governing_token_mint: &Pubkey) -> Pubkey { + Pubkey::find_program_address(&get_registrar_seeds(realm, governing_token_mint), &id()).0 +} + +impl Registrar { + pub fn get_collection_config(&self, collection: Pubkey) -> Result<&CollectionConfig> { + return self + .collection_configs + .iter() + .find(|cc| cc.collection == collection) + .ok_or_else(|| NftVoterError::CollectionNotFound.into()); + } +} + +// Resolves governing_token_owner from voter TokenOwnerRecord and +// 1) asserts it matches the given Registrar and VoterWeightRecord +// 2) asserts governing_token_owner or its delegate is a signer +pub fn resolve_governing_token_owner( + registrar: &Registrar, + voter_token_owner_record_info: &AccountInfo, + voter_authority_info: &AccountInfo, + voter_weight_record: &VoterWeightRecord, +) -> Result { + let voter_token_owner_record = + token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint( + ®istrar.governance_program_id, + voter_token_owner_record_info, + ®istrar.realm, + ®istrar.governing_token_mint, + )?; + + voter_token_owner_record.assert_token_owner_or_delegate_is_signer(voter_authority_info)?; + + // Assert voter TokenOwnerRecord and VoterWeightRecord are for the same governing_token_owner + require_eq!( + voter_token_owner_record.governing_token_owner, + voter_weight_record.governing_token_owner, + NftVoterError::InvalidTokenOwnerForVoterWeightRecord + ); + + Ok(voter_token_owner_record.governing_token_owner) +} + +/// Resolves vote weight and voting mint for the given NFT +pub fn resolve_nft_vote_weight_and_mint( + registrar: &Registrar, + governing_token_owner: &Pubkey, + nft_info: &AccountInfo, + nft_metadata_info: &AccountInfo, + unique_nft_mints: &mut Vec, +) -> Result<(u64, Pubkey)> { + let nft_owner = get_spl_token_owner(nft_info)?; + + // voter_weight_record.governing_token_owner must be the owner of the NFT + require!( + nft_owner == *governing_token_owner, + NftVoterError::VoterDoesNotOwnNft + ); + + let nft_mint = get_spl_token_mint(nft_info)?; + + // Ensure the same NFT was not provided more than once + if unique_nft_mints.contains(&nft_mint) { + return Err(NftVoterError::DuplicatedNftDetected.into()); + } + unique_nft_mints.push(nft_mint); + + // Ensure the token amount is exactly 1 + let nft_amount = get_spl_token_amount(nft_info)?; + + require!(nft_amount == 1, NftVoterError::InvalidNftAmount); + + let nft_metadata = get_token_metadata_for_mint(nft_metadata_info, &nft_mint)?; + + // The NFT must have a collection and the collection must be verified + let collection = nft_metadata + .collection + .ok_or(NftVoterError::MissingMetadataCollection)?; + + require!(collection.verified, NftVoterError::CollectionMustBeVerified); + + let collection_config = registrar.get_collection_config(collection.key)?; + + Ok((collection_config.weight, nft_mint)) +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_get_space() { + // Arrange + let expected_space = Registrar::get_space(3); + + let registrar = Registrar { + governance_program_id: Pubkey::default(), + realm: Pubkey::default(), + governing_token_mint: Pubkey::default(), + collection_configs: vec![ + CollectionConfig::default(), + CollectionConfig::default(), + CollectionConfig::default(), + ], + reserved: [0; 128], + }; + + // Act + let actual_space = DISCRIMINATOR_SIZE + registrar.try_to_vec().unwrap().len(); + + // Assert + assert_eq!(expected_space, actual_space); + } +} diff --git a/programs/core-voter/src/state/voter_weight_record.rs b/programs/core-voter/src/state/voter_weight_record.rs new file mode 100644 index 00000000..0d0e24c7 --- /dev/null +++ b/programs/core-voter/src/state/voter_weight_record.rs @@ -0,0 +1,110 @@ +use anchor_lang::prelude::*; +use solana_program::pubkey::PUBKEY_BYTES; + +use crate::tools::anchor::DISCRIMINATOR_SIZE; + +/// VoterWeightAction enum as defined in spl-governance-addin-api +/// It's redefined here for Anchor to export it to IDL +#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq)] +pub enum VoterWeightAction { + /// Cast vote for a proposal. Target: Proposal + CastVote, + + /// Comment a proposal. Target: Proposal + CommentProposal, + + /// Create Governance within a realm. Target: Realm + CreateGovernance, + + /// Create a proposal for a governance. Target: Governance + CreateProposal, + + /// Signs off a proposal for a governance. Target: Proposal + /// Note: SignOffProposal is not supported in the current version + SignOffProposal, +} + +/// VoterWeightRecord account as defined in spl-governance-addin-api +/// It's redefined here without account_discriminator for Anchor to treat it as native account +/// +/// The account is used as an api interface to provide voting power to the governance program from external addin contracts +#[account] +#[derive(Debug, PartialEq)] +pub struct VoterWeightRecord { + /// The Realm the VoterWeightRecord belongs to + pub realm: Pubkey, + + /// Governing Token Mint the VoterWeightRecord is associated with + /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only + // The mint here is to link the record to either community or council mint of the realm + pub governing_token_mint: Pubkey, + + /// The owner of the governing token and voter + /// This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner + pub governing_token_owner: Pubkey, + + /// Voter's weight + /// The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter) + pub voter_weight: u64, + + /// The slot when the voting weight expires + /// It should be set to None if the weight never expires + /// If the voter weight decays with time, for example for time locked based weights, then the expiry must be set + /// As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction + /// and the expiry set to the current slot to provide up to date weight + pub voter_weight_expiry: Option, + + /// The governance action the voter's weight pertains to + /// It allows to provided voter's weight specific to the particular action the weight is evaluated for + /// When the action is provided then the governance program asserts the executing action is the same as specified by the addin + pub weight_action: Option, + + /// The target the voter's weight action pertains to + /// It allows to provided voter's weight specific to the target the weight is evaluated for + /// For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target + /// When the target is provided then the governance program asserts the target is the same as specified by the addin + pub weight_action_target: Option, + + /// Reserved space for future versions + pub reserved: [u8; 8], +} + +impl VoterWeightRecord { + pub fn get_space() -> usize { + DISCRIMINATOR_SIZE + PUBKEY_BYTES * 4 + 8 + 1 + 8 + 1 + 1 + 1 + 8 + } +} + +impl Default for VoterWeightRecord { + fn default() -> Self { + Self { + realm: Default::default(), + governing_token_mint: Default::default(), + governing_token_owner: Default::default(), + voter_weight: Default::default(), + voter_weight_expiry: Some(0), + weight_action: Some(VoterWeightAction::CastVote), + weight_action_target: Some(Default::default()), + reserved: Default::default(), + } + } +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_get_space() { + // Arrange + let expected_space = VoterWeightRecord::get_space(); + + // Act + let actual_space = + DISCRIMINATOR_SIZE + VoterWeightRecord::default().try_to_vec().unwrap().len(); + + // Assert + assert_eq!(expected_space, actual_space); + } +} diff --git a/programs/core-voter/src/tools/anchor.rs b/programs/core-voter/src/tools/anchor.rs new file mode 100644 index 00000000..abc1dd52 --- /dev/null +++ b/programs/core-voter/src/tools/anchor.rs @@ -0,0 +1 @@ +pub const DISCRIMINATOR_SIZE: usize = 8; diff --git a/programs/core-voter/src/tools/governance.rs b/programs/core-voter/src/tools/governance.rs new file mode 100644 index 00000000..ccb25732 --- /dev/null +++ b/programs/core-voter/src/tools/governance.rs @@ -0,0 +1,19 @@ +use anchor_lang::prelude::Pubkey; +use spl_governance::state::{token_owner_record, vote_record}; + +pub fn get_vote_record_address( + program_id: &Pubkey, + realm: &Pubkey, + governing_token_mint: &Pubkey, + governing_token_owner: &Pubkey, + proposal: &Pubkey, +) -> Pubkey { + let token_owner_record_key = token_owner_record::get_token_owner_record_address( + program_id, + realm, + governing_token_mint, + governing_token_owner, + ); + + vote_record::get_vote_record_address(program_id, proposal, &token_owner_record_key) +} diff --git a/programs/core-voter/src/tools/mod.rs b/programs/core-voter/src/tools/mod.rs new file mode 100644 index 00000000..13516dbb --- /dev/null +++ b/programs/core-voter/src/tools/mod.rs @@ -0,0 +1,4 @@ +pub mod anchor; +pub mod governance; +pub mod spl_token; +pub mod token_metadata; diff --git a/programs/core-voter/src/tools/spl_token.rs b/programs/core-voter/src/tools/spl_token.rs new file mode 100644 index 00000000..49a97d5b --- /dev/null +++ b/programs/core-voter/src/tools/spl_token.rs @@ -0,0 +1,15 @@ +use anchor_lang::prelude::*; +use arrayref::array_ref; +use spl_governance::tools::spl_token::assert_is_valid_spl_token_account; + +/// Computationally cheap method to get amount from a token account +/// It reads amount without deserializing full account data +pub fn get_spl_token_amount(token_account_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_account(token_account_info)?; + + // TokeAccount layout: mint(32), owner(32), amount(8), ... + let data = token_account_info.try_borrow_data()?; + let amount_bytes = array_ref![data, 64, 8]; + + Ok(u64::from_le_bytes(*amount_bytes)) +} diff --git a/programs/core-voter/src/tools/token_metadata.rs b/programs/core-voter/src/tools/token_metadata.rs new file mode 100644 index 00000000..8ac1007b --- /dev/null +++ b/programs/core-voter/src/tools/token_metadata.rs @@ -0,0 +1,32 @@ +use std::convert::TryFrom; + +use anchor_lang::prelude::*; +use mpl_token_metadata::accounts::Metadata; + +use crate::error::NftVoterError; + +pub fn get_token_metadata(account_info: &AccountInfo) -> Result { + if *account_info.owner != mpl_token_metadata::ID { + return Err(NftVoterError::InvalidAccountOwner.into()); + } + + let metadata = Metadata::try_from(account_info)?; + + // I'm not sure if this is needed but try_from_slice_checked in from_account_info + // ignores Key::Uninitialized and hence checking for the exact Key match here + if metadata.key != mpl_token_metadata::types::Key::MetadataV1 { + return Err(NftVoterError::InvalidTokenMetadataAccount.into()); + } + + Ok(metadata) +} + +pub fn get_token_metadata_for_mint(account_info: &AccountInfo, mint: &Pubkey) -> Result { + let token_metadata = get_token_metadata(account_info)?; + + if token_metadata.mint != *mint { + return Err(NftVoterError::TokenMetadataDoesNotMatch.into()); + } + + Ok(token_metadata) +} diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs new file mode 100644 index 00000000..97e3934e --- /dev/null +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -0,0 +1,1370 @@ +use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use gpl_nft_voter::error::NftVoterError; +use gpl_nft_voter::state::*; +use program_test::token_metadata_test::CreateNftArgs; +use program_test::{ + nft_voter_test::*, + tools::{assert_gov_err, assert_nft_voter_err}, +}; + +use solana_program_test::*; +use solana_sdk::transport::TransportError; +use spl_governance::error::GovernanceError; + +mod program_test; + +#[tokio::test] +async fn test_cast_nft_vote() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + // Act + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Assert + let nft_vote_record = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record); + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 10); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_cookie2 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + // Act + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1, &nft_cookie2], + None, + ) + .await?; + + // Assert + let nft_vote_record1 = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); + + let nft_vote_record2 = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) + .await; + + assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Act + + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + + // Act + + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie2, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + // Create NFT without verified collection + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + verify_collection: false, + ..Default::default() + }), + ) + .await?; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie2, None) + .await?; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + + let nft_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie2, &voter_cookie, None) + .await?; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionNotFound); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_invalid_metadata_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let mut nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + verify_collection: false, + ..Default::default() + }), + ) + .await?; + + let nft2_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Try to use verified NFT Metadata + nft1_cookie.metadata = nft2_cookie.metadata; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft1_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::TokenMetadataDoesNotMatch); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie, &nft_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + amount: 0, + ..Default::default() + }), + ) + .await?; + + // Act + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let mut nft_cookies = vec![]; + + for _ in 0..5 { + nft_voter_test.bench.advance_clock().await; + let nft_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_cookies.push(nft_cookie) + } + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + // Act + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_cookies.iter().collect::>(), + None, + ) + .await?; + + // Assert + let nft_vote_record1 = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); + + let nft_vote_record2 = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) + .await; + + assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 50); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + let args = CastNftVoteArgs { + cast_spl_gov_vote: false, + }; + + nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + Some(args), + ) + .await?; + + let nft_cookie2 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Act + + nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie2], + None, + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let args = CastNftVoteArgs { + cast_spl_gov_vote: false, + }; + + nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + Some(args), + ) + .await?; + + // Act + + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let args = CastNftVoteArgs { + cast_spl_gov_vote: false, + }; + + // Cast vote with NFT + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + Some(args), + ) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Try relinquish NftVoteRecords to accumulate vote + nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await?; + + // Act + + nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 10); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + + let delegate_cookie = nft_voter_test.bench.with_wallet().await; + nft_voter_test + .governance + .set_governance_delegate( + &realm_cookie, + &voter_token_owner_record_cookie, + &voter_cookie, + &Some(delegate_cookie.address), + ) + .await; + + // Act + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &delegate_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Assert + let nft_vote_record = nft_voter_test + .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_nft_vote_with_invalid_voter_weight_token_owner_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + // Try to update VoterWeightRecord for different governing_token_owner + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_weight_record_cookie2 = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie2) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Act + + let err = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie2, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); + + Ok(()) +} diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs new file mode 100644 index 00000000..4d83f5e3 --- /dev/null +++ b/programs/core-voter/tests/configure_collection.rs @@ -0,0 +1,413 @@ +use gpl_nft_voter::error::NftVoterError; +use program_test::{ + nft_voter_test::NftVoterTest, + tools::{assert_anchor_err, assert_nft_voter_err}, +}; + +use solana_program_test::*; +use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; + +use crate::program_test::nft_voter_test::ConfigureCollectionArgs; + +mod program_test; + +#[tokio::test] +async fn test_configure_collection() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Act + let collection_config_cookie = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + // Assert + let registrar = nft_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.collection_configs.len(), 1); + + assert_eq!( + registrar.collection_configs[0], + collection_config_cookie.collection_config + ); + + let max_voter_weight_record = nft_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!( + max_voter_weight_record.max_voter_weight, + (registrar.collection_configs[0].weight as u32 * registrar.collection_configs[0].size) + as u64 + ); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_multiple_collections() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie1 = nft_voter_test.token_metadata.with_nft_collection().await?; + let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Act + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie1, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { weight: 1, size: 5 }), + ) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie2, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 2, + size: 10, + }), + ) + .await?; + + // Assert + let registrar = nft_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.collection_configs.len(), 2); + + let max_voter_weight_record = nft_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.max_voter_weight, 25); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_max_collections() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Act + + for _ in 0..registrar_cookie.max_collections { + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + } + + // Assert + let registrar = nft_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!( + registrar.collection_configs.len() as u8, + registrar_cookie.max_collections + ); + + let max_voter_weight_record = nft_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.max_voter_weight, 30); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_existing_collection() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + // Act + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 2, + size: 10, + }), + ) + .await?; + + // Assert + let registrar = nft_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.collection_configs.len(), 1); + + let max_voter_weight_record = nft_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.max_voter_weight, 20); + + Ok(()) +} + +// TODO: Remove collection test + +#[tokio::test] +async fn test_configure_collection_with_invalid_realm_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Try to use a different Realm + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + + // Act + let err = nft_voter_test + .with_collection_using_ix( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + |i| i.accounts[1].pubkey = realm_cookie2.address, // realm + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::InvalidRealmForRegistrar); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_collection_with_realm_authority_must_sign_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Act + let err = nft_voter_test + .with_collection_using_ix( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + |i| i.accounts[2].is_signer = false, // realm_authority + Some(&[]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let realm_authority = Keypair::new(); + + // Act + let err = nft_voter_test + .with_collection_using_ix( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + |i| i.accounts[2].pubkey = realm_authority.pubkey(), // realm_authority + Some(&[&realm_authority]), + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::InvalidRealmAuthority); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let registrar_cookie2 = nft_voter_test.with_registrar(&realm_cookie2).await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie2) + .await?; + + // Act + let err = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::InvalidMaxVoterWeightRecordRealm); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_collection_with_invalid_max_voter_weight_mint_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + // Create Registrar for council mint + realm_cookie.account.community_mint = realm_cookie.account.config.council_mint.unwrap(); + let registrar_cookie2 = nft_voter_test.with_registrar(&realm_cookie).await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie2) + .await?; + + // Act + let err = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::InvalidMaxVoterWeightRecordMint); + + Ok(()) +} diff --git a/programs/core-voter/tests/create_max_voter_weight_record.rs b/programs/core-voter/tests/create_max_voter_weight_record.rs new file mode 100644 index 00000000..a69f0462 --- /dev/null +++ b/programs/core-voter/tests/create_max_voter_weight_record.rs @@ -0,0 +1,127 @@ +use anchor_lang::prelude::ErrorCode; +use program_test::{ + nft_voter_test::NftVoterTest, + tools::{assert_anchor_err, assert_ix_err}, +}; +use solana_program::instruction::InstructionError; +use solana_program_test::*; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_create_max_voter_weight_record() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + // Act + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Assert + + let max_voter_weight_record = nft_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!( + max_voter_weight_record_cookie.account, + max_voter_weight_record + ); + + Ok(()) +} + +#[tokio::test] +async fn test_create_max_voter_weight_record_with_invalid_realm_error() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + + // Act + let err = nft_voter_test + .with_max_voter_weight_record_using_ix(®istrar_cookie, |i| { + i.accounts[2].pubkey = realm_cookie2.address // Realm + }) + .await + .err() + .unwrap(); + + // Assert + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_max_voter_weight_record_with_invalid_mint_error() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + + // Act + let err = nft_voter_test + .with_max_voter_weight_record_using_ix(®istrar_cookie, |i| { + i.accounts[2].pubkey = realm_cookie2.address // Mint + }) + .await + .err() + .unwrap(); + + // Assert + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_max_voter_weight_record_with_already_exists_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Act + let err = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await + .err() + .unwrap(); + + // Assert + + // InstructionError::Custom(0) is returned for TransactionError::AccountInUse + assert_ix_err(err, InstructionError::Custom(0)); + + Ok(()) +} diff --git a/programs/core-voter/tests/create_registrar.rs b/programs/core-voter/tests/create_registrar.rs new file mode 100644 index 00000000..07561195 --- /dev/null +++ b/programs/core-voter/tests/create_registrar.rs @@ -0,0 +1,156 @@ +mod program_test; + +use anchor_lang::prelude::{ErrorCode, Pubkey}; +use gpl_nft_voter::error::NftVoterError; +use program_test::nft_voter_test::NftVoterTest; + +use solana_program_test::*; +use solana_sdk::{signature::Keypair, transport::TransportError}; + +use program_test::tools::{assert_anchor_err, assert_nft_voter_err}; + +#[tokio::test] +async fn test_create_registrar() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + // Act + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + // Assert + let registrar = nft_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar, registrar_cookie.account); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_realm_authority_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + // Act + let err = nft_voter_test + .with_registrar(&realm_cookie) + .await + .err() + .unwrap(); + + assert_nft_voter_err(err, NftVoterError::InvalidRealmAuthority); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_realm_authority_must_sign_error() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + // Act + let err = nft_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[4].is_signer = false, // realm_authority + Some(&[]), + ) + .await + .err() + .unwrap(); + + assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_spl_gov_program_id_error() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + // Try to use a different program id + let governance_program_id = nft_voter_test.program_id; + + // Act + let err = nft_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[1].pubkey = governance_program_id, //governance_program_id + None, + ) + .await + .err() + .unwrap(); + + assert_anchor_err(err, anchor_lang::error::ErrorCode::ConstraintOwner); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_realm_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + // Act + let err = nft_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[2].pubkey = Pubkey::new_unique(), // realm + None, + ) + .await + .err() + .unwrap(); + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_governing_token_mint_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + let mint_cookie = nft_voter_test.bench.with_mint().await?; + + // Act + let err = nft_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[3].pubkey = mint_cookie.address, // governing_token_mint + None, + ) + .await + .err() + .unwrap(); + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} diff --git a/programs/core-voter/tests/create_voter_weight_record.rs b/programs/core-voter/tests/create_voter_weight_record.rs new file mode 100644 index 00000000..761b2f49 --- /dev/null +++ b/programs/core-voter/tests/create_voter_weight_record.rs @@ -0,0 +1,127 @@ +use anchor_lang::prelude::ErrorCode; +use program_test::nft_voter_test::NftVoterTest; +use program_test::tools::{assert_anchor_err, assert_ix_err}; +use solana_program::instruction::InstructionError; +use solana_program_test::*; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_create_voter_weight_record() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + // Act + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record_cookie.account, voter_weight_record); + + Ok(()) +} + +#[tokio::test] +async fn test_create_voter_weight_record_with_invalid_realm_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + // Act + let err = nft_voter_test + .with_voter_weight_record_using_ix(®istrar_cookie, &voter_cookie, |i| { + i.accounts[2].pubkey = realm_cookie2.address // Realm + }) + .await + .err() + .unwrap(); + + // Assert + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_voter_weight_record_with_invalid_mint_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + // Act + let err = nft_voter_test + .with_voter_weight_record_using_ix(®istrar_cookie, &voter_cookie, |i| { + i.accounts[2].pubkey = realm_cookie2.address // Mint + }) + .await + .err() + .unwrap(); + + // Assert + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_voter_weight_record_with_already_exists_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Act + let err = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await + .err() + .unwrap(); + + // Assert + + // InstructionError::Custom(0) is returned for TransactionError::AccountInUse + assert_ix_err(err, InstructionError::Custom(0)); + + Ok(()) +} diff --git a/programs/core-voter/tests/fixtures/mpl_token_metadata.so b/programs/core-voter/tests/fixtures/mpl_token_metadata.so new file mode 100644 index 0000000000000000000000000000000000000000..8bbba46b848b03672b6ead90137137b535a1aafd GIT binary patch literal 693904 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�c^-bYB}?YD!g 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 a#eWyEwpjBiXveBD$PZKo^hKCXVN+ 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

ZfAggyy&VY!bV-*yC_vJR#KM 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�c)81_S#_J`-J|g^j3SuC#X*p=%>3tR0&mYJ4 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

`U4zMq(AyZ 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

=;tyYo+JA;`uJ4r`*Z2n&xIcqjZdGy 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, +} + +impl RealmCookie { + pub fn get_realm_authority(&self) -> Keypair { + clone_keypair(&self.realm_authority) + } +} + +pub struct ProposalCookie { + pub address: Pubkey, + pub account: ProposalV2, +} + +pub struct TokenOwnerRecordCookie { + pub address: Pubkey, + pub account: TokenOwnerRecordV2, +} + +pub struct GovernanceTest { + pub program_id: Pubkey, + pub bench: Arc, + pub next_id: u8, + pub community_voter_weight_addin: Option, + pub max_community_voter_weight_addin: Option, +} + +impl GovernanceTest { + pub fn program_id() -> Pubkey { + Pubkey::from_str("Governance111111111111111111111111111111111").unwrap() + } + + #[allow(dead_code)] + pub fn add_program(program_test: &mut ProgramTest) { + program_test.add_program("spl_governance", Self::program_id(), None); + } + + #[allow(dead_code)] + pub fn new( + bench: Arc, + community_voter_weight_addin: Option, + max_community_voter_weight_addin: Option, + ) -> Self { + GovernanceTest { + bench, + program_id: Self::program_id(), + next_id: 0, + community_voter_weight_addin, + max_community_voter_weight_addin, + } + } + + #[allow(dead_code)] + pub async fn with_realm(&mut self) -> Result { + let realm_authority = Keypair::new(); + + let community_mint_cookie = self.bench.with_mint().await?; + let council_mint_cookie = self.bench.with_mint().await?; + + self.next_id += 1; + let realm_name = format!("Realm #{}", self.next_id).to_string(); + + let min_community_weight_to_create_governance = 1; + let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; + + let realm_key = get_realm_address(&self.program_id, &realm_name); + + let community_token_config_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: self.community_voter_weight_addin, + max_voter_weight_addin: self.max_community_voter_weight_addin, + token_type: GoverningTokenType::default(), + }; + + let create_realm_ix = create_realm( + &self.program_id, + &realm_authority.pubkey(), + &community_mint_cookie.address, + &self.bench.payer.pubkey(), + Some(council_mint_cookie.address), + Some(community_token_config_args), + None, + realm_name.clone(), + min_community_weight_to_create_governance, + community_mint_max_voter_weight_source.clone(), + ); + + self.bench + .process_transaction(&[create_realm_ix], None) + .await?; + + let account = RealmV2 { + account_type: GovernanceAccountType::RealmV2, + community_mint: community_mint_cookie.address, + + name: realm_name, + reserved: [0; 6], + authority: Some(realm_authority.pubkey()), + config: RealmConfig { + council_mint: Some(council_mint_cookie.address), + reserved: [0; 6], + min_community_weight_to_create_governance, + community_mint_max_voter_weight_source, + legacy1: 0, + legacy2: 0, + }, + reserved_v2: [0; 128], + legacy1: 0, + }; + + Ok(RealmCookie { + address: realm_key, + account, + realm_authority, + community_mint_cookie, + council_mint_cookie: Some(council_mint_cookie), + }) + } + + #[allow(dead_code)] + pub async fn with_proposal( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + let token_account_cookie = self + .bench + .with_token_account(&realm_cookie.account.community_mint) + .await?; + + let token_owner = self.bench.payer.pubkey(); + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + let governing_token_mint = council_mint_cookie.address; + + let governing_token_account_cookie = self + .bench + .with_tokens(council_mint_cookie, &token_owner, 1) + .await?; + + let proposal_owner_record_key = get_token_owner_record_address( + &self.program_id, + &realm_cookie.address, + &governing_token_mint, + &token_owner, + ); + + let create_tor_ix = create_token_owner_record( + &self.program_id, + &realm_cookie.address, + &self.bench.payer.pubkey(), + &governing_token_mint, + &self.bench.payer.pubkey(), + ); + + self.bench + .process_transaction(&[create_tor_ix], None) + .await?; + + let deposit_ix = deposit_governing_tokens( + &self.program_id, + &realm_cookie.address, + &governing_token_account_cookie.address, + &token_owner, + &token_owner, + &self.bench.payer.pubkey(), + 1, + &governing_token_mint, + ); + + self.bench.process_transaction(&[deposit_ix], None).await?; + + let governance_key = get_governance_address( + &self.program_id, + &realm_cookie.address, + &token_account_cookie.address, + ); + + let create_governance_ix = create_governance( + &self.program_id, + &realm_cookie.address, + Some(&token_account_cookie.address), + &proposal_owner_record_key, + &self.bench.payer.pubkey(), + &realm_cookie.realm_authority.pubkey(), + None, + spl_governance::state::governance::GovernanceConfig { + min_community_weight_to_create_proposal: 1, + min_transaction_hold_up_time: 0, + + min_council_weight_to_create_proposal: 1, + community_vote_threshold: VoteThreshold::YesVotePercentage(60), + voting_base_time: 600, + community_vote_tipping: VoteTipping::Strict, + council_vote_threshold: VoteThreshold::YesVotePercentage(60), + council_veto_vote_threshold: VoteThreshold::Disabled, + council_vote_tipping: VoteTipping::Disabled, + community_veto_vote_threshold: VoteThreshold::Disabled, + voting_cool_off_time: 0, + deposit_exempt_proposal_count: 10, + }, + ); + + self.bench + .process_transaction( + &[create_governance_ix], + Some(&[&realm_cookie.realm_authority]), + ) + .await?; + + let proposal_governing_token_mint = realm_cookie.account.community_mint; + let proposal_seed = Pubkey::new_unique(); + + let proposal_key = get_proposal_address( + &self.program_id, + &governance_key, + &proposal_governing_token_mint, + &proposal_seed, + ); + + let create_proposal_ix = create_proposal( + &self.program_id, + &governance_key, + &proposal_owner_record_key, + &token_owner, + &self.bench.payer.pubkey(), + None, + &realm_cookie.address, + String::from("Proposal #1"), + String::from("Proposal #1 link"), + &proposal_governing_token_mint, + spl_governance::state::proposal::VoteType::SingleChoice, + vec!["Yes".to_string()], + true, + &proposal_seed, + ); + + let sign_off_proposal_ix = sign_off_proposal( + &self.program_id, + &realm_cookie.address, + &governance_key, + &proposal_key, + &token_owner, + Some(&proposal_owner_record_key), + ); + + self.bench + .process_transaction(&[create_proposal_ix, sign_off_proposal_ix], None) + .await?; + + let account = ProposalV2 { + account_type: GovernanceAccountType::GovernanceV2, + governing_token_mint: proposal_governing_token_mint, + state: ProposalState::Voting, + governance: governance_key, + token_owner_record: proposal_owner_record_key, + signatories_count: 1, + signatories_signed_off_count: 1, + vote_type: spl_governance::state::proposal::VoteType::SingleChoice, + options: vec![], + deny_vote_weight: Some(1), + veto_vote_weight: 0, + abstain_vote_weight: None, + start_voting_at: None, + draft_at: 1, + signing_off_at: None, + voting_at: None, + voting_at_slot: None, + voting_completed_at: None, + executing_at: None, + closed_at: None, + execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, + max_vote_weight: None, + max_voting_time: None, + reserved: [0; 64], + name: String::from("Proposal #1"), + description_link: String::from("Proposal #1 link"), + reserved1: 0, + vote_threshold: None, + }; + + Ok(ProposalCookie { + address: proposal_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn with_token_owner_record( + &mut self, + realm_cookie: &RealmCookie, + token_owner_cookie: &WalletCookie, + ) -> Result { + let token_owner_record_key = get_token_owner_record_address( + &self.program_id, + &realm_cookie.address, + &realm_cookie.account.community_mint, + &token_owner_cookie.address, + ); + + let create_tor_ix = create_token_owner_record( + &self.program_id, + &realm_cookie.address, + &token_owner_cookie.address, + &realm_cookie.account.community_mint, + &self.bench.payer.pubkey(), + ); + + self.bench + .process_transaction(&[create_tor_ix], None) + .await?; + + let account = TokenOwnerRecordV2 { + account_type: GovernanceAccountType::TokenOwnerRecordV2, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + governing_token_owner: token_owner_cookie.address, + governing_token_deposit_amount: 0, + unrelinquished_votes_count: 0, + outstanding_proposal_count: 0, + reserved: [0; 6], + governance_delegate: None, + reserved_v2: [0; 128], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }; + + Ok(TokenOwnerRecordCookie { + address: token_owner_record_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn relinquish_vote( + &mut self, + proposal_cookie: &ProposalCookie, + token_owner_cookie: &WalletCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), TransportError> { + let relinquish_vote_ix = relinquish_vote( + &self.program_id, + &token_owner_record_cookie.account.realm, + &proposal_cookie.account.governance, + &proposal_cookie.address, + &token_owner_record_cookie.address, + &proposal_cookie.account.governing_token_mint, + Some(token_owner_record_cookie.account.governing_token_owner), + Some(self.bench.payer.pubkey()), + ); + + self.bench + .process_transaction(&[relinquish_vote_ix], Some(&[&token_owner_cookie.signer])) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn set_governance_delegate( + &mut self, + realm_cookie: &RealmCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_owner_authority_cookie: &WalletCookie, + new_governance_delegate: &Option, + ) { + let set_governance_delegate_ix = set_governance_delegate( + &self.program_id, + &token_owner_authority_cookie.address, + &realm_cookie.address, + &token_owner_record_cookie.account.governing_token_mint, + &token_owner_record_cookie.account.governing_token_owner, + new_governance_delegate, + ); + + self.bench + .process_transaction( + &[set_governance_delegate_ix], + Some(&[&token_owner_authority_cookie.signer]), + ) + .await + .unwrap(); + } + + #[allow(dead_code)] + pub async fn get_proposal(&mut self, proposal_key: &Pubkey) -> ProposalV2 { + self.bench + .get_borsh_account::(proposal_key) + .await + } + + #[allow(dead_code)] + pub async fn get_token_owner_record( + &mut self, + token_owner_record_key: &Pubkey, + ) -> TokenOwnerRecordV2 { + self.bench + .get_borsh_account::(token_owner_record_key) + .await + } +} diff --git a/programs/core-voter/tests/program_test/mod.rs b/programs/core-voter/tests/program_test/mod.rs new file mode 100644 index 00000000..60cbb5dd --- /dev/null +++ b/programs/core-voter/tests/program_test/mod.rs @@ -0,0 +1,5 @@ +pub mod governance_test; +pub mod nft_voter_test; +pub mod program_test_bench; +pub mod token_metadata_test; +pub mod tools; diff --git a/programs/core-voter/tests/program_test/nft_voter_test.rs b/programs/core-voter/tests/program_test/nft_voter_test.rs new file mode 100644 index 00000000..309bdf71 --- /dev/null +++ b/programs/core-voter/tests/program_test/nft_voter_test.rs @@ -0,0 +1,597 @@ +use std::sync::Arc; + +use anchor_lang::prelude::{AccountMeta, Pubkey}; + +use gpl_nft_voter::state::max_voter_weight_record::{ + get_max_voter_weight_record_address, MaxVoterWeightRecord, +}; +use gpl_nft_voter::state::*; + +use spl_governance::instruction::cast_vote; +use spl_governance::state::vote_record::{self, Vote, VoteChoice}; + +use gpl_nft_voter::state::{ + get_nft_vote_record_address, get_registrar_address, CollectionConfig, NftVoteRecord, Registrar, +}; + +use solana_program_test::{BanksClientError, ProgramTest}; +use solana_sdk::instruction::Instruction; +use solana_sdk::signature::Keypair; +use solana_sdk::signer::Signer; + +use crate::program_test::governance_test::GovernanceTest; +use crate::program_test::program_test_bench::ProgramTestBench; + +use crate::program_test::governance_test::{ProposalCookie, RealmCookie, TokenOwnerRecordCookie}; +use crate::program_test::program_test_bench::WalletCookie; +use crate::program_test::token_metadata_test::{NftCollectionCookie, NftCookie, TokenMetadataTest}; +use crate::program_test::tools::NopOverride; + +#[derive(Debug, PartialEq)] +pub struct RegistrarCookie { + pub address: Pubkey, + pub account: Registrar, + + pub realm_authority: Keypair, + pub max_collections: u8, +} + +pub struct VoterWeightRecordCookie { + pub address: Pubkey, + pub account: VoterWeightRecord, +} + +pub struct MaxVoterWeightRecordCookie { + pub address: Pubkey, + pub account: MaxVoterWeightRecord, +} + +pub struct CollectionConfigCookie { + pub collection_config: CollectionConfig, +} + +pub struct ConfigureCollectionArgs { + pub weight: u64, + pub size: u32, +} + +impl Default for ConfigureCollectionArgs { + fn default() -> Self { + Self { weight: 1, size: 3 } + } +} + +#[derive(Debug, PartialEq)] +pub struct NftVoteRecordCookie { + pub address: Pubkey, + pub account: NftVoteRecord, +} + +pub struct CastNftVoteArgs { + pub cast_spl_gov_vote: bool, +} + +impl Default for CastNftVoteArgs { + fn default() -> Self { + Self { + cast_spl_gov_vote: true, + } + } +} + +pub struct NftVoterTest { + pub program_id: Pubkey, + pub bench: Arc, + pub governance: GovernanceTest, + pub token_metadata: TokenMetadataTest, +} + +impl NftVoterTest { + #[allow(dead_code)] + pub fn add_program(program_test: &mut ProgramTest) { + program_test.add_program("gpl_nft_voter", gpl_nft_voter::id(), None); + } + + #[allow(dead_code)] + pub async fn start_new() -> Self { + let mut program_test = ProgramTest::default(); + + NftVoterTest::add_program(&mut program_test); + GovernanceTest::add_program(&mut program_test); + TokenMetadataTest::add_program(&mut program_test); + + let program_id = gpl_nft_voter::id(); + + let bench = ProgramTestBench::start_new(program_test).await; + let bench_rc = Arc::new(bench); + + let governance_bench = + GovernanceTest::new(bench_rc.clone(), Some(program_id), Some(program_id)); + let token_metadata_bench = TokenMetadataTest::new(bench_rc.clone()); + + Self { + program_id, + bench: bench_rc, + governance: governance_bench, + token_metadata: token_metadata_bench, + } + } + + #[allow(dead_code)] + pub async fn with_registrar( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + self.with_registrar_using_ix(realm_cookie, NopOverride, None) + .await + } + + #[allow(dead_code)] + pub async fn with_registrar_using_ix( + &mut self, + realm_cookie: &RealmCookie, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let registrar_key = + get_registrar_address(&realm_cookie.address, &realm_cookie.account.community_mint); + + let max_collections = 10; + + let data = + anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::CreateRegistrar { + max_collections, + }); + + let accounts = anchor_lang::ToAccountMetas::to_account_metas( + &gpl_nft_voter::accounts::CreateRegistrar { + registrar: registrar_key, + realm: realm_cookie.address, + governance_program_id: self.governance.program_id, + governing_token_mint: realm_cookie.account.community_mint, + realm_authority: realm_cookie.get_realm_authority().pubkey(), + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }, + None, + ); + + let mut create_registrar_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts, + data, + }; + + instruction_override(&mut create_registrar_ix); + + let default_signers = &[&realm_cookie.realm_authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[create_registrar_ix], Some(signers)) + .await?; + + let account = Registrar { + governance_program_id: self.governance.program_id, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + collection_configs: vec![], + reserved: [0; 128], + }; + + Ok(RegistrarCookie { + address: registrar_key, + account, + realm_authority: realm_cookie.get_realm_authority(), + max_collections, + }) + } + + #[allow(dead_code)] + pub async fn with_voter_weight_record( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &WalletCookie, + ) -> Result { + self.with_voter_weight_record_using_ix(registrar_cookie, voter_cookie, NopOverride) + .await + } + + #[allow(dead_code)] + pub async fn with_voter_weight_record_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &WalletCookie, + instruction_override: F, + ) -> Result { + let governing_token_owner = voter_cookie.address; + + let (voter_weight_record_key, _) = Pubkey::find_program_address( + &[ + b"voter-weight-record".as_ref(), + registrar_cookie.account.realm.as_ref(), + registrar_cookie.account.governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + ], + &gpl_nft_voter::id(), + ); + + let data = anchor_lang::InstructionData::data( + &gpl_nft_voter::instruction::CreateVoterWeightRecord { + governing_token_owner, + }, + ); + + let accounts = gpl_nft_voter::accounts::CreateVoterWeightRecord { + governance_program_id: self.governance.program_id, + realm: registrar_cookie.account.realm, + realm_governing_token_mint: registrar_cookie.account.governing_token_mint, + voter_weight_record: voter_weight_record_key, + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }; + + let mut create_voter_weight_record_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut create_voter_weight_record_ix); + + self.bench + .process_transaction(&[create_voter_weight_record_ix], None) + .await?; + + let account = VoterWeightRecord { + realm: registrar_cookie.account.realm, + governing_token_mint: registrar_cookie.account.governing_token_mint, + governing_token_owner, + voter_weight: 0, + voter_weight_expiry: Some(0), + weight_action: None, + weight_action_target: None, + reserved: [0; 8], + }; + + Ok(VoterWeightRecordCookie { + address: voter_weight_record_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn with_max_voter_weight_record( + &mut self, + registrar_cookie: &RegistrarCookie, + ) -> Result { + self.with_max_voter_weight_record_using_ix(registrar_cookie, NopOverride) + .await + } + + #[allow(dead_code)] + pub async fn with_max_voter_weight_record_using_ix( + &mut self, + registrar_cookie: &RegistrarCookie, + instruction_override: F, + ) -> Result { + let max_voter_weight_record_key = get_max_voter_weight_record_address( + ®istrar_cookie.account.realm, + ®istrar_cookie.account.governing_token_mint, + ); + + let data = anchor_lang::InstructionData::data( + &gpl_nft_voter::instruction::CreateMaxVoterWeightRecord {}, + ); + + let accounts = gpl_nft_voter::accounts::CreateMaxVoterWeightRecord { + governance_program_id: self.governance.program_id, + realm: registrar_cookie.account.realm, + realm_governing_token_mint: registrar_cookie.account.governing_token_mint, + max_voter_weight_record: max_voter_weight_record_key, + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }; + + let mut create_max_voter_weight_record_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut create_max_voter_weight_record_ix); + + self.bench + .process_transaction(&[create_max_voter_weight_record_ix], None) + .await?; + + let account = MaxVoterWeightRecord { + realm: registrar_cookie.account.realm, + governing_token_mint: registrar_cookie.account.governing_token_mint, + max_voter_weight: 0, + max_voter_weight_expiry: Some(0), + reserved: [0; 8], + }; + + Ok(MaxVoterWeightRecordCookie { + account, + address: max_voter_weight_record_key, + }) + } + + #[allow(dead_code)] + pub async fn update_voter_weight_record( + &self, + registrar_cookie: &RegistrarCookie, + voter_weight_record_cookie: &mut VoterWeightRecordCookie, + voter_weight_action: VoterWeightAction, + nft_cookies: &[&NftCookie], + ) -> Result<(), BanksClientError> { + let data = anchor_lang::InstructionData::data( + &gpl_nft_voter::instruction::UpdateVoterWeightRecord { + voter_weight_action, + }, + ); + + let accounts = gpl_nft_voter::accounts::UpdateVoterWeightRecord { + registrar: registrar_cookie.address, + voter_weight_record: voter_weight_record_cookie.address, + }; + + let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); + + for nft_cookie in nft_cookies { + account_metas.push(AccountMeta::new_readonly(nft_cookie.address, false)); + account_metas.push(AccountMeta::new_readonly(nft_cookie.metadata, false)); + } + + let instructions = vec![Instruction { + program_id: gpl_nft_voter::id(), + accounts: account_metas, + data, + }]; + + self.bench.process_transaction(&instructions, None).await + } + + #[allow(dead_code)] + pub async fn relinquish_nft_vote( + &mut self, + registrar_cookie: &RegistrarCookie, + voter_weight_record_cookie: &VoterWeightRecordCookie, + proposal_cookie: &ProposalCookie, + voter_cookie: &WalletCookie, + voter_token_owner_record_cookie: &TokenOwnerRecordCookie, + nft_vote_record_cookies: &Vec, + ) -> Result<(), BanksClientError> { + let data = + anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::RelinquishNftVote {}); + + let vote_record_key = vote_record::get_vote_record_address( + &self.governance.program_id, + &proposal_cookie.address, + &voter_token_owner_record_cookie.address, + ); + + let accounts = gpl_nft_voter::accounts::RelinquishNftVote { + registrar: registrar_cookie.address, + voter_weight_record: voter_weight_record_cookie.address, + governance: proposal_cookie.account.governance, + proposal: proposal_cookie.address, + vote_record: vote_record_key, + beneficiary: self.bench.payer.pubkey(), + voter_token_owner_record: voter_token_owner_record_cookie.address, + voter_authority: voter_cookie.address, + }; + + let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); + + for nft_vote_record_cookie in nft_vote_record_cookies { + account_metas.push(AccountMeta::new(nft_vote_record_cookie.address, false)); + } + + let relinquish_nft_vote_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts: account_metas, + data, + }; + + self.bench + .process_transaction(&[relinquish_nft_vote_ix], Some(&[&voter_cookie.signer])) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn with_collection( + &mut self, + registrar_cookie: &RegistrarCookie, + nft_collection_cookie: &NftCollectionCookie, + max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, + args: Option, + ) -> Result { + self.with_collection_using_ix( + registrar_cookie, + nft_collection_cookie, + max_voter_weight_record_cookie, + args, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn with_collection_using_ix( + &mut self, + registrar_cookie: &RegistrarCookie, + nft_collection_cookie: &NftCollectionCookie, + max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, + args: Option, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let args = args.unwrap_or_default(); + + let data = + anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::ConfigureCollection { + weight: args.weight, + size: args.size, + }); + + let accounts = gpl_nft_voter::accounts::ConfigureCollection { + registrar: registrar_cookie.address, + realm: registrar_cookie.account.realm, + realm_authority: registrar_cookie.realm_authority.pubkey(), + collection: nft_collection_cookie.mint, + max_voter_weight_record: max_voter_weight_record_cookie.address, + }; + + let mut configure_collection_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut configure_collection_ix); + + let default_signers = &[®istrar_cookie.realm_authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[configure_collection_ix], Some(signers)) + .await?; + + let collection_config = CollectionConfig { + collection: nft_collection_cookie.mint, + size: args.size, + weight: args.weight, + reserved: [0; 8], + }; + + Ok(CollectionConfigCookie { collection_config }) + } + + /// Casts NFT Vote and spl-gov Vote + #[allow(dead_code)] + pub async fn cast_nft_vote( + &mut self, + registrar_cookie: &RegistrarCookie, + voter_weight_record_cookie: &VoterWeightRecordCookie, + max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, + proposal_cookie: &ProposalCookie, + nft_voter_cookie: &WalletCookie, + voter_token_owner_record_cookie: &TokenOwnerRecordCookie, + nft_cookies: &[&NftCookie], + args: Option, + ) -> Result, BanksClientError> { + let args = args.unwrap_or_default(); + + let data = anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::CastNftVote { + proposal: proposal_cookie.address, + }); + + let accounts = gpl_nft_voter::accounts::CastNftVote { + registrar: registrar_cookie.address, + voter_weight_record: voter_weight_record_cookie.address, + voter_token_owner_record: voter_token_owner_record_cookie.address, + voter_authority: nft_voter_cookie.address, + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }; + + let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); + let mut nft_vote_record_cookies = vec![]; + + for nft_cookie in nft_cookies { + account_metas.push(AccountMeta::new_readonly(nft_cookie.address, false)); + account_metas.push(AccountMeta::new_readonly(nft_cookie.metadata, false)); + + let nft_vote_record_key = get_nft_vote_record_address( + &proposal_cookie.address, + &nft_cookie.mint_cookie.address, + ); + account_metas.push(AccountMeta::new(nft_vote_record_key, false)); + + let account = NftVoteRecord { + proposal: proposal_cookie.address, + nft_mint: nft_cookie.mint_cookie.address, + governing_token_owner: voter_weight_record_cookie.account.governing_token_owner, + account_discriminator: NftVoteRecord::ACCOUNT_DISCRIMINATOR, + reserved: [0; 8], + }; + + nft_vote_record_cookies.push(NftVoteRecordCookie { + address: nft_vote_record_key, + account, + }) + } + + let cast_nft_vote_ix = Instruction { + program_id: gpl_nft_voter::id(), + accounts: account_metas, + data, + }; + + let mut instruction = vec![cast_nft_vote_ix]; + + if args.cast_spl_gov_vote { + // spl-gov cast vote + let vote = Vote::Approve(vec![VoteChoice { + rank: 0, + weight_percentage: 100, + }]); + + let cast_vote_ix = cast_vote( + &self.governance.program_id, + ®istrar_cookie.account.realm, + &proposal_cookie.account.governance, + &proposal_cookie.address, + &proposal_cookie.account.token_owner_record, + &voter_token_owner_record_cookie.address, + &nft_voter_cookie.address, + &proposal_cookie.account.governing_token_mint, + &self.bench.payer.pubkey(), + Some(voter_weight_record_cookie.address), + Some(max_voter_weight_record_cookie.address), + vote, + ); + + instruction.push(cast_vote_ix); + } + + self.bench + .process_transaction(&instruction, Some(&[&nft_voter_cookie.signer])) + .await?; + + Ok(nft_vote_record_cookies) + } + + #[allow(dead_code)] + pub async fn get_registrar_account(&mut self, registrar: &Pubkey) -> Registrar { + self.bench.get_anchor_account::(*registrar).await + } + + #[allow(dead_code)] + pub async fn get_nft_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> NftVoteRecord { + self.bench + .get_borsh_account::(nft_vote_record) + .await + } + + #[allow(dead_code)] + pub async fn get_max_voter_weight_record( + &self, + max_voter_weight_record: &Pubkey, + ) -> MaxVoterWeightRecord { + self.bench + .get_anchor_account(*max_voter_weight_record) + .await + } + + #[allow(dead_code)] + pub async fn get_voter_weight_record(&self, voter_weight_record: &Pubkey) -> VoterWeightRecord { + self.bench.get_anchor_account(*voter_weight_record).await + } +} diff --git a/programs/core-voter/tests/program_test/program_test_bench.rs b/programs/core-voter/tests/program_test/program_test_bench.rs new file mode 100644 index 00000000..7d0f4554 --- /dev/null +++ b/programs/core-voter/tests/program_test/program_test_bench.rs @@ -0,0 +1,328 @@ +use std::cell::RefCell; + +use anchor_lang::{ + prelude::{Pubkey, Rent}, + AccountDeserialize, +}; + +use solana_program::{borsh::try_from_slice_unchecked, system_program}; +use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; +use solana_sdk::{ + account::{Account, ReadableAccount}, + instruction::Instruction, + program_pack::Pack, + signature::Keypair, + signer::Signer, + system_instruction, + transaction::Transaction, + transport::TransportError, +}; + +use borsh::BorshDeserialize; + +use crate::program_test::tools::clone_keypair; + +pub struct MintCookie { + pub address: Pubkey, + pub mint_authority: Keypair, + pub freeze_authority: Option, +} +pub struct TokenAccountCookie { + pub address: Pubkey, +} + +#[derive(Debug)] +pub struct WalletCookie { + pub address: Pubkey, + pub account: Account, + + pub signer: Keypair, +} + +pub struct ProgramTestBench { + pub context: RefCell, + pub payer: Keypair, + pub rent: Rent, +} + +impl ProgramTestBench { + /// Create new bench given a ProgramTest instance populated with all of the + /// desired programs. + pub async fn start_new(program_test: ProgramTest) -> Self { + let mut context = program_test.start_with_context().await; + + let payer = clone_keypair(&context.payer); + + let rent = context.banks_client.get_rent().await.unwrap(); + + Self { + payer, + context: RefCell::new(context), + rent, + } + } + + #[allow(dead_code)] + pub async fn process_transaction( + &self, + instructions: &[Instruction], + signers: Option<&[&Keypair]>, + ) -> Result<(), BanksClientError> { + let mut context = self.context.borrow_mut(); + + let mut transaction = + Transaction::new_with_payer(&instructions, Some(&context.payer.pubkey())); + + let mut all_signers = vec![&context.payer]; + + if let Some(signers) = signers { + all_signers.extend_from_slice(signers); + } + + transaction.sign(&all_signers, context.last_blockhash); + + context + .banks_client + .process_transaction_with_commitment( + transaction, + solana_sdk::commitment_config::CommitmentLevel::Processed, + ) + .await + } + + pub async fn get_clock(&self) -> solana_program::clock::Clock { + self.context + .borrow_mut() + .banks_client + .get_sysvar::() + .await + .unwrap() + } + + #[allow(dead_code)] + pub async fn advance_clock(&self) { + let clock = self.get_clock().await; + self.context + .borrow_mut() + .warp_to_slot(clock.slot + 2) + .unwrap(); + } + + pub async fn with_mint(&self) -> Result { + let mint_keypair = Keypair::new(); + let mint_authority = Keypair::new(); + let freeze_authority = clone_keypair(&mint_authority); + + self.create_mint( + &mint_keypair, + &mint_authority.pubkey(), + Some(&freeze_authority.pubkey()), + ) + .await?; + + Ok(MintCookie { + address: mint_keypair.pubkey(), + mint_authority, + freeze_authority: Some(freeze_authority), + }) + } + + #[allow(dead_code)] + pub async fn create_mint( + &self, + mint_keypair: &Keypair, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + ) -> Result<(), BanksClientError> { + let mint_rent = self.rent.minimum_balance(spl_token::state::Mint::LEN); + + let instructions = [ + system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + spl_token::state::Mint::LEN as u64, + &spl_token::id(), + ), + spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ]; + + self.process_transaction(&instructions, Some(&[mint_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn with_token_account( + &self, + token_mint: &Pubkey, + ) -> Result { + let token_account_keypair = Keypair::new(); + self.create_token_account(&token_account_keypair, token_mint, &self.payer.pubkey()) + .await?; + + Ok(TokenAccountCookie { + address: token_account_keypair.pubkey(), + }) + } + + #[allow(dead_code)] + pub async fn with_tokens( + &self, + mint_cookie: &MintCookie, + owner: &Pubkey, + amount: u64, + ) -> Result { + let token_account_keypair = Keypair::new(); + + self.create_token_account(&token_account_keypair, &mint_cookie.address, owner) + .await?; + + self.mint_tokens( + &mint_cookie.address, + &mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + amount, + ) + .await?; + + Ok(TokenAccountCookie { + address: token_account_keypair.pubkey(), + }) + } + + pub async fn mint_tokens( + &self, + token_mint: &Pubkey, + token_mint_authority: &Keypair, + token_account: &Pubkey, + amount: u64, + ) -> Result<(), BanksClientError> { + let mint_instruction = spl_token::instruction::mint_to( + &spl_token::id(), + token_mint, + token_account, + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap(); + + self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) + .await + } + + #[allow(dead_code)] + pub async fn create_token_account( + &self, + token_account_keypair: &Keypair, + token_mint: &Pubkey, + owner: &Pubkey, + ) -> Result<(), BanksClientError> { + let rent = self + .context + .borrow_mut() + .banks_client + .get_rent() + .await + .unwrap(); + + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + rent.minimum_balance(spl_token::state::Account::get_packed_len()), + spl_token::state::Account::get_packed_len() as u64, + &spl_token::id(), + ); + + let initialize_account_instruction = spl_token::instruction::initialize_account( + &spl_token::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + + self.process_transaction( + &[create_account_instruction, initialize_account_instruction], + Some(&[token_account_keypair]), + ) + .await + } + + #[allow(dead_code)] + pub async fn with_wallet(&self) -> WalletCookie { + let account_rent = self.rent.minimum_balance(0); + let account_keypair = Keypair::new(); + + let create_account_ix = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &account_keypair.pubkey(), + account_rent, + 0, + &system_program::id(), + ); + + self.process_transaction(&[create_account_ix], Some(&[&account_keypair])) + .await + .unwrap(); + + let account = Account { + lamports: account_rent, + data: vec![], + owner: system_program::id(), + executable: false, + rent_epoch: 0, + }; + + WalletCookie { + address: account_keypair.pubkey(), + account, + signer: account_keypair, + } + } + + #[allow(dead_code)] + pub async fn get_account(&self, address: &Pubkey) -> Option { + self.context + .borrow_mut() + .banks_client + .get_account(*address) + .await + .unwrap() + } + + #[allow(dead_code)] + pub async fn get_borsh_account(&self, address: &Pubkey) -> T { + self.get_account(address) + .await + .map(|a| try_from_slice_unchecked(&a.data).unwrap()) + .unwrap_or_else(|| panic!("GET-TEST-ACCOUNT-ERROR: Account {} not found", address)) + } + + #[allow(dead_code)] + pub async fn get_account_data(&self, address: Pubkey) -> Vec { + self.context + .borrow_mut() + .banks_client + .get_account(address) + .await + .unwrap() + .unwrap() + .data() + .to_vec() + } + + #[allow(dead_code)] + pub async fn get_anchor_account(&self, address: Pubkey) -> T { + let data = self.get_account_data(address).await; + let mut data_slice: &[u8] = &data; + AccountDeserialize::try_deserialize(&mut data_slice).unwrap() + } +} diff --git a/programs/core-voter/tests/program_test/token_metadata_test.rs b/programs/core-voter/tests/program_test/token_metadata_test.rs new file mode 100644 index 00000000..08c94ea8 --- /dev/null +++ b/programs/core-voter/tests/program_test/token_metadata_test.rs @@ -0,0 +1,253 @@ +use std::{str::FromStr, sync::Arc}; + +use anchor_lang::prelude::Pubkey; +use mpl_token_metadata::{types::Collection, types::DataV2}; +use solana_program_test::ProgramTest; +use solana_sdk::{signer::Signer, system_program, transport::TransportError}; + +use crate::program_test::program_test_bench::{MintCookie, ProgramTestBench, WalletCookie}; + +pub struct NftCookie { + pub address: Pubkey, + pub metadata: Pubkey, + pub mint_cookie: MintCookie, +} + +pub struct NftCollectionCookie { + pub mint: Pubkey, + pub metadata: Pubkey, + pub master_edition: Pubkey, +} + +pub struct CreateNftArgs { + pub verify_collection: bool, + pub amount: u64, +} + +impl Default for CreateNftArgs { + fn default() -> Self { + Self { + verify_collection: true, + amount: 1, + } + } +} + +pub struct TokenMetadataTest { + pub bench: Arc, + pub program_id: Pubkey, +} + +impl TokenMetadataTest { + pub fn program_id() -> Pubkey { + Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap() + } + + #[allow(dead_code)] + pub fn add_program(program_test: &mut ProgramTest) { + program_test.add_program("mpl_token_metadata", Self::program_id(), None); + } + + #[allow(dead_code)] + pub fn new(bench: Arc) -> Self { + TokenMetadataTest { + bench, + program_id: Self::program_id(), + } + } + + #[allow(dead_code)] + pub async fn with_nft_collection(&self) -> Result { + let update_authority = self.bench.context.borrow().payer.pubkey(); + let payer = self.bench.context.borrow().payer.pubkey(); + + // Create collection + let coll_mint_cookie = self.bench.with_mint().await?; + self.bench + .with_tokens(&coll_mint_cookie, &update_authority, 1) + .await?; + + let coll_metadata_seeds = &[ + b"metadata".as_ref(), + self.program_id.as_ref(), + &coll_mint_cookie.address.as_ref(), + ]; + let (coll_metadata_key, _) = + Pubkey::find_program_address(coll_metadata_seeds, &self.program_id); + + let coll_name = "NFT_C".to_string(); + let coll_symbol = "NFT_C".to_string(); + let coll_uri = "URI".to_string(); + + // instruction args + let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { + data: DataV2 { + name: coll_name, + symbol: coll_symbol, + uri: coll_uri, + seller_fee_basis_points: 10, + creators: None, + collection: None, + uses: None, + }, + is_mutable: true, + collection_details: None, + }; + + // instruction accounts + let create_coll_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { + metadata: coll_metadata_key, + mint: coll_mint_cookie.address, + mint_authority: coll_mint_cookie.mint_authority.pubkey(), + payer: payer, + update_authority: (payer, true), + system_program: system_program::ID, + rent: None, + }; + + // creates the instruction + let create_coll_metadata_ix = create_coll_metadata_ix_accounts.instruction(args); + + self.bench + .process_transaction( + &[create_coll_metadata_ix], + Some(&[&coll_mint_cookie.mint_authority]), + ) + .await?; + + let master_edition_seeds = &[ + b"metadata".as_ref(), + self.program_id.as_ref(), + coll_mint_cookie.address.as_ref(), + b"edition".as_ref(), + ]; + let (master_edition_key, _) = + Pubkey::find_program_address(master_edition_seeds, &self.program_id); + + + // instruction args + let args_master_edition_v3 = mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { + max_supply: Some(0), + }; + + // instruction accounts + let create_master_edition_v3_ix_accounts = mpl_token_metadata::instructions::CreateMasterEditionV3 { + edition: master_edition_key, + metadata: coll_metadata_key, + mint: coll_mint_cookie.address, + mint_authority: coll_mint_cookie.mint_authority.pubkey(), + payer: payer, + update_authority: payer, + system_program: system_program::ID, + token_program: spl_token::id(), + rent: None, + }; + + let create_master_edition_ix = create_master_edition_v3_ix_accounts.instruction(args_master_edition_v3); + + self.bench + .process_transaction( + &[create_master_edition_ix], + Some(&[&coll_mint_cookie.mint_authority]), + ) + .await?; + + Ok(NftCollectionCookie { + mint: coll_mint_cookie.address, + metadata: coll_metadata_key, + master_edition: master_edition_key, + }) + } + + #[allow(dead_code)] + pub async fn with_nft_v2( + &self, + nft_collection_cookie: &NftCollectionCookie, + nft_owner_cookie: &WalletCookie, + args: Option, + ) -> Result { + let CreateNftArgs { + verify_collection, + amount, + } = args.unwrap_or_default(); + + // Crate NFT + let mint_cookie = self.bench.with_mint().await?; + let nft_account_cookie = self + .bench + .with_tokens(&mint_cookie, &nft_owner_cookie.address, amount) + .await?; + + let metadata_seeds = &[ + b"metadata".as_ref(), + self.program_id.as_ref(), + &mint_cookie.address.as_ref(), + ]; + let (metadata_key, _) = Pubkey::find_program_address(metadata_seeds, &self.program_id); + + let name = "TestNFT".to_string(); + let symbol = "NFT".to_string(); + let uri = "URI".to_string(); + + let collection = Collection { + verified: false, + key: nft_collection_cookie.mint, + }; + + // instruction args + let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { + data: DataV2 { + name: name, + symbol: symbol, + uri: uri, + seller_fee_basis_points: 10, + creators: None, + collection: Some(collection), + uses: None, + }, + is_mutable: true, + collection_details: None, + }; + + // instruction accounts + let create_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { + metadata: metadata_key, + mint: mint_cookie.address, + mint_authority: mint_cookie.mint_authority.pubkey(), + payer: self.bench.payer.pubkey(), + update_authority: (self.bench.payer.pubkey(), true), + system_program: system_program::ID, + rent: None, + }; + + // creates the instruction + let create_metadata_ix = create_metadata_ix_accounts.instruction(args); + + self.bench + .process_transaction(&[create_metadata_ix], Some(&[&mint_cookie.mint_authority])) + .await?; + + if verify_collection { + let verify_collection_accounts = mpl_token_metadata::instructions::VerifyCollection { + metadata: metadata_key, + collection_authority: self.bench.payer.pubkey(), + payer: self.bench.payer.pubkey(), + collection_mint: nft_collection_cookie.mint, + collection: nft_collection_cookie.metadata, + collection_master_edition_account: nft_collection_cookie.master_edition, + collection_authority_record: None, + }; + let verify_collection = verify_collection_accounts.instruction(); + + self.bench + .process_transaction(&[verify_collection], None) + .await?; + } + + Ok(NftCookie { + address: nft_account_cookie.address, + metadata: metadata_key, + mint_cookie, + }) + } +} diff --git a/programs/core-voter/tests/program_test/tools.rs b/programs/core-voter/tests/program_test/tools.rs new file mode 100644 index 00000000..77a13c8e --- /dev/null +++ b/programs/core-voter/tests/program_test/tools.rs @@ -0,0 +1,93 @@ +use anchor_lang::prelude::ERROR_CODE_OFFSET; +use gpl_nft_voter::error::NftVoterError; +use solana_program::instruction::InstructionError; +use solana_program_test::BanksClientError; +use solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}; +use spl_governance::error::GovernanceError; +use spl_governance_tools::error::GovernanceToolsError; + +pub fn clone_keypair(source: &Keypair) -> Keypair { + Keypair::from_bytes(&source.to_bytes()).unwrap() +} + +/// NOP (No Operation) Override function +#[allow(non_snake_case)] +pub fn NopOverride(_: &mut T) {} + +#[allow(dead_code)] +pub fn assert_nft_voter_err(banks_client_error: BanksClientError, nft_locker_error: NftVoterError) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, nft_locker_error as u32 + ERROR_CODE_OFFSET) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_gov_tools_err( + banks_client_error: TransportError, + gov_tools_error: GovernanceToolsError, +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, gov_tools_error as u32) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_gov_err(banks_client_error: BanksClientError, gov_error: GovernanceError) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, gov_error as u32) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_anchor_err( + banks_client_error: BanksClientError, + anchor_error: anchor_lang::error::ErrorCode, +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, anchor_error as u32) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_ix_err(banks_client_error: BanksClientError, ix_error: InstructionError) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => { + assert_eq!(instruction_error, ix_error); + } + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs new file mode 100644 index 00000000..4f6005c1 --- /dev/null +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -0,0 +1,649 @@ +use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use gpl_nft_voter::error::NftVoterError; +use program_test::nft_voter_test::{CastNftVoteArgs, NftVoterTest}; +use program_test::tools::{assert_gov_err, assert_nft_voter_err}; +use solana_program_test::*; +use solana_sdk::transport::TransportError; +use spl_governance::error::GovernanceError; + +mod program_test; + +#[tokio::test] +async fn test_relinquish_nft_vote() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Act + + nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight_expiry, Some(0)); + assert_eq!(voter_weight_record.voter_weight, 0); + + // Check NftVoteRecord was disposed + let nft_vote_record = nft_voter_test + .bench + .get_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(None, nft_vote_record); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Relinquish Vote from spl-gov + nft_voter_test + .governance + .relinquish_vote( + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + ) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Act + + nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight_expiry, Some(0)); + assert_eq!(voter_weight_record.voter_weight, 0); + + // Check NftVoteRecord was disposed + let nft_vote_record = nft_voter_test + .bench + .get_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(None, nft_vote_record); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Act + + let err = nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::VoteRecordMustBeWithdrawn); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Try to use a different voter + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + + // Act + + let err = nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie2, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> +{ + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let args = CastNftVoteArgs { + cast_spl_gov_vote: false, + }; + + // Cast vote with NFT + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + Some(args), + ) + .await?; + + // Act + + let err = nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::VoterWeightRecordMustBeExpired); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( +) -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + // Try to update VoterWeightRecord for different governing_token_owner + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_weight_record_cookie2 = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie2) + .await?; + + // Act + + let err = nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie2, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); + + Ok(()) +} + +#[tokio::test] +async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let voter_token_owner_record_cookie = nft_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = nft_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_vote_record_cookies = nft_voter_test + .cast_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&nft_cookie1], + None, + ) + .await?; + + nft_voter_test.bench.advance_clock().await; + + // Setup delegate + let delegate_cookie = nft_voter_test.bench.with_wallet().await; + nft_voter_test + .governance + .set_governance_delegate( + &realm_cookie, + &voter_token_owner_record_cookie, + &voter_cookie, + &Some(delegate_cookie.address), + ) + .await; + + // Act + + nft_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &delegate_cookie, + &voter_token_owner_record_cookie, + &nft_vote_record_cookies, + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight_expiry, Some(0)); + assert_eq!(voter_weight_record.voter_weight, 0); + + // Check NftVoteRecord was disposed + let nft_vote_record = nft_voter_test + .bench + .get_account(&nft_vote_record_cookies[0].address) + .await; + + assert_eq!(None, nft_vote_record); + + Ok(()) +} diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs new file mode 100644 index 00000000..d29809a2 --- /dev/null +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -0,0 +1,575 @@ +use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use gpl_nft_voter::error::NftVoterError; +use gpl_nft_voter::state::*; +use program_test::nft_voter_test::NftVoterTest; +use program_test::token_metadata_test::CreateNftArgs; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_update_voter_weight_record() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _collection_config_cookie = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + // Act + nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateProposal, + &[&nft1_cookie], + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 10); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CreateProposal.into()) + ); + assert_eq!(voter_weight_record.weight_action_target, None); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _collection_config_cookie = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft_cookie1 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + let nft_cookie2 = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + nft_voter_test.bench.advance_clock().await; + let clock = nft_voter_test.bench.get_clock().await; + + // Act + nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateProposal, + &[&nft_cookie1, &nft_cookie2], + ) + .await?; + + // Assert + + let voter_weight_record = nft_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CreateProposal.into()) + ); + assert_eq!(voter_weight_record.weight_action_target, None); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CastVote, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CastVoteIsNotAllowed); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_unverified_collection_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + // Create NFT without verified collection + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + verify_collection: false, + ..Default::default() + }), + ) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateGovernance, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie2, None) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateGovernance, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie2, &voter_cookie, None) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateGovernance, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionNotFound); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_invalid_metadata_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let mut nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + verify_collection: false, + ..Default::default() + }), + ) + .await?; + + let nft2_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Try to use verified NFT Metadata + nft1_cookie.metadata = nft2_cookie.metadata; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateGovernance, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::TokenMetadataDoesNotMatch); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft_cookie = nft_voter_test + .token_metadata + .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateProposal, + &[&nft_cookie, &nft_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); + + Ok(()) +} + +#[tokio::test] +async fn test_update_voter_weight_record_with_no_nft_error() -> Result<(), TransportError> { + // Arrange + let mut nft_voter_test = NftVoterTest::start_new().await; + + let realm_cookie = nft_voter_test.governance.with_realm().await?; + + let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + + let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + + let max_voter_weight_record_cookie = nft_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _collection_config_cookie = nft_voter_test + .with_collection( + ®istrar_cookie, + &nft_collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_cookie = nft_voter_test.bench.with_wallet().await; + + let mut voter_weight_record_cookie = nft_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let nft1_cookie = nft_voter_test + .token_metadata + .with_nft_v2( + &nft_collection_cookie, + &voter_cookie, + Some(CreateNftArgs { + amount: 0, + ..Default::default() + }), + ) + .await?; + + // Act + let err = nft_voter_test + .update_voter_weight_record( + ®istrar_cookie, + &mut voter_weight_record_cookie, + VoterWeightAction::CreateProposal, + &[&nft1_cookie], + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); + + Ok(()) +} From ebd28e287c04217ed7222d137c1e38205445fca9 Mon Sep 17 00:00:00 2001 From: Tony Boyle <81017245+tonyboylehub@users.noreply.github.com> Date: Thu, 25 Jul 2024 16:10:16 +0100 Subject: [PATCH 02/18] added anchor flag to crate import --- Cargo.lock | 1 + programs/core-voter/Cargo.toml | 2 +- programs/core-voter/src/instructions/configure_collection.rs | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97b34a10..29b90511 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2530,6 +2530,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d4f516cd9daae872182a50850ab6d5588667e71152d49b0729a32830036b83" dependencies = [ + "anchor-lang", "base64 0.22.1", "borsh 0.10.3", "modular-bitfield", diff --git a/programs/core-voter/Cargo.toml b/programs/core-voter/Cargo.toml index cd09dbfd..cdbc86f0 100644 --- a/programs/core-voter/Cargo.toml +++ b/programs/core-voter/Cargo.toml @@ -23,7 +23,7 @@ anchor-lang = { version = "0.30.1", features = ["init-if-needed"] } anchor-spl = { version = "0.30.1", features = ["token"] } itertools = "0.10.2" mpl-token-metadata = "^4.1.2" -mpl-core = "0.7.1" +mpl-core = {version = "0.7.1", features = ["anchor"]} solana-program = "1.18.18" spl-governance = { version = "4.0", features = ["no-entrypoint"] } spl-governance-tools = "0.1.4" diff --git a/programs/core-voter/src/instructions/configure_collection.rs b/programs/core-voter/src/instructions/configure_collection.rs index c217718f..86cda54e 100644 --- a/programs/core-voter/src/instructions/configure_collection.rs +++ b/programs/core-voter/src/instructions/configure_collection.rs @@ -5,7 +5,7 @@ use anchor_lang::{ }; use anchor_lang::prelude::*; -use anchor_spl::token::Mint; +use mpl_core::accounts::BaseCollectionV1; use spl_governance::state::realm; use crate::error::NftVoterError; @@ -32,7 +32,7 @@ pub struct ConfigureCollection<'info> { pub realm_authority: Signer<'info>, // Collection which is going to be used for voting - pub collection: Account<'info, Mint>, + pub collection: Account<'info, BaseCollectionV1>, #[account( mut, From 65290089dc7624c21ac46631685749b9ac849c65 Mon Sep 17 00:00:00 2001 From: Tony Boyle Date: Sun, 28 Jul 2024 22:40:13 +0100 Subject: [PATCH 03/18] tony/start-core-migration --- programs/core-voter/src/error.rs | 3 ++ .../src/instructions/cast_nft_vote.rs | 29 +++++++------- .../update_voter_weight_record.rs | 8 ++-- .../core-voter/src/state/nft_vote_record.rs | 38 +++++++++---------- programs/core-voter/src/state/registrar.rs | 34 ++++++++--------- 5 files changed, 57 insertions(+), 55 deletions(-) diff --git a/programs/core-voter/src/error.rs b/programs/core-voter/src/error.rs index ab01160e..ca3f3b24 100644 --- a/programs/core-voter/src/error.rs +++ b/programs/core-voter/src/error.rs @@ -73,4 +73,7 @@ pub enum NftVoterError { #[msg("VoterWeightRecord must be expired")] VoterWeightRecordMustBeExpired, + + #[msg("Invalid NFT collection")] + InvalidNftCollection, } diff --git a/programs/core-voter/src/instructions/cast_nft_vote.rs b/programs/core-voter/src/instructions/cast_nft_vote.rs index c869deb7..f7566f62 100644 --- a/programs/core-voter/src/instructions/cast_nft_vote.rs +++ b/programs/core-voter/src/instructions/cast_nft_vote.rs @@ -3,6 +3,7 @@ use crate::{id, state::*}; use anchor_lang::prelude::*; use anchor_lang::Accounts; use itertools::Itertools; +use mpl_core::accounts::BaseAssetV1; use spl_governance_tools::account::create_and_serialize_account_signed; /// Casts NFT vote. The NFTs used for voting are tracked using NftVoteRecord accounts @@ -67,28 +68,28 @@ pub fn cast_nft_vote<'a, 'b, 'c, 'info>( let mut voter_weight = 0u64; // Ensure all voting nfts in the batch are unique - let mut unique_nft_mints = vec![]; + let mut unique_asset_mints = vec![]; let rent = Rent::get()?; - for (nft_info, nft_metadata_info, nft_vote_record_info) in + for (asset, asset_vote_record_info) in ctx.remaining_accounts.iter().tuples() { - let (nft_vote_weight, nft_mint) = resolve_nft_vote_weight_and_mint( + let (asset_vote_weight, asset_mint) = resolve_nft_vote_weight_and_mint( registrar, &governing_token_owner, - nft_info, - nft_metadata_info, - &mut unique_nft_mints, + asset.key.clone(), + &BaseAssetV1::from_bytes(&asset.data.borrow()).unwrap(), + &mut unique_asset_mints, )?; - voter_weight = voter_weight.checked_add(nft_vote_weight as u64).unwrap(); + voter_weight = voter_weight.checked_add(asset_vote_weight as u64).unwrap(); // Create NFT vote record to ensure the same NFT hasn't been already used for voting // Note: The correct PDA of the NftVoteRecord is validated in create_and_serialize_account_signed // It ensures the NftVoteRecord is for ('nft-vote-record',proposal,nft_mint) seeds require!( - nft_vote_record_info.data_is_empty(), + asset_vote_record_info.data_is_empty(), NftVoterError::NftAlreadyVoted ); @@ -98,10 +99,10 @@ pub fn cast_nft_vote<'a, 'b, 'c, 'info>( // Note: Once the NFT plugin is enabled the governing_token_mint is used only as identity // for the voting population and the tokens of that mint are no longer used - let nft_vote_record = NftVoteRecord { - account_discriminator: NftVoteRecord::ACCOUNT_DISCRIMINATOR, + let asset_vote_record = AssetVoteRecord { + account_discriminator: AssetVoteRecord::ACCOUNT_DISCRIMINATOR, proposal, - nft_mint, + asset_mint, governing_token_owner, reserved: [0; 8], }; @@ -110,9 +111,9 @@ pub fn cast_nft_vote<'a, 'b, 'c, 'info>( // and we have to take it on the manual drive create_and_serialize_account_signed( &ctx.accounts.payer.to_account_info(), - nft_vote_record_info, - &nft_vote_record, - &get_nft_vote_record_seeds(&proposal, &nft_mint), + asset_vote_record_info, + &asset_vote_record, + &get_nft_vote_record_seeds(&proposal, &asset_mint), &id(), &ctx.accounts.system_program.to_account_info(), &rent, diff --git a/programs/core-voter/src/instructions/update_voter_weight_record.rs b/programs/core-voter/src/instructions/update_voter_weight_record.rs index 43145e2a..36158063 100644 --- a/programs/core-voter/src/instructions/update_voter_weight_record.rs +++ b/programs/core-voter/src/instructions/update_voter_weight_record.rs @@ -1,7 +1,7 @@ use crate::error::NftVoterError; use crate::state::*; use anchor_lang::prelude::*; -use itertools::Itertools; +use mpl_core::accounts::BaseAssetV1; /// Updates VoterWeightRecord to evaluate governance power for non voting use cases: CreateProposal, CreateGovernance etc... /// This instruction updates VoterWeightRecord which is valid for the current Slot and the given target action only @@ -49,12 +49,12 @@ pub fn update_voter_weight_record( // Ensure all nfts are unique let mut unique_nft_mints = vec![]; - for (nft_info, nft_metadata_info) in ctx.remaining_accounts.iter().tuples() { + for asset in ctx.remaining_accounts.iter() { let (nft_vote_weight, _) = resolve_nft_vote_weight_and_mint( registrar, governing_token_owner, - nft_info, - nft_metadata_info, + asset.key.clone(), + &BaseAssetV1::from_bytes(&asset.data.borrow()).unwrap(), &mut unique_nft_mints, )?; diff --git a/programs/core-voter/src/state/nft_vote_record.rs b/programs/core-voter/src/state/nft_vote_record.rs index 25fcf101..95742fd4 100644 --- a/programs/core-voter/src/state/nft_vote_record.rs +++ b/programs/core-voter/src/state/nft_vote_record.rs @@ -7,12 +7,12 @@ use spl_governance_tools::account::{get_account_data, AccountMaxSize}; use crate::{error::NftVoterError, id}; /// Vote record indicating the given NFT voted on the Proposal -/// The PDA of the record is ["nft-vote-record",proposal,nft_mint] +/// The PDA of the record is ["nft-vote-record",proposal,asset_mint] /// It guarantees uniques and ensures the same NFT can't vote twice #[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub struct NftVoteRecord { - /// NftVoteRecord discriminator sha256("account:NftVoteRecord")[..8] - /// Note: The discriminator is used explicitly because NftVoteRecords +pub struct AssetVoteRecord { + /// AssetVoteRecord discriminator sha256("account:AssetVoteRecord")[..8] + /// Note: The discriminator is used explicitly because AssetVoteRecords /// are created and consumed dynamically using remaining_accounts /// and Anchor doesn't really support this scenario without going through lots of hoops /// Once Anchor has better support for the scenario it shouldn't be necessary @@ -22,7 +22,7 @@ pub struct NftVoteRecord { pub proposal: Pubkey, /// The mint of the NFT which was used for the vote - pub nft_mint: Pubkey, + pub asset_mint: Pubkey, /// The voter who casted this vote /// It's a Realm member pubkey corresponding to TokenOwnerRecord.governing_token_owner @@ -32,32 +32,32 @@ pub struct NftVoteRecord { pub reserved: [u8; 8], } -impl NftVoteRecord { - /// sha256("account:NftVoteRecord")[..8] +impl AssetVoteRecord { + /// sha256("account:AssetVoteRecord")[..8] pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [137, 6, 55, 139, 251, 126, 254, 99]; } -impl AccountMaxSize for NftVoteRecord {} +impl AccountMaxSize for AssetVoteRecord {} -impl IsInitialized for NftVoteRecord { +impl IsInitialized for AssetVoteRecord { fn is_initialized(&self) -> bool { - self.account_discriminator == NftVoteRecord::ACCOUNT_DISCRIMINATOR + self.account_discriminator == AssetVoteRecord::ACCOUNT_DISCRIMINATOR } } -/// Returns NftVoteRecord PDA seeds -pub fn get_nft_vote_record_seeds<'a>(proposal: &'a Pubkey, nft_mint: &'a Pubkey) -> [&'a [u8]; 3] { - [b"nft-vote-record", proposal.as_ref(), nft_mint.as_ref()] +/// Returns AssetVoteRecord PDA seeds +pub fn get_nft_vote_record_seeds<'a>(proposal: &'a Pubkey, asset_mint: &'a Pubkey) -> [&'a [u8]; 3] { + [b"nft-vote-record", proposal.as_ref(), asset_mint.as_ref()] } -/// Returns NftVoteRecord PDA address -pub fn get_nft_vote_record_address(proposal: &Pubkey, nft_mint: &Pubkey) -> Pubkey { - Pubkey::find_program_address(&get_nft_vote_record_seeds(proposal, nft_mint), &id()).0 +/// Returns AssetVoteRecord PDA address +pub fn get_nft_vote_record_address(proposal: &Pubkey, asset_mint: &Pubkey) -> Pubkey { + Pubkey::find_program_address(&get_nft_vote_record_seeds(proposal, asset_mint), &id()).0 } /// Deserializes account and checks owner program -pub fn get_nft_vote_record_data(nft_vote_record_info: &AccountInfo) -> Result { - Ok(get_account_data::( +pub fn get_nft_vote_record_data(nft_vote_record_info: &AccountInfo) -> Result { + Ok(get_account_data::( &id(), nft_vote_record_info, )?) @@ -67,7 +67,7 @@ pub fn get_nft_vote_record_data_for_proposal_and_token_owner( nft_vote_record_info: &AccountInfo, proposal: &Pubkey, governing_token_owner: &Pubkey, -) -> Result { +) -> Result { let nft_vote_record = get_nft_vote_record_data(nft_vote_record_info)?; require!( diff --git a/programs/core-voter/src/state/registrar.rs b/programs/core-voter/src/state/registrar.rs index a6479c57..e29cdc29 100644 --- a/programs/core-voter/src/state/registrar.rs +++ b/programs/core-voter/src/state/registrar.rs @@ -8,6 +8,7 @@ use crate::{ }, }; use anchor_lang::prelude::*; +use mpl_core::{accounts::BaseAssetV1, types::UpdateAuthority}; use solana_program::pubkey::PUBKEY_BYTES; use spl_governance::state::token_owner_record; use spl_governance::tools::spl_token::{get_spl_token_mint, get_spl_token_owner}; @@ -28,7 +29,7 @@ pub struct Registrar { /// and the actual token of the mint is not used pub governing_token_mint: Pubkey, - /// MPL Collection used for voting + /// Core Collection used for voting pub collection_configs: Vec, /// Reserved for future upgrades @@ -101,11 +102,12 @@ pub fn resolve_governing_token_owner( pub fn resolve_nft_vote_weight_and_mint( registrar: &Registrar, governing_token_owner: &Pubkey, - nft_info: &AccountInfo, - nft_metadata_info: &AccountInfo, + asset_key: Pubkey, + asset: &BaseAssetV1, + // nft_metadata_info: &AccountInfo, unique_nft_mints: &mut Vec, ) -> Result<(u64, Pubkey)> { - let nft_owner = get_spl_token_owner(nft_info)?; + let nft_owner = asset.owner; // voter_weight_record.governing_token_owner must be the owner of the NFT require!( @@ -113,7 +115,7 @@ pub fn resolve_nft_vote_weight_and_mint( NftVoterError::VoterDoesNotOwnNft ); - let nft_mint = get_spl_token_mint(nft_info)?; + let nft_mint = asset_key; // Ensure the same NFT was not provided more than once if unique_nft_mints.contains(&nft_mint) { @@ -121,21 +123,17 @@ pub fn resolve_nft_vote_weight_and_mint( } unique_nft_mints.push(nft_mint); - // Ensure the token amount is exactly 1 - let nft_amount = get_spl_token_amount(nft_info)?; + // The Core NFT must have a collection and the collection must be verified + let collection = match asset.update_authority { + UpdateAuthority::Collection(collection) => { + collection + }, + _ => return Err(NftVoterError::InvalidNftCollection.into()) + }; - require!(nft_amount == 1, NftVoterError::InvalidNftAmount); + let collection_config = registrar.get_collection_config(collection)?; - let nft_metadata = get_token_metadata_for_mint(nft_metadata_info, &nft_mint)?; - - // The NFT must have a collection and the collection must be verified - let collection = nft_metadata - .collection - .ok_or(NftVoterError::MissingMetadataCollection)?; - - require!(collection.verified, NftVoterError::CollectionMustBeVerified); - - let collection_config = registrar.get_collection_config(collection.key)?; + assert!(collection_config.collection == collection, NftVoterError::InvalidNftCollection); Ok((collection_config.weight, nft_mint)) } From c2628a6a9c316899bcdc5dbf215425671ff7cd1c Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:02:08 +0200 Subject: [PATCH 04/18] Changed how to get size for the collection since now we have that data directly in the Collection account and doesn't need to be an input. --- .../src/instructions/configure_collection.rs | 7 ++-- programs/core-voter/src/lib.rs | 3 +- programs/core-voter/src/state/registrar.rs | 6 +--- programs/core-voter/src/tools/mod.rs | 2 -- programs/core-voter/src/tools/spl_token.rs | 15 --------- .../core-voter/src/tools/token_metadata.rs | 32 ------------------- 6 files changed, 6 insertions(+), 59 deletions(-) delete mode 100644 programs/core-voter/src/tools/spl_token.rs delete mode 100644 programs/core-voter/src/tools/token_metadata.rs diff --git a/programs/core-voter/src/instructions/configure_collection.rs b/programs/core-voter/src/instructions/configure_collection.rs index 86cda54e..8c2e3ef6 100644 --- a/programs/core-voter/src/instructions/configure_collection.rs +++ b/programs/core-voter/src/instructions/configure_collection.rs @@ -48,10 +48,7 @@ pub struct ConfigureCollection<'info> { pub fn configure_collection( ctx: Context, weight: u64, - size: u32, ) -> Result<()> { - require!(size > 0, NftVoterError::InvalidCollectionSize); - let registrar = &mut ctx.accounts.registrar; let realm = realm::get_realm_data_for_governing_token_mint( @@ -74,6 +71,10 @@ pub fn configure_collection( // } let collection = &ctx.accounts.collection; + + let size = collection.current_size; + + require!(size > 0, NftVoterError::InvalidCollectionSize); let collection_config = CollectionConfig { collection: collection.key(), diff --git a/programs/core-voter/src/lib.rs b/programs/core-voter/src/lib.rs index fcd118fe..74544789 100644 --- a/programs/core-voter/src/lib.rs +++ b/programs/core-voter/src/lib.rs @@ -48,10 +48,9 @@ pub mod nft_voter { pub fn configure_collection( ctx: Context, weight: u64, - size: u32, ) -> Result<()> { log_version(); - instructions::configure_collection(ctx, weight, size) + instructions::configure_collection(ctx, weight) } pub fn cast_nft_vote<'a, 'b, 'c, 'info>( diff --git a/programs/core-voter/src/state/registrar.rs b/programs/core-voter/src/state/registrar.rs index e29cdc29..b77f933d 100644 --- a/programs/core-voter/src/state/registrar.rs +++ b/programs/core-voter/src/state/registrar.rs @@ -2,16 +2,12 @@ use crate::{ error::NftVoterError, id, state::{CollectionConfig, VoterWeightRecord}, - tools::{ - anchor::DISCRIMINATOR_SIZE, spl_token::get_spl_token_amount, - token_metadata::get_token_metadata_for_mint, - }, + tools::anchor::DISCRIMINATOR_SIZE, }; use anchor_lang::prelude::*; use mpl_core::{accounts::BaseAssetV1, types::UpdateAuthority}; use solana_program::pubkey::PUBKEY_BYTES; use spl_governance::state::token_owner_record; -use spl_governance::tools::spl_token::{get_spl_token_mint, get_spl_token_owner}; /// Registrar which stores NFT voting configuration for the given Realm #[account] diff --git a/programs/core-voter/src/tools/mod.rs b/programs/core-voter/src/tools/mod.rs index 13516dbb..aecc39e5 100644 --- a/programs/core-voter/src/tools/mod.rs +++ b/programs/core-voter/src/tools/mod.rs @@ -1,4 +1,2 @@ pub mod anchor; pub mod governance; -pub mod spl_token; -pub mod token_metadata; diff --git a/programs/core-voter/src/tools/spl_token.rs b/programs/core-voter/src/tools/spl_token.rs deleted file mode 100644 index 49a97d5b..00000000 --- a/programs/core-voter/src/tools/spl_token.rs +++ /dev/null @@ -1,15 +0,0 @@ -use anchor_lang::prelude::*; -use arrayref::array_ref; -use spl_governance::tools::spl_token::assert_is_valid_spl_token_account; - -/// Computationally cheap method to get amount from a token account -/// It reads amount without deserializing full account data -pub fn get_spl_token_amount(token_account_info: &AccountInfo) -> Result { - assert_is_valid_spl_token_account(token_account_info)?; - - // TokeAccount layout: mint(32), owner(32), amount(8), ... - let data = token_account_info.try_borrow_data()?; - let amount_bytes = array_ref![data, 64, 8]; - - Ok(u64::from_le_bytes(*amount_bytes)) -} diff --git a/programs/core-voter/src/tools/token_metadata.rs b/programs/core-voter/src/tools/token_metadata.rs deleted file mode 100644 index 8ac1007b..00000000 --- a/programs/core-voter/src/tools/token_metadata.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::convert::TryFrom; - -use anchor_lang::prelude::*; -use mpl_token_metadata::accounts::Metadata; - -use crate::error::NftVoterError; - -pub fn get_token_metadata(account_info: &AccountInfo) -> Result { - if *account_info.owner != mpl_token_metadata::ID { - return Err(NftVoterError::InvalidAccountOwner.into()); - } - - let metadata = Metadata::try_from(account_info)?; - - // I'm not sure if this is needed but try_from_slice_checked in from_account_info - // ignores Key::Uninitialized and hence checking for the exact Key match here - if metadata.key != mpl_token_metadata::types::Key::MetadataV1 { - return Err(NftVoterError::InvalidTokenMetadataAccount.into()); - } - - Ok(metadata) -} - -pub fn get_token_metadata_for_mint(account_info: &AccountInfo, mint: &Pubkey) -> Result { - let token_metadata = get_token_metadata(account_info)?; - - if token_metadata.mint != *mint { - return Err(NftVoterError::TokenMetadataDoesNotMatch.into()); - } - - Ok(token_metadata) -} From 01a4ac82172cf67adaf7f335061c95e934e79651 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Mon, 29 Jul 2024 13:11:23 +0200 Subject: [PATCH 05/18] Started refactoring tests --- programs/core-voter/src/lib.rs | 2 +- programs/core-voter/tests/cast_nft_vote.rs | 647 ++++++++---------- .../tests/program_test/core_test.rs | 134 ++++ .../{nft_voter_test.rs => core_voter_test.rs} | 89 ++- programs/core-voter/tests/program_test/mod.rs | 4 +- .../tests/program_test/token_metadata_test.rs | 253 ------- 6 files changed, 451 insertions(+), 678 deletions(-) create mode 100644 programs/core-voter/tests/program_test/core_test.rs rename programs/core-voter/tests/program_test/{nft_voter_test.rs => core_voter_test.rs} (88%) delete mode 100644 programs/core-voter/tests/program_test/token_metadata_test.rs diff --git a/programs/core-voter/src/lib.rs b/programs/core-voter/src/lib.rs index 74544789..4d2b9871 100644 --- a/programs/core-voter/src/lib.rs +++ b/programs/core-voter/src/lib.rs @@ -14,7 +14,7 @@ use crate::state::*; declare_id!("GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw"); #[program] -pub mod nft_voter { +pub mod core_voter { use crate::state::VoterWeightAction; diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 97e3934e..3e98ac96 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -1,9 +1,8 @@ -use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use crate::program_test::core_voter_test::ConfigureCollectionArgs; use gpl_nft_voter::error::NftVoterError; use gpl_nft_voter::state::*; -use program_test::token_metadata_test::CreateNftArgs; use program_test::{ - nft_voter_test::*, + core_voter_test::*, tools::{assert_gov_err, assert_nft_voter_err}, }; @@ -16,22 +15,22 @@ mod program_test; #[tokio::test] async fn test_cast_nft_vote() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -40,32 +39,32 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; // Act - let nft_vote_record_cookies = nft_voter_test + let asset_vote_record_cookies = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -73,19 +72,19 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Assert - let nft_vote_record = nft_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + let asset_vote_record = core_voter_test + .get_nft_vote_record_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record); + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -106,22 +105,22 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { #[tokio::test] async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -130,37 +129,37 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_cookie2 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; // Act - let nft_vote_record_cookies = nft_voter_test + let nft_vote_record_cookies = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -174,19 +173,19 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { .await?; // Assert - let nft_vote_record1 = nft_voter_test + let nft_vote_record1 = core_voter_test .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) .await; assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); - let nft_vote_record2 = nft_voter_test + let nft_vote_record2 = core_voter_test .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) .await; assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -207,49 +206,49 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { #[tokio::test] async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test + core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -262,11 +261,11 @@ async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), Transpo ) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -290,53 +289,53 @@ async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), Transpo #[tokio::test] async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_cookie2 = core_voter_test.bench.with_wallet().await; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -360,22 +359,22 @@ async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportEr #[tokio::test] async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -384,37 +383,30 @@ async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), Tra ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; // Create NFT without verified collection - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - verify_collection: false, - ..Default::default() - }), - ) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, None) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -438,22 +430,22 @@ async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), Tra #[tokio::test] async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -462,31 +454,31 @@ async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportEr ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_cookie2 = core_voter_test.bench.with_wallet().await; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie2, None) + let nft_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -510,22 +502,22 @@ async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportEr #[tokio::test] async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie: program_test::governance_test::RealmCookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -534,31 +526,31 @@ async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), Transp ) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; - let nft_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie2, &voter_cookie, None) + let nft_cookie = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -579,138 +571,53 @@ async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), Transp Ok(()) } -#[tokio::test] -async fn test_cast_nft_vote_with_invalid_metadata_error() -> Result<(), TransportError> { - // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; - - let realm_cookie = nft_voter_test.governance.with_realm().await?; - - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; - - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; - - let max_voter_weight_record_cookie = nft_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - nft_voter_test - .with_collection( - ®istrar_cookie, - &nft_collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let proposal_cookie = nft_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let voter_cookie = nft_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = nft_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = nft_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let mut nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - verify_collection: false, - ..Default::default() - }), - ) - .await?; - - let nft2_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) - .await?; - - // Try to use verified NFT Metadata - nft1_cookie.metadata = nft2_cookie.metadata; - - // Act - let err = nft_voter_test - .cast_nft_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&nft1_cookie], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::TokenMetadataDoesNotMatch); - - Ok(()) -} - #[tokio::test] async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -735,22 +642,22 @@ async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> #[tokio::test] async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -759,36 +666,24 @@ async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - amount: 0, - ..Default::default() - }), - ) - .await?; - // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -796,7 +691,7 @@ async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[], None, ) .await @@ -812,22 +707,22 @@ async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { #[tokio::test] async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -836,18 +731,18 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; @@ -855,20 +750,20 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { let mut nft_cookies = vec![]; for _ in 0..5 { - nft_voter_test.bench.advance_clock().await; - let nft_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + core_voter_test.bench.advance_clock().await; + let nft_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; nft_cookies.push(nft_cookie) } - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; // Act - let nft_vote_record_cookies = nft_voter_test + let nft_vote_record_cookies = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -882,19 +777,19 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { .await?; // Assert - let nft_vote_record1 = nft_voter_test + let nft_vote_record1 = core_voter_test .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) .await; assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); - let nft_vote_record2 = nft_voter_test + let nft_vote_record2 = core_voter_test .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) .await; assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -915,22 +810,22 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { #[tokio::test] async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -939,35 +834,35 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; - let args = CastNftVoteArgs { + let args = CastAssetVoteArgs { cast_spl_gov_vote: false, }; - nft_voter_test + core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -980,14 +875,14 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor ) .await?; - let nft_cookie2 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - nft_voter_test + core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1002,7 +897,7 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -1024,22 +919,22 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -1048,32 +943,32 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let args = CastNftVoteArgs { + let args = CastAssetVoteArgs { cast_spl_gov_vote: false, }; - nft_voter_test + core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1088,7 +983,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1113,22 +1008,22 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -1137,33 +1032,33 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let args = CastNftVoteArgs { + let args = CastAssetVoteArgs { cast_spl_gov_vote: false, }; // Cast vote with NFT - let nft_vote_record_cookies = nft_voter_test + let nft_vote_record_cookies = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1176,10 +1071,10 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche ) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Try relinquish NftVoteRecords to accumulate vote - nft_voter_test + core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1192,7 +1087,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche // Act - nft_voter_test + core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1207,7 +1102,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -1219,52 +1114,52 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche #[tokio::test] async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; - let delegate_cookie = nft_voter_test.bench.with_wallet().await; - nft_voter_test + let delegate_cookie = core_voter_test.bench.with_wallet().await; + core_voter_test .governance .set_governance_delegate( &realm_cookie, @@ -1275,7 +1170,7 @@ async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { .await; // Act - let nft_vote_record_cookies = nft_voter_test + let nft_vote_record_cookies = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, @@ -1289,7 +1184,7 @@ async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { .await?; // Assert - let nft_vote_record = nft_voter_test + let nft_vote_record = core_voter_test .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) .await; @@ -1302,53 +1197,53 @@ async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { async fn test_cast_nft_vote_with_invalid_voter_weight_token_owner_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; // Try to update VoterWeightRecord for different governing_token_owner - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; - let voter_weight_record_cookie2 = nft_voter_test + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + let voter_weight_record_cookie2 = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie2) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let nft_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .cast_nft_vote( ®istrar_cookie, &voter_weight_record_cookie2, diff --git a/programs/core-voter/tests/program_test/core_test.rs b/programs/core-voter/tests/program_test/core_test.rs new file mode 100644 index 00000000..13ca914d --- /dev/null +++ b/programs/core-voter/tests/program_test/core_test.rs @@ -0,0 +1,134 @@ +use std::{str::FromStr, sync::Arc}; + +use anchor_lang::prelude::Pubkey; +use solana_program_test::ProgramTest; +use solana_sdk::{signer::Signer, system_program, transport::TransportError, signature::Keypair}; + +use crate::program_test::program_test_bench::{ProgramTestBench, WalletCookie}; + +pub struct AssetCookie { + pub asset: Pubkey, +} + +pub struct CollectionCookie { + pub collection: Pubkey, + pub authority: Keypair, +} + +pub struct CoreTest { + pub bench: Arc, + pub program_id: Pubkey, +} + +impl CoreTest { + pub fn program_id() -> Pubkey { + Pubkey::from_str("CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d").unwrap() + } + + #[allow(dead_code)] + pub fn add_program(program_test: &mut ProgramTest) { + program_test.add_program("mpl_core", Self::program_id(), None); + } + + #[allow(dead_code)] + pub fn new(bench: Arc) -> Self { + CoreTest { + bench, + program_id: Self::program_id(), + } + } + + #[allow(dead_code)] + pub async fn with_collection(&self) -> Result { + let payer = self.bench.context.borrow().payer.pubkey(); + + // Create collection + let coll_keypair = Keypair::new(); + let coll_authority = Keypair::new(); + + let coll_name = "NFT_C".to_string(); + let coll_uri = "URI".to_string(); + + // instruction args + let args = mpl_core::instructions::CreateCollectionV2InstructionArgs { + name: coll_name, + uri: coll_uri, + plugins: None, + external_plugin_adapters: None, + }; + + // instruction accounts + let create_coll_ix_accounts = mpl_core::instructions::CreateCollectionV2 { + collection: coll_keypair.pubkey(), + update_authority: Some(coll_authority.pubkey()), + payer, + system_program: system_program::ID, + }; + + // creates the instruction + let create_coll_ix = create_coll_ix_accounts.instruction(args); + + self.bench + .process_transaction( + &[create_coll_ix], + Some(&[&coll_keypair, &coll_authority]), + ) + .await?; + + Ok(CollectionCookie { + collection: coll_keypair.pubkey(), + authority: coll_authority, + }) + } + + #[allow(dead_code)] + pub async fn with_asset( + &self, + collection_cookie: &CollectionCookie, + asset_owner_cookie: &WalletCookie, + collection: Option + ) -> Result { + let payer = self.bench.context.borrow().payer.pubkey(); + + // Create Asset + let asset_keypair = Keypair::new(); + + let name = "TestAsset".to_string(); + let uri = "URI".to_string(); + + // instruction args + let args = mpl_core::instructions::CreateV2InstructionArgs { + data_state: mpl_core::types::DataState::AccountState, + name, + uri, + plugins: None, + external_plugin_adapters: None, + }; + + // instruction accounts + let create_accounts = mpl_core::instructions::CreateV2 { + asset: asset_keypair.pubkey(), + collection, + authority: Some(collection_cookie.authority.pubkey()), + payer, + owner: Some(asset_owner_cookie.address), + update_authority: None, + system_program: system_program::ID, + log_wrapper: None + }; + + // creates the instruction + let create_ix = create_accounts.instruction(args); + + self.bench + .process_transaction( + &[create_ix], + Some(&[&asset_keypair, &collection_cookie.authority]), + ) + .await?; + + Ok(AssetCookie { + asset: asset_keypair.pubkey(), + }) + } +} diff --git a/programs/core-voter/tests/program_test/nft_voter_test.rs b/programs/core-voter/tests/program_test/core_voter_test.rs similarity index 88% rename from programs/core-voter/tests/program_test/nft_voter_test.rs rename to programs/core-voter/tests/program_test/core_voter_test.rs index 309bdf71..54d0183b 100644 --- a/programs/core-voter/tests/program_test/nft_voter_test.rs +++ b/programs/core-voter/tests/program_test/core_voter_test.rs @@ -11,7 +11,7 @@ use spl_governance::instruction::cast_vote; use spl_governance::state::vote_record::{self, Vote, VoteChoice}; use gpl_nft_voter::state::{ - get_nft_vote_record_address, get_registrar_address, CollectionConfig, NftVoteRecord, Registrar, + get_nft_vote_record_address, get_registrar_address, CollectionConfig, AssetVoteRecord, Registrar, }; use solana_program_test::{BanksClientError, ProgramTest}; @@ -24,7 +24,7 @@ use crate::program_test::program_test_bench::ProgramTestBench; use crate::program_test::governance_test::{ProposalCookie, RealmCookie, TokenOwnerRecordCookie}; use crate::program_test::program_test_bench::WalletCookie; -use crate::program_test::token_metadata_test::{NftCollectionCookie, NftCookie, TokenMetadataTest}; +use crate::program_test::core_test::{CollectionCookie, AssetCookie, CoreTest}; use crate::program_test::tools::NopOverride; #[derive(Debug, PartialEq)] @@ -62,16 +62,16 @@ impl Default for ConfigureCollectionArgs { } #[derive(Debug, PartialEq)] -pub struct NftVoteRecordCookie { +pub struct AssetVoteRecordCookie { pub address: Pubkey, - pub account: NftVoteRecord, + pub account: AssetVoteRecord, } -pub struct CastNftVoteArgs { +pub struct CastAssetVoteArgs { pub cast_spl_gov_vote: bool, } -impl Default for CastNftVoteArgs { +impl Default for CastAssetVoteArgs { fn default() -> Self { Self { cast_spl_gov_vote: true, @@ -79,26 +79,26 @@ impl Default for CastNftVoteArgs { } } -pub struct NftVoterTest { +pub struct CoreVoterTest { pub program_id: Pubkey, pub bench: Arc, pub governance: GovernanceTest, - pub token_metadata: TokenMetadataTest, + pub core: CoreTest, } -impl NftVoterTest { +impl CoreVoterTest { #[allow(dead_code)] pub fn add_program(program_test: &mut ProgramTest) { - program_test.add_program("gpl_nft_voter", gpl_nft_voter::id(), None); + program_test.add_program("gpl_core_voter", gpl_nft_voter::id(), None); } #[allow(dead_code)] pub async fn start_new() -> Self { let mut program_test = ProgramTest::default(); - NftVoterTest::add_program(&mut program_test); + CoreVoterTest::add_program(&mut program_test); GovernanceTest::add_program(&mut program_test); - TokenMetadataTest::add_program(&mut program_test); + CoreTest::add_program(&mut program_test); let program_id = gpl_nft_voter::id(); @@ -107,13 +107,13 @@ impl NftVoterTest { let governance_bench = GovernanceTest::new(bench_rc.clone(), Some(program_id), Some(program_id)); - let token_metadata_bench = TokenMetadataTest::new(bench_rc.clone()); + let core_bench = CoreTest::new(bench_rc.clone()); Self { program_id, bench: bench_rc, governance: governance_bench, - token_metadata: token_metadata_bench, + core: core_bench, } } @@ -325,7 +325,7 @@ impl NftVoterTest { registrar_cookie: &RegistrarCookie, voter_weight_record_cookie: &mut VoterWeightRecordCookie, voter_weight_action: VoterWeightAction, - nft_cookies: &[&NftCookie], + asset_cookies: &[&AssetCookie], ) -> Result<(), BanksClientError> { let data = anchor_lang::InstructionData::data( &gpl_nft_voter::instruction::UpdateVoterWeightRecord { @@ -340,9 +340,8 @@ impl NftVoterTest { let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); - for nft_cookie in nft_cookies { - account_metas.push(AccountMeta::new_readonly(nft_cookie.address, false)); - account_metas.push(AccountMeta::new_readonly(nft_cookie.metadata, false)); + for asset_cookie in asset_cookies { + account_metas.push(AccountMeta::new_readonly(asset_cookie.asset, false)); } let instructions = vec![Instruction { @@ -362,7 +361,7 @@ impl NftVoterTest { proposal_cookie: &ProposalCookie, voter_cookie: &WalletCookie, voter_token_owner_record_cookie: &TokenOwnerRecordCookie, - nft_vote_record_cookies: &Vec, + asset_vote_record_cookies: &Vec, ) -> Result<(), BanksClientError> { let data = anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::RelinquishNftVote {}); @@ -386,8 +385,8 @@ impl NftVoterTest { let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); - for nft_vote_record_cookie in nft_vote_record_cookies { - account_metas.push(AccountMeta::new(nft_vote_record_cookie.address, false)); + for asset_vote_record_cookie in asset_vote_record_cookies { + account_metas.push(AccountMeta::new(asset_vote_record_cookie.address, false)); } let relinquish_nft_vote_ix = Instruction { @@ -407,7 +406,7 @@ impl NftVoterTest { pub async fn with_collection( &mut self, registrar_cookie: &RegistrarCookie, - nft_collection_cookie: &NftCollectionCookie, + nft_collection_cookie: &CollectionCookie, max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, args: Option, ) -> Result { @@ -426,7 +425,7 @@ impl NftVoterTest { pub async fn with_collection_using_ix( &mut self, registrar_cookie: &RegistrarCookie, - nft_collection_cookie: &NftCollectionCookie, + collection_cookie: &CollectionCookie, max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, args: Option, instruction_override: F, @@ -437,14 +436,13 @@ impl NftVoterTest { let data = anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::ConfigureCollection { weight: args.weight, - size: args.size, }); let accounts = gpl_nft_voter::accounts::ConfigureCollection { registrar: registrar_cookie.address, realm: registrar_cookie.account.realm, realm_authority: registrar_cookie.realm_authority.pubkey(), - collection: nft_collection_cookie.mint, + collection: collection_cookie.collection, max_voter_weight_record: max_voter_weight_record_cookie.address, }; @@ -464,7 +462,7 @@ impl NftVoterTest { .await?; let collection_config = CollectionConfig { - collection: nft_collection_cookie.mint, + collection: collection_cookie.collection, size: args.size, weight: args.weight, reserved: [0; 8], @@ -481,11 +479,11 @@ impl NftVoterTest { voter_weight_record_cookie: &VoterWeightRecordCookie, max_voter_weight_record_cookie: &MaxVoterWeightRecordCookie, proposal_cookie: &ProposalCookie, - nft_voter_cookie: &WalletCookie, + asset_voter_cookie: &WalletCookie, voter_token_owner_record_cookie: &TokenOwnerRecordCookie, - nft_cookies: &[&NftCookie], - args: Option, - ) -> Result, BanksClientError> { + asset_cookies: &[&AssetCookie], + args: Option, + ) -> Result, BanksClientError> { let args = args.unwrap_or_default(); let data = anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::CastNftVote { @@ -496,34 +494,33 @@ impl NftVoterTest { registrar: registrar_cookie.address, voter_weight_record: voter_weight_record_cookie.address, voter_token_owner_record: voter_token_owner_record_cookie.address, - voter_authority: nft_voter_cookie.address, + voter_authority: asset_voter_cookie.address, payer: self.bench.payer.pubkey(), system_program: solana_sdk::system_program::id(), }; let mut account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); - let mut nft_vote_record_cookies = vec![]; + let mut asset_vote_record_cookies = vec![]; - for nft_cookie in nft_cookies { - account_metas.push(AccountMeta::new_readonly(nft_cookie.address, false)); - account_metas.push(AccountMeta::new_readonly(nft_cookie.metadata, false)); + for asset_cookie in asset_cookies { + account_metas.push(AccountMeta::new_readonly(asset_cookie.asset, false)); let nft_vote_record_key = get_nft_vote_record_address( &proposal_cookie.address, - &nft_cookie.mint_cookie.address, + &asset_cookie.asset, ); account_metas.push(AccountMeta::new(nft_vote_record_key, false)); - let account = NftVoteRecord { + let account = AssetVoteRecord { proposal: proposal_cookie.address, - nft_mint: nft_cookie.mint_cookie.address, + asset_mint: asset_cookie.asset, governing_token_owner: voter_weight_record_cookie.account.governing_token_owner, - account_discriminator: NftVoteRecord::ACCOUNT_DISCRIMINATOR, + account_discriminator: AssetVoteRecord::ACCOUNT_DISCRIMINATOR, reserved: [0; 8], }; - nft_vote_record_cookies.push(NftVoteRecordCookie { - address: nft_vote_record_key, + asset_vote_record_cookies.push(AssetVoteRecordCookie { + address: asset_voter_cookie.address, account, }) } @@ -550,7 +547,7 @@ impl NftVoterTest { &proposal_cookie.address, &proposal_cookie.account.token_owner_record, &voter_token_owner_record_cookie.address, - &nft_voter_cookie.address, + &asset_voter_cookie.address, &proposal_cookie.account.governing_token_mint, &self.bench.payer.pubkey(), Some(voter_weight_record_cookie.address), @@ -562,10 +559,10 @@ impl NftVoterTest { } self.bench - .process_transaction(&instruction, Some(&[&nft_voter_cookie.signer])) + .process_transaction(&instruction, Some(&[&asset_voter_cookie.signer])) .await?; - Ok(nft_vote_record_cookies) + Ok(asset_vote_record_cookies) } #[allow(dead_code)] @@ -574,9 +571,9 @@ impl NftVoterTest { } #[allow(dead_code)] - pub async fn get_nft_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> NftVoteRecord { + pub async fn get_nft_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> AssetVoteRecord { self.bench - .get_borsh_account::(nft_vote_record) + .get_borsh_account::(nft_vote_record) .await } diff --git a/programs/core-voter/tests/program_test/mod.rs b/programs/core-voter/tests/program_test/mod.rs index 60cbb5dd..bfe26678 100644 --- a/programs/core-voter/tests/program_test/mod.rs +++ b/programs/core-voter/tests/program_test/mod.rs @@ -1,5 +1,5 @@ pub mod governance_test; -pub mod nft_voter_test; +pub mod core_voter_test; pub mod program_test_bench; -pub mod token_metadata_test; +pub mod core_test; pub mod tools; diff --git a/programs/core-voter/tests/program_test/token_metadata_test.rs b/programs/core-voter/tests/program_test/token_metadata_test.rs deleted file mode 100644 index 08c94ea8..00000000 --- a/programs/core-voter/tests/program_test/token_metadata_test.rs +++ /dev/null @@ -1,253 +0,0 @@ -use std::{str::FromStr, sync::Arc}; - -use anchor_lang::prelude::Pubkey; -use mpl_token_metadata::{types::Collection, types::DataV2}; -use solana_program_test::ProgramTest; -use solana_sdk::{signer::Signer, system_program, transport::TransportError}; - -use crate::program_test::program_test_bench::{MintCookie, ProgramTestBench, WalletCookie}; - -pub struct NftCookie { - pub address: Pubkey, - pub metadata: Pubkey, - pub mint_cookie: MintCookie, -} - -pub struct NftCollectionCookie { - pub mint: Pubkey, - pub metadata: Pubkey, - pub master_edition: Pubkey, -} - -pub struct CreateNftArgs { - pub verify_collection: bool, - pub amount: u64, -} - -impl Default for CreateNftArgs { - fn default() -> Self { - Self { - verify_collection: true, - amount: 1, - } - } -} - -pub struct TokenMetadataTest { - pub bench: Arc, - pub program_id: Pubkey, -} - -impl TokenMetadataTest { - pub fn program_id() -> Pubkey { - Pubkey::from_str("metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s").unwrap() - } - - #[allow(dead_code)] - pub fn add_program(program_test: &mut ProgramTest) { - program_test.add_program("mpl_token_metadata", Self::program_id(), None); - } - - #[allow(dead_code)] - pub fn new(bench: Arc) -> Self { - TokenMetadataTest { - bench, - program_id: Self::program_id(), - } - } - - #[allow(dead_code)] - pub async fn with_nft_collection(&self) -> Result { - let update_authority = self.bench.context.borrow().payer.pubkey(); - let payer = self.bench.context.borrow().payer.pubkey(); - - // Create collection - let coll_mint_cookie = self.bench.with_mint().await?; - self.bench - .with_tokens(&coll_mint_cookie, &update_authority, 1) - .await?; - - let coll_metadata_seeds = &[ - b"metadata".as_ref(), - self.program_id.as_ref(), - &coll_mint_cookie.address.as_ref(), - ]; - let (coll_metadata_key, _) = - Pubkey::find_program_address(coll_metadata_seeds, &self.program_id); - - let coll_name = "NFT_C".to_string(); - let coll_symbol = "NFT_C".to_string(); - let coll_uri = "URI".to_string(); - - // instruction args - let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { - data: DataV2 { - name: coll_name, - symbol: coll_symbol, - uri: coll_uri, - seller_fee_basis_points: 10, - creators: None, - collection: None, - uses: None, - }, - is_mutable: true, - collection_details: None, - }; - - // instruction accounts - let create_coll_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { - metadata: coll_metadata_key, - mint: coll_mint_cookie.address, - mint_authority: coll_mint_cookie.mint_authority.pubkey(), - payer: payer, - update_authority: (payer, true), - system_program: system_program::ID, - rent: None, - }; - - // creates the instruction - let create_coll_metadata_ix = create_coll_metadata_ix_accounts.instruction(args); - - self.bench - .process_transaction( - &[create_coll_metadata_ix], - Some(&[&coll_mint_cookie.mint_authority]), - ) - .await?; - - let master_edition_seeds = &[ - b"metadata".as_ref(), - self.program_id.as_ref(), - coll_mint_cookie.address.as_ref(), - b"edition".as_ref(), - ]; - let (master_edition_key, _) = - Pubkey::find_program_address(master_edition_seeds, &self.program_id); - - - // instruction args - let args_master_edition_v3 = mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { - max_supply: Some(0), - }; - - // instruction accounts - let create_master_edition_v3_ix_accounts = mpl_token_metadata::instructions::CreateMasterEditionV3 { - edition: master_edition_key, - metadata: coll_metadata_key, - mint: coll_mint_cookie.address, - mint_authority: coll_mint_cookie.mint_authority.pubkey(), - payer: payer, - update_authority: payer, - system_program: system_program::ID, - token_program: spl_token::id(), - rent: None, - }; - - let create_master_edition_ix = create_master_edition_v3_ix_accounts.instruction(args_master_edition_v3); - - self.bench - .process_transaction( - &[create_master_edition_ix], - Some(&[&coll_mint_cookie.mint_authority]), - ) - .await?; - - Ok(NftCollectionCookie { - mint: coll_mint_cookie.address, - metadata: coll_metadata_key, - master_edition: master_edition_key, - }) - } - - #[allow(dead_code)] - pub async fn with_nft_v2( - &self, - nft_collection_cookie: &NftCollectionCookie, - nft_owner_cookie: &WalletCookie, - args: Option, - ) -> Result { - let CreateNftArgs { - verify_collection, - amount, - } = args.unwrap_or_default(); - - // Crate NFT - let mint_cookie = self.bench.with_mint().await?; - let nft_account_cookie = self - .bench - .with_tokens(&mint_cookie, &nft_owner_cookie.address, amount) - .await?; - - let metadata_seeds = &[ - b"metadata".as_ref(), - self.program_id.as_ref(), - &mint_cookie.address.as_ref(), - ]; - let (metadata_key, _) = Pubkey::find_program_address(metadata_seeds, &self.program_id); - - let name = "TestNFT".to_string(); - let symbol = "NFT".to_string(); - let uri = "URI".to_string(); - - let collection = Collection { - verified: false, - key: nft_collection_cookie.mint, - }; - - // instruction args - let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { - data: DataV2 { - name: name, - symbol: symbol, - uri: uri, - seller_fee_basis_points: 10, - creators: None, - collection: Some(collection), - uses: None, - }, - is_mutable: true, - collection_details: None, - }; - - // instruction accounts - let create_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { - metadata: metadata_key, - mint: mint_cookie.address, - mint_authority: mint_cookie.mint_authority.pubkey(), - payer: self.bench.payer.pubkey(), - update_authority: (self.bench.payer.pubkey(), true), - system_program: system_program::ID, - rent: None, - }; - - // creates the instruction - let create_metadata_ix = create_metadata_ix_accounts.instruction(args); - - self.bench - .process_transaction(&[create_metadata_ix], Some(&[&mint_cookie.mint_authority])) - .await?; - - if verify_collection { - let verify_collection_accounts = mpl_token_metadata::instructions::VerifyCollection { - metadata: metadata_key, - collection_authority: self.bench.payer.pubkey(), - payer: self.bench.payer.pubkey(), - collection_mint: nft_collection_cookie.mint, - collection: nft_collection_cookie.metadata, - collection_master_edition_account: nft_collection_cookie.master_edition, - collection_authority_record: None, - }; - let verify_collection = verify_collection_accounts.instruction(); - - self.bench - .process_transaction(&[verify_collection], None) - .await?; - } - - Ok(NftCookie { - address: nft_account_cookie.address, - metadata: metadata_key, - mint_cookie, - }) - } -} From f53301aba15cbfcb01a6475b10ddc04acbe82ff7 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:32:01 +0200 Subject: [PATCH 06/18] Finished updating Tests. Need to run them to see if i'm missing anything --- programs/core-voter/tests/cast_nft_vote.rs | 179 +++++----- .../core-voter/tests/configure_collection.rs | 164 ++++----- .../tests/create_max_voter_weight_record.rs | 46 +-- programs/core-voter/tests/create_registrar.rs | 44 +-- .../tests/create_voter_weight_record.rs | 52 +-- .../tests/program_test/core_voter_test.rs | 4 +- .../core-voter/tests/relinquish_nft_vote.rs | 314 ++++++++-------- .../tests/update_voter_weight_record.rs | 336 +++++++----------- 8 files changed, 524 insertions(+), 615 deletions(-) diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 3e98ac96..d2031408 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -13,7 +13,7 @@ use spl_governance::error::GovernanceError; mod program_test; #[tokio::test] -async fn test_cast_nft_vote() -> Result<(), TransportError> { +async fn test_cast_asset_vote() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -65,7 +65,7 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { // Act let asset_vote_record_cookies = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, @@ -79,7 +79,7 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { // Assert let asset_vote_record = core_voter_test - .get_nft_vote_record_account(&asset_vote_record_cookies[0].address) + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) .await; assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); @@ -103,7 +103,7 @@ async fn test_cast_nft_vote() -> Result<(), TransportError> { } #[tokio::test] -async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -145,12 +145,12 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_cookie2 = core_voter_test + let asset_cookie2 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -159,31 +159,31 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { let clock = core_voter_test.bench.get_clock().await; // Act - let nft_vote_record_cookies = core_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1, &nft_cookie2], + &[&asset_cookie1, &asset_cookie2], None, ) .await?; // Assert - let nft_vote_record1 = core_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + let asset_vote_record1 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - let nft_vote_record2 = core_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) + let asset_vote_record2 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) .await; - assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); + assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) @@ -204,7 +204,7 @@ async fn test_cast_nft_vote_with_multiple_nfts() -> Result<(), TransportError> { } #[tokio::test] -async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -243,20 +243,20 @@ async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), Transpo .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; @@ -264,16 +264,15 @@ async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), Transpo core_voter_test.bench.advance_clock().await; // Act - let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await @@ -287,7 +286,7 @@ async fn test_cast_nft_vote_with_nft_already_voted_error() -> Result<(), Transpo } #[tokio::test] -async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -326,7 +325,7 @@ async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportEr .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -336,14 +335,14 @@ async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportEr // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie2, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await @@ -357,7 +356,7 @@ async fn test_cast_nft_vote_with_invalid_voter_error() -> Result<(), TransportEr } #[tokio::test] -async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -400,21 +399,21 @@ async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), Tra .await?; // Create NFT without verified collection - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, None) .await?; // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await @@ -428,7 +427,7 @@ async fn test_cast_nft_vote_with_unverified_collection_error() -> Result<(), Tra } #[tokio::test] -async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -472,21 +471,21 @@ async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportEr .with_proposal(&realm_cookie) .await?; - let nft_cookie = core_voter_test + let asset_cookie = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) .await?; // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie], + &[&asset_cookie], None, ) .await @@ -500,7 +499,7 @@ async fn test_cast_nft_vote_with_invalid_owner_error() -> Result<(), TransportEr } #[tokio::test] -async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -544,21 +543,21 @@ async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), Transp let collection_cookie2 = core_voter_test.core.with_collection().await?; - let nft_cookie = core_voter_test + let asset_cookie = core_voter_test .core .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) .await?; // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie], + &[&asset_cookie], None, ) .await @@ -572,7 +571,7 @@ async fn test_cast_nft_vote_with_invalid_collection_error() -> Result<(), Transp } #[tokio::test] -async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -611,21 +610,21 @@ async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_cookie = core_voter_test + let asset_cookie = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie, &nft_cookie], + &[&asset_cookie, &asset_cookie], None, ) .await @@ -640,7 +639,7 @@ async fn test_cast_nft_vote_with_same_nft_error() -> Result<(), TransportError> } #[tokio::test] -async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -684,7 +683,7 @@ async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, @@ -705,7 +704,7 @@ async fn test_cast_nft_vote_with_no_nft_error() -> Result<(), TransportError> { } #[tokio::test] -async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { +async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -747,47 +746,47 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { .with_proposal(&realm_cookie) .await?; - let mut nft_cookies = vec![]; + let mut asset_cookies = vec![]; for _ in 0..5 { core_voter_test.bench.advance_clock().await; - let nft_cookie = core_voter_test + let asset_cookie = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_cookies.push(nft_cookie) + asset_cookies.push(asset_cookie) } core_voter_test.bench.advance_clock().await; let clock = core_voter_test.bench.get_clock().await; // Act - let nft_vote_record_cookies = core_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_cookies.iter().collect::>(), + &asset_cookies.iter().collect::>(), None, ) .await?; // Assert - let nft_vote_record1 = core_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + let asset_vote_record1 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record1); + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - let nft_vote_record2 = core_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[1].address) + let asset_vote_record2 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) .await; - assert_eq!(nft_vote_record_cookies[1].account, nft_vote_record2); + assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) @@ -808,7 +807,7 @@ async fn test_cast_nft_vote_with_max_5_nfts() -> Result<(), TransportError> { } #[tokio::test] -async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), TransportError> { +async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -850,7 +849,7 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -863,19 +862,19 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor }; core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], Some(args), ) .await?; - let nft_cookie2 = core_voter_test + let asset_cookie2 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -883,14 +882,14 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor // Act core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie2], + &[&asset_cookie2], None, ) .await?; @@ -916,7 +915,7 @@ async fn test_cast_nft_vote_using_multiple_instructions() -> Result<(), Transpor } #[tokio::test] -async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_error( +async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted_error( ) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -959,7 +958,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -969,14 +968,14 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e }; core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], Some(args), ) .await?; @@ -984,14 +983,14 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await @@ -1005,7 +1004,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_nft_already_voted_e } #[tokio::test] -async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( +async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( ) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -1048,7 +1047,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -1058,15 +1057,15 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche }; // Cast vote with NFT - let nft_vote_record_cookies = core_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], Some(args), ) .await?; @@ -1081,21 +1080,21 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await?; // Act core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; @@ -1112,7 +1111,7 @@ async fn test_cast_nft_vote_using_multiple_instructions_with_attempted_sandwiche } #[tokio::test] -async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { +async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -1151,7 +1150,7 @@ async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -1170,31 +1169,31 @@ async fn test_cast_nft_vote_using_delegate() -> Result<(), TransportError> { .await; // Act - let nft_vote_record_cookies = core_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &delegate_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Assert - let nft_vote_record = core_voter_test - .get_nft_vote_record_account(&nft_vote_record_cookies[0].address) + let asset_vote_record = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(nft_vote_record_cookies[0].account, nft_vote_record); + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); Ok(()) } #[tokio::test] -async fn test_cast_nft_vote_with_invalid_voter_weight_token_owner_error( +async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error( ) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -1236,7 +1235,7 @@ async fn test_cast_nft_vote_with_invalid_voter_weight_token_owner_error( .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = core_voter_test + let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; @@ -1244,14 +1243,14 @@ async fn test_cast_nft_vote_with_invalid_voter_weight_token_owner_error( // Act let err = core_voter_test - .cast_nft_vote( + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie2, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index 4d83f5e3..653328ec 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -1,43 +1,43 @@ use gpl_nft_voter::error::NftVoterError; use program_test::{ - nft_voter_test::NftVoterTest, + core_voter_test::CoreVoterTest, tools::{assert_anchor_err, assert_nft_voter_err}, }; use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; -use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use crate::program_test::core_voter_test::ConfigureCollectionArgs; mod program_test; #[tokio::test] async fn test_configure_collection() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Act - let collection_config_cookie = nft_voter_test + let collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; // Assert - let registrar = nft_voter_test + let registrar = core_voter_test .get_registrar_account(®istrar_cookie.address) .await; @@ -48,7 +48,7 @@ async fn test_configure_collection() -> Result<(), TransportError> { collection_config_cookie.collection_config ); - let max_voter_weight_record = nft_voter_test + let max_voter_weight_record = core_voter_test .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) .await; @@ -65,33 +65,33 @@ async fn test_configure_collection() -> Result<(), TransportError> { #[tokio::test] async fn test_configure_multiple_collections() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie1 = nft_voter_test.token_metadata.with_nft_collection().await?; - let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie1 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Act - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie1, + &collection_cookie1, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 1, size: 5 }), ) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie2, + &collection_cookie2, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 2, @@ -101,13 +101,13 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { .await?; // Assert - let registrar = nft_voter_test + let registrar = core_voter_test .get_registrar_account(®istrar_cookie.address) .await; assert_eq!(registrar.collection_configs.len(), 2); - let max_voter_weight_record = nft_voter_test + let max_voter_weight_record = core_voter_test .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) .await; @@ -120,25 +120,25 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { #[tokio::test] async fn test_configure_max_collections() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Act for _ in 0..registrar_cookie.max_collections { - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) @@ -146,7 +146,7 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { } // Assert - let registrar = nft_voter_test + let registrar = core_voter_test .get_registrar_account(®istrar_cookie.address) .await; @@ -155,7 +155,7 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { registrar_cookie.max_collections ); - let max_voter_weight_record = nft_voter_test + let max_voter_weight_record = core_voter_test .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) .await; @@ -168,22 +168,22 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { #[tokio::test] async fn test_configure_existing_collection() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) @@ -191,10 +191,10 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { // Act - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 2, @@ -204,13 +204,13 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { .await?; // Assert - let registrar = nft_voter_test + let registrar = core_voter_test .get_registrar_account(®istrar_cookie.address) .await; assert_eq!(registrar.collection_configs.len(), 1); - let max_voter_weight_record = nft_voter_test + let max_voter_weight_record = core_voter_test .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) .await; @@ -225,26 +225,26 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { #[tokio::test] async fn test_configure_collection_with_invalid_realm_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Try to use a different Realm - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_collection_using_ix( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, |i| i.accounts[1].pubkey = realm_cookie2.address, // realm @@ -265,23 +265,23 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran async fn test_configure_collection_with_realm_authority_must_sign_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_collection_using_ix( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, |i| i.accounts[2].is_signer = false, // realm_authority @@ -302,25 +302,25 @@ async fn test_configure_collection_with_realm_authority_must_sign_error( async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; let realm_authority = Keypair::new(); // Act - let err = nft_voter_test + let err = core_voter_test .with_collection_using_ix( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, |i| i.accounts[2].pubkey = realm_authority.pubkey(), // realm_authority @@ -341,25 +341,25 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; - let registrar_cookie2 = nft_voter_test.with_registrar(&realm_cookie2).await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; + let registrar_cookie2 = core_voter_test.with_registrar(&realm_cookie2).await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie2) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) @@ -378,26 +378,26 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( async fn test_configure_collection_with_invalid_max_voter_weight_mint_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; // Create Registrar for council mint realm_cookie.account.community_mint = realm_cookie.account.config.council_mint.unwrap(); - let registrar_cookie2 = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie2 = core_voter_test.with_registrar(&realm_cookie).await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie2) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) diff --git a/programs/core-voter/tests/create_max_voter_weight_record.rs b/programs/core-voter/tests/create_max_voter_weight_record.rs index a69f0462..d6bb2dcf 100644 --- a/programs/core-voter/tests/create_max_voter_weight_record.rs +++ b/programs/core-voter/tests/create_max_voter_weight_record.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::ErrorCode; use program_test::{ - nft_voter_test::NftVoterTest, + core_voter_test::CoreVoterTest, tools::{assert_anchor_err, assert_ix_err}, }; use solana_program::instruction::InstructionError; @@ -12,20 +12,20 @@ mod program_test; #[tokio::test] async fn test_create_max_voter_weight_record() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; // Act - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; // Assert - - let max_voter_weight_record = nft_voter_test + + let max_voter_weight_record = core_voter_test .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) .await; @@ -41,16 +41,16 @@ async fn test_create_max_voter_weight_record() -> Result<(), TransportError> { async fn test_create_max_voter_weight_record_with_invalid_realm_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_max_voter_weight_record_using_ix(®istrar_cookie, |i| { i.accounts[2].pubkey = realm_cookie2.address // Realm }) @@ -70,16 +70,16 @@ async fn test_create_max_voter_weight_record_with_invalid_realm_error() -> Resul async fn test_create_max_voter_weight_record_with_invalid_mint_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_max_voter_weight_record_using_ix(®istrar_cookie, |i| { i.accounts[2].pubkey = realm_cookie2.address // Mint }) @@ -99,20 +99,20 @@ async fn test_create_max_voter_weight_record_with_invalid_mint_error() -> Result async fn test_create_max_voter_weight_record_with_already_exists_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - nft_voter_test + core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Act - let err = nft_voter_test + let err = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await .err() diff --git a/programs/core-voter/tests/create_registrar.rs b/programs/core-voter/tests/create_registrar.rs index 07561195..dde04925 100644 --- a/programs/core-voter/tests/create_registrar.rs +++ b/programs/core-voter/tests/create_registrar.rs @@ -2,7 +2,7 @@ mod program_test; use anchor_lang::prelude::{ErrorCode, Pubkey}; use gpl_nft_voter::error::NftVoterError; -use program_test::nft_voter_test::NftVoterTest; +use program_test::core_voter_test::CoreVoterTest; use solana_program_test::*; use solana_sdk::{signature::Keypair, transport::TransportError}; @@ -12,15 +12,15 @@ use program_test::tools::{assert_anchor_err, assert_nft_voter_err}; #[tokio::test] async fn test_create_registrar() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; // Act - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; // Assert - let registrar = nft_voter_test + let registrar = core_voter_test .get_registrar_account(®istrar_cookie.address) .await; @@ -32,13 +32,13 @@ async fn test_create_registrar() -> Result<(), TransportError> { #[tokio::test] async fn test_create_registrar_with_invalid_realm_authority_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; realm_cookie.realm_authority = Keypair::new(); // Act - let err = nft_voter_test + let err = core_voter_test .with_registrar(&realm_cookie) .await .err() @@ -53,13 +53,13 @@ async fn test_create_registrar_with_invalid_realm_authority_error() -> Result<() async fn test_create_registrar_with_realm_authority_must_sign_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; realm_cookie.realm_authority = Keypair::new(); // Act - let err = nft_voter_test + let err = core_voter_test .with_registrar_using_ix( &realm_cookie, |i| i.accounts[4].is_signer = false, // realm_authority @@ -78,16 +78,16 @@ async fn test_create_registrar_with_realm_authority_must_sign_error() -> Result< async fn test_create_registrar_with_invalid_spl_gov_program_id_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; realm_cookie.realm_authority = Keypair::new(); // Try to use a different program id - let governance_program_id = nft_voter_test.program_id; + let governance_program_id = core_voter_test.program_id; // Act - let err = nft_voter_test + let err = core_voter_test .with_registrar_using_ix( &realm_cookie, |i| i.accounts[1].pubkey = governance_program_id, //governance_program_id @@ -105,13 +105,13 @@ async fn test_create_registrar_with_invalid_spl_gov_program_id_error() -> Result #[tokio::test] async fn test_create_registrar_with_invalid_realm_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; realm_cookie.realm_authority = Keypair::new(); // Act - let err = nft_voter_test + let err = core_voter_test .with_registrar_using_ix( &realm_cookie, |i| i.accounts[2].pubkey = Pubkey::new_unique(), // realm @@ -131,15 +131,15 @@ async fn test_create_registrar_with_invalid_realm_error() -> Result<(), Transpor async fn test_create_registrar_with_invalid_governing_token_mint_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let mut realm_cookie = nft_voter_test.governance.with_realm().await?; + let mut realm_cookie = core_voter_test.governance.with_realm().await?; realm_cookie.realm_authority = Keypair::new(); - let mint_cookie = nft_voter_test.bench.with_mint().await?; + let mint_cookie = core_voter_test.bench.with_mint().await?; // Act - let err = nft_voter_test + let err = core_voter_test .with_registrar_using_ix( &realm_cookie, |i| i.accounts[3].pubkey = mint_cookie.address, // governing_token_mint diff --git a/programs/core-voter/tests/create_voter_weight_record.rs b/programs/core-voter/tests/create_voter_weight_record.rs index 761b2f49..6a6c75db 100644 --- a/programs/core-voter/tests/create_voter_weight_record.rs +++ b/programs/core-voter/tests/create_voter_weight_record.rs @@ -1,5 +1,5 @@ use anchor_lang::prelude::ErrorCode; -use program_test::nft_voter_test::NftVoterTest; +use program_test::core_voter_test::CoreVoterTest; use program_test::tools::{assert_anchor_err, assert_ix_err}; use solana_program::instruction::InstructionError; use solana_program_test::*; @@ -10,22 +10,22 @@ mod program_test; #[tokio::test] async fn test_create_voter_weight_record() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; // Act - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -37,18 +37,18 @@ async fn test_create_voter_weight_record() -> Result<(), TransportError> { #[tokio::test] async fn test_create_voter_weight_record_with_invalid_realm_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; // Act - let err = nft_voter_test + let err = core_voter_test .with_voter_weight_record_using_ix(®istrar_cookie, &voter_cookie, |i| { i.accounts[2].pubkey = realm_cookie2.address // Realm }) @@ -67,18 +67,18 @@ async fn test_create_voter_weight_record_with_invalid_realm_error() -> Result<() #[tokio::test] async fn test_create_voter_weight_record_with_invalid_mint_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let realm_cookie2 = nft_voter_test.governance.with_realm().await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; // Act - let err = nft_voter_test + let err = core_voter_test .with_voter_weight_record_using_ix(®istrar_cookie, &voter_cookie, |i| { i.accounts[2].pubkey = realm_cookie2.address // Mint }) @@ -97,22 +97,22 @@ async fn test_create_voter_weight_record_with_invalid_mint_error() -> Result<(), #[tokio::test] async fn test_create_voter_weight_record_with_already_exists_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - nft_voter_test + core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Act - let err = nft_voter_test + let err = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await .err() diff --git a/programs/core-voter/tests/program_test/core_voter_test.rs b/programs/core-voter/tests/program_test/core_voter_test.rs index 54d0183b..c9160715 100644 --- a/programs/core-voter/tests/program_test/core_voter_test.rs +++ b/programs/core-voter/tests/program_test/core_voter_test.rs @@ -473,7 +473,7 @@ impl CoreVoterTest { /// Casts NFT Vote and spl-gov Vote #[allow(dead_code)] - pub async fn cast_nft_vote( + pub async fn cast_asset_vote( &mut self, registrar_cookie: &RegistrarCookie, voter_weight_record_cookie: &VoterWeightRecordCookie, @@ -571,7 +571,7 @@ impl CoreVoterTest { } #[allow(dead_code)] - pub async fn get_nft_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> AssetVoteRecord { + pub async fn get_asset_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> AssetVoteRecord { self.bench .get_borsh_account::(nft_vote_record) .await diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 4f6005c1..8c815bae 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -1,6 +1,6 @@ -use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use crate::program_test::core_voter_test::ConfigureCollectionArgs; use gpl_nft_voter::error::NftVoterError; -use program_test::nft_voter_test::{CastNftVoteArgs, NftVoterTest}; +use program_test::core_voter_test::{CastAssetVoteArgs, CoreVoterTest}; use program_test::tools::{assert_gov_err, assert_nft_voter_err}; use solana_program_test::*; use solana_sdk::transport::TransportError; @@ -11,79 +11,79 @@ mod program_test; #[tokio::test] async fn test_relinquish_nft_vote() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Act - nft_voter_test + core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -91,12 +91,12 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { assert_eq!(voter_weight_record.voter_weight, 0); // Check NftVoteRecord was disposed - let nft_vote_record = nft_voter_test + let asset_vote_record = core_voter_test .bench - .get_account(&nft_vote_record_cookies[0].address) + .get_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(None, nft_vote_record); + assert_eq!(None, asset_vote_record); Ok(()) } @@ -104,63 +104,63 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { #[tokio::test] async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Relinquish Vote from spl-gov - nft_voter_test + core_voter_test .governance .relinquish_vote( &proposal_cookie, @@ -169,24 +169,24 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T ) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Act - nft_voter_test + core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -194,12 +194,12 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T assert_eq!(voter_weight_record.voter_weight, 0); // Check NftVoteRecord was disposed - let nft_vote_record = nft_voter_test + let asset_vote_record = core_voter_test .bench - .get_account(&nft_vote_record_cookies[0].address) + .get_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(None, nft_vote_record); + assert_eq!(None, asset_vote_record); Ok(()) } @@ -208,71 +208,71 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await .err() @@ -287,74 +287,74 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e #[tokio::test] async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Try to use a different voter - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_cookie2 = core_voter_test.bench.with_wallet().await; // Act - let err = nft_voter_test + let err = core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &voter_cookie2, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await .err() @@ -371,22 +371,22 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -395,55 +395,55 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let args = CastNftVoteArgs { + let args = CastAssetVoteArgs { cast_spl_gov_vote: false, }; // Cast vote with NFT - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], Some(args), ) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await .err() @@ -460,77 +460,77 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( ) -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; // Try to update VoterWeightRecord for different governing_token_owner - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; - let voter_weight_record_cookie2 = nft_voter_test + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + let voter_weight_record_cookie2 = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie2) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie2, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await .err() @@ -546,66 +546,66 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( #[tokio::test] async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = nft_voter_test + let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) .await?; - let voter_weight_record_cookie = nft_voter_test + let voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let proposal_cookie = nft_voter_test + let proposal_cookie = core_voter_test .governance .with_proposal(&realm_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_vote_record_cookies = nft_voter_test - .cast_nft_vote( + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( ®istrar_cookie, &voter_weight_record_cookie, &max_voter_weight_record_cookie, &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&nft_cookie1], + &[&asset_cookie1], None, ) .await?; - nft_voter_test.bench.advance_clock().await; + core_voter_test.bench.advance_clock().await; // Setup delegate - let delegate_cookie = nft_voter_test.bench.with_wallet().await; - nft_voter_test + let delegate_cookie = core_voter_test.bench.with_wallet().await; + core_voter_test .governance .set_governance_delegate( &realm_cookie, @@ -617,20 +617,20 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> // Act - nft_voter_test + core_voter_test .relinquish_nft_vote( ®istrar_cookie, &voter_weight_record_cookie, &proposal_cookie, &delegate_cookie, &voter_token_owner_record_cookie, - &nft_vote_record_cookies, + &asset_vote_record_cookies, ) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -638,12 +638,12 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> assert_eq!(voter_weight_record.voter_weight, 0); // Check NftVoteRecord was disposed - let nft_vote_record = nft_voter_test + let asset_vote_record = core_voter_test .bench - .get_account(&nft_vote_record_cookies[0].address) + .get_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(None, nft_vote_record); + assert_eq!(None, asset_vote_record); Ok(()) } diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index d29809a2..8af9a37c 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -1,8 +1,7 @@ -use crate::program_test::nft_voter_test::ConfigureCollectionArgs; +use crate::program_test::core_voter_test::ConfigureCollectionArgs; use gpl_nft_voter::error::NftVoterError; use gpl_nft_voter::state::*; -use program_test::nft_voter_test::NftVoterTest; -use program_test::token_metadata_test::CreateNftArgs; +use program_test::core_voter_test::CoreVoterTest; use program_test::tools::*; use solana_program_test::*; use solana_sdk::transport::TransportError; @@ -12,22 +11,22 @@ mod program_test; #[tokio::test] async fn test_update_voter_weight_record() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - let _collection_config_cookie = nft_voter_test + let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -36,38 +35,39 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; // Act - nft_voter_test + core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateProposal, - &[&nft1_cookie], + &[&asset_cookie1], ) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; assert_eq!(voter_weight_record.voter_weight, 10); assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( voter_weight_record.weight_action, Some(VoterWeightAction::CreateProposal.into()) @@ -80,22 +80,22 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { #[tokio::test] async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - let _collection_config_cookie = nft_voter_test + let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -104,38 +104,38 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_cookie1 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - let nft_cookie2 = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - nft_voter_test.bench.advance_clock().await; - let clock = nft_voter_test.bench.get_clock().await; + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; // Act - nft_voter_test + core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateProposal, - &[&nft_cookie1, &nft_cookie2], + &[&asset_cookie1, &asset_cookie2], ) .await?; // Assert - let voter_weight_record = nft_voter_test + let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -153,22 +153,22 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr #[tokio::test] async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -177,24 +177,24 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CastVote, - &[&nft1_cookie], + &[&asset_cookie1], ) .await .err() @@ -209,22 +209,22 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( #[tokio::test] async fn test_update_voter_weight_with_unverified_collection_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -233,32 +233,25 @@ async fn test_update_voter_weight_with_unverified_collection_error() -> Result<( ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; // Create NFT without verified collection - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - verify_collection: false, - ..Default::default() - }), - ) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, None) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateGovernance, - &[&nft1_cookie], + &[&asset_cookie1], ) .await .err() @@ -273,22 +266,22 @@ async fn test_update_voter_weight_with_unverified_collection_error() -> Result<( #[tokio::test] async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -297,26 +290,26 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let voter_cookie2 = nft_voter_test.bench.with_wallet().await; + let voter_cookie2 = core_voter_test.bench.with_wallet().await; - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie2, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateGovernance, - &[&nft1_cookie], + &[&asset_cookie1], ) .await .err() @@ -331,22 +324,22 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans #[tokio::test] async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -355,26 +348,26 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_collection_cookie2 = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie2, &voter_cookie, None) + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateGovernance, - &[&nft1_cookie], + &[&asset_cookie1], ) .await .err() @@ -386,119 +379,48 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), Ok(()) } -#[tokio::test] -async fn test_update_voter_weight_with_invalid_metadata_error() -> Result<(), TransportError> { - // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; - - let realm_cookie = nft_voter_test.governance.with_realm().await?; - - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; - - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; - - let max_voter_weight_record_cookie = nft_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - nft_voter_test - .with_collection( - ®istrar_cookie, - &nft_collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = nft_voter_test.bench.with_wallet().await; - - let mut voter_weight_record_cookie = nft_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let mut nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - verify_collection: false, - ..Default::default() - }), - ) - .await?; - - let nft2_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) - .await?; - - // Try to use verified NFT Metadata - nft1_cookie.metadata = nft2_cookie.metadata; - - // Act - let err = nft_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - VoterWeightAction::CreateGovernance, - &[&nft1_cookie], - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::TokenMetadataDoesNotMatch); - - Ok(()) -} - #[tokio::test] async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - nft_voter_test + core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, None, ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft_cookie = nft_voter_test - .token_metadata - .with_nft_v2(&nft_collection_cookie, &voter_cookie, None) + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateProposal, - &[&nft_cookie, &nft_cookie], + &[&asset_cookie, &asset_cookie], ) .await .err() @@ -514,22 +436,22 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE #[tokio::test] async fn test_update_voter_weight_record_with_no_nft_error() -> Result<(), TransportError> { // Arrange - let mut nft_voter_test = NftVoterTest::start_new().await; + let mut core_voter_test = CoreVoterTest::start_new().await; - let realm_cookie = nft_voter_test.governance.with_realm().await?; + let realm_cookie = core_voter_test.governance.with_realm().await?; - let registrar_cookie = nft_voter_test.with_registrar(&realm_cookie).await?; + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let nft_collection_cookie = nft_voter_test.token_metadata.with_nft_collection().await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = nft_voter_test + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - let _collection_config_cookie = nft_voter_test + let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, - &nft_collection_cookie, + &collection_cookie, &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, @@ -538,31 +460,19 @@ async fn test_update_voter_weight_record_with_no_nft_error() -> Result<(), Trans ) .await?; - let voter_cookie = nft_voter_test.bench.with_wallet().await; + let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = nft_voter_test + let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let nft1_cookie = nft_voter_test - .token_metadata - .with_nft_v2( - &nft_collection_cookie, - &voter_cookie, - Some(CreateNftArgs { - amount: 0, - ..Default::default() - }), - ) - .await?; - // Act - let err = nft_voter_test + let err = core_voter_test .update_voter_weight_record( ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateProposal, - &[&nft1_cookie], + &[], ) .await .err() From db97e079a6ec22afc9b67840f521bcd363ac05cf Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:53:39 +0200 Subject: [PATCH 07/18] Finished all the test refactoring --- Anchor.toml | 1 + programs/core-voter/Cargo.toml | 2 +- programs/core-voter/tests/cast_nft_vote.rs | 4 +- .../core-voter/tests/configure_collection.rs | 2 +- programs/core-voter/tests/create_registrar.rs | 2 +- .../core-voter/tests/fixtures/mpl_core.so | Bin 0 -> 848320 bytes .../tests/fixtures/mpl_token_metadata.so | Bin 693904 -> 0 bytes .../tests/program_test/core_voter_test.rs | 54 +++++++++--------- .../core-voter/tests/program_test/tools.rs | 2 +- .../core-voter/tests/relinquish_nft_vote.rs | 2 +- .../tests/update_voter_weight_record.rs | 4 +- 11 files changed, 37 insertions(+), 36 deletions(-) create mode 100644 programs/core-voter/tests/fixtures/mpl_core.so delete mode 100644 programs/core-voter/tests/fixtures/mpl_token_metadata.so diff --git a/Anchor.toml b/Anchor.toml index b4fb909b..1c140a32 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -5,6 +5,7 @@ solana_version = "1.18.18" seeds = false [programs.localnet] +core-voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" nft_voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" gateway = "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk" solana-gateway-program = "gatem74V238djXdzWnJf94Wo1DcnuGkfijbf3AuBhfs" diff --git a/programs/core-voter/Cargo.toml b/programs/core-voter/Cargo.toml index cdbc86f0..29a439c4 100644 --- a/programs/core-voter/Cargo.toml +++ b/programs/core-voter/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [lib] crate-type = ["cdylib", "lib"] -name = "gpl_nft_voter" +name = "gpl_core_voter" [features] no-entrypoint = [] diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index d2031408..8c0ad98d 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -1,6 +1,6 @@ use crate::program_test::core_voter_test::ConfigureCollectionArgs; -use gpl_nft_voter::error::NftVoterError; -use gpl_nft_voter::state::*; +use gpl_core_voter::error::NftVoterError; +use gpl_core_voter::state::*; use program_test::{ core_voter_test::*, tools::{assert_gov_err, assert_nft_voter_err}, diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index 653328ec..1caf0bf1 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -1,4 +1,4 @@ -use gpl_nft_voter::error::NftVoterError; +use gpl_core_voter::error::NftVoterError; use program_test::{ core_voter_test::CoreVoterTest, tools::{assert_anchor_err, assert_nft_voter_err}, diff --git a/programs/core-voter/tests/create_registrar.rs b/programs/core-voter/tests/create_registrar.rs index dde04925..7803a3df 100644 --- a/programs/core-voter/tests/create_registrar.rs +++ b/programs/core-voter/tests/create_registrar.rs @@ -1,7 +1,7 @@ mod program_test; use anchor_lang::prelude::{ErrorCode, Pubkey}; -use gpl_nft_voter::error::NftVoterError; +use gpl_core_voter::error::NftVoterError; use program_test::core_voter_test::CoreVoterTest; use solana_program_test::*; diff --git a/programs/core-voter/tests/fixtures/mpl_core.so b/programs/core-voter/tests/fixtures/mpl_core.so new file mode 100644 index 0000000000000000000000000000000000000000..7491bb42a1a27fe8a9f5b4fdb5c96ebfac8edf08 GIT binary patch literal 848320 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

*}57HreJ@y^bxcUT=qssXU=vgo6)0ZJv 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 z z@1{OY_MyBt;R|P^uV2>NS)Q){uL<;Ncpbq3cZ00M6HfO7-XL&kNzWrRt`W2&)}0B^ zuAR6Z9@@#yA^16=bmCq?#CJsb1N$Blrd>mRG~YY@UlQN0oj!_oYMwLv1K~s3aTRc} z9wpnic(v9u;QfK{iRbV54szY(O?TJk8t+NN)SOcIX$ zAuW9=)Qfy?T&?BC^&%s@UV{sD-=1_czS?~Ui)r&d)jp+nNRp-h-3$D=oj-`>b%(@n z7I@+%1%A%i@1e0BN4`&Ga!X)=SNV?d$~mf?n$CF!`vvQLBkIp`*fnFm@u}xp(#2{) z7ETHqPHXK1rY_F zD+FO$(tEhfFLF?C%}<7S{z1EE!txnkoqmbnVLOd{zwjql4o)9M4kn5m{H-vcoP1II zW(d;k5j#omd}tF*DtO&2=@-a`FpeZl@*cC>Sc<6`bp9^3%Z2ok-G`MO~YO;`_CcB zPA%Ck3GLFqf_;D2FO)NuK>YM;9f+_n{qU}krAuf+jqW%{W}P>uZY?0sQC!62l_d%@NV~++8^`VD@X-jAJl%B4Jp5Jd%xSy z<@$L9KYyK1mu&K$Hp_Fmh8r5sZdt+4P3AkD*)DCr>Iuxn`u?-{!^$q;St|93^_z_I zw+oo?d&V@3^LF1d+qq8RaW;l7?U*fozHouW=Uu(x~ zq6GSRbLWe{yBe=={4Z%sJ$IDt(sKP=Mz+W5w@%1R)~25mx?*}npPN1H`+=0Ry|_Q- zc5Sxfpw?@T%0n5iauH+pnEBz{w+c#-gY{Z&CuEn--5cVJq7}sRok9B9&Wfa0FJ~_Dvo8Md zec}oKEBIM`fLsG!O^)VK5*_%-{=xOt+~(=o`hOJsjrzC5AGG`4`Ia3LPN(29SOM?T z$e-;Tl62Qo#EWRyrFwQE+z;^efPST8!*u2Q#)ZEk`RlsOjQ82^m2g)7w&Jz-(XzVQ z^M2mEQU8&o4;JpN4_~PG*G~VWq{s5>_T&oQCo%cScBnk!-mt*qoR0YI<{@)2R`@(5 zv-cM>>&I!wsq9{&SGwWjT^qy45ZW7d!GD4;^=kwyar=PsK*@4D&BxvKU{3|{!*te&-qOcKZE2Xsnv7If2V%7UJp6$zZ ziO@fHtNgnClkHq8c(M-|zPmJ^w=>Q^>HbYrKlcC7Z!S@I%Ju7xN4zfE1iLrbO~Kx> z^7fd#JN@MzLFDHnalpcgm-4`&((Un?FprAgO}LTkHt0um-Y;A)_`S8X z<92C(+GE{-!}qPFoV4SWat<`@xJb^Qj;Ft@Li;|S^@j^Dq00o!BAh;_6#2;ZCY+wJlmfv=N!dr>cd?4akU7v;NRwvOiWOrO^^*Ugp* z{!!<(*8lwbZ}IxsJ18&XnAettpE%SGS5D@N95?H8o7BhYt=EN|Fzyc9Jd5M6)X(e^ zw_jW8GgUtf;q_trT}nDlUsWGa{H#CYecX-L|IR0T9e?1w9Jcp2Ark(sW^Kx?l3q^U zDfH*Z?bCi|c9_$ZU%6l6N&h_J)9DH3(NiQo+pT)h&yQ!jdKDgUq%@vacQY)bF4n+p zJ{-Q^V|H5I?sfHBdgkk2(@|l#K|8;Mclwmx>24oyx3KE1#?T`Y9-KZ~^0}QoIK3j_ zU>~DVNT=7+@6oMCBq2AMAME1r-K_5j9<~qRstx)uO)~)H`9$dG!W4H&` zjSdFq_u%{;gth5!wD5Tc%eVCk_RCLq!2Yv-ldKfT_~^)IbY zbA3$fl}~5uqJ7TnRsZG%;y2gJDiZd2c7CPRbD2c9`L5mhLT~l~tw;4_m4kBfF3I5Q zWWEndJ;oBMC+Gl?ueACio5;J}C-Qdp{aKzTWuY#VP4KvUAr6En3fyt!+krsOMfNO^W%CI-@c{lKc@K8 zDLRgE9bNj-dM%&p(Ch)>`xyu`o$DM=fc~20!+VH=FYVBEL)x=~r>=M?*T^FF-C_JL z%d8*cO?W@@`$~_kJIC|nZwUNhqkD?_d$k@xFT4o$BENUooVV?;`sw{4x7Ra!-x~V@ zI*-_^aM@06@6`7X&>eZ-#@A=Fy~?l5zRTlwORYouAIBM55WXMp`)Th{cFO#pJ$v|6 zjVLE~{gA&}?-QfZ;iwryNZxb{p}fr9OJ_FOl($@0>EdZ0{-f zIA2b5KxrqBe}@YC{X!qV%gO5n??CA#dhVb!P2?uUJ28|{mP0x6c6U3noLpr2j+cG) zv~<3nI{-X6T9()odQrdU@$0Z5+u1`m zL)L21_q;ixdOK0S-H3ejDUXaNoxXm+Fx%PROJEr25N`6B8YbMYL^@N#{Yr$%_ptws zu=YEaqI9rj{rexJpU&SO@%|O`d6<9hmv(5b2WbC3mhUKD4}IeD-trv~>&K!0K0ql~ zdMog&K0g4xVh7mwRI>*Ng??}I60WOP5Y7!>HpA?I=_=2I3lC~N{QDF8J|^M1JQv&j^Qc4f9bVO^zK`JT zJvfiGKs~S~KQh2Y?`c;Q}se*Zq9E8ntT{O0?UiPqoVeeUm? zAmQeCKSlW!-syeP!pEC`Sosy+w^zGlqrKbf^}@Q$QTcM~OQE0lsU4EpJ6-AImrF&O z^w|4=Lt4MEZuy{w$=|mV&o0BWN839stKH_`QzoA&Va@YLx*!01ROl@7+28ph{yE^c zx94bl5Br5fiZ33|52NgK%IAfD;U0al{qENKl#|a2TuV9UYI-{5(~|D{)j0nk3Hjm` zQjdI#y{oua^{9U@I-8^U^Tqm(qMzU6I7z;$=UpLBjE8XdY&q%zt2i~(1{LFU>Qruq57wfx_ z{@qS~&q~tok?iuF)y;%=y9#u$T(;vU@w+CYUigg7Fc$4C1`rkvfINigh zK+DPd1t33eySBq|3$(x3yIfx1e2dy~!}}DU+m*5Y_!!FfcQaXkI)8^VzkjvhFDIu< zJoI*G2ZB1B*MB}D$&dVgrK^*J6P&-Zna@OpB)nPh^v`ttwAI4o9^vnmaBlg1|A+0* zsQBHlb)cW}e?H>LuUE|D`!;KYAN?~|6CJ{Dw(uJyoDDr<_|?wZVDH9moOz?AuTXx@ zTyNo}7QRZt^`ZaA@ZDnJS6NsE!OxdC|DA8^L4O4~HkproKA|Jqr+jYei;aS}Ri9iS z@#F*hOKX2KzS;Q2enF0UzlhttIBpyO&TOaZGao?QtU}oPtXwK(8BK5C# z3mE2mI-dLYv~qhV$j>)GUkm((Z7L5NZ9jM{`rd^N&gT1ObHskfxdi3kkkXBHDG4{< zc~m)z@lsy=zELbUf73%bQM&u>d_sLl>($?-@&maMy2Czac<)Z-WrNLEHrjWGv!RN> zW1cB=t)1~c3CHwQNYBm6H_Gonb6v>Z@y)_KY`f$u>IuTHg?`A7({{psryy#MiyH6v z;_o?b2Bh!rbDffM;^(7@_pBfO=m_HpM|tLax;FX0v_5uTAhr1v=WBv*n-o9dyvr+) zmhDsh>Us?Gc5SyEN+0!3JNqJ?$WZ`vU8Z<_|2-b>rW3!tmz_@emf(%smy*l+ycBRa zM`h(&yVyIyqtTa^^gIprza-yA`>q}K$0XbjT|?K{`ILkQ=gpRIw)05|=kv@i*!hHo zF}TCkcP7HeezU{sJJl}gpQi&S-T^T9^8|i_eHU@#ybC0p*>@B3d1qL7hr!Rc@IDKp z;o!2J`z1U$PYt*F&i^gp{&~wJy}t90Ec_Y?=eKQF|D=1>pR`qctkWspli1qi`vME! zB;ovx*Q$TCc^bl#45%5OLaj4;G4(7m?X#QB!drWKI(Ip@AUS8c$Qn6 zl8T@8E8J|$=lfh7_t}MdCX^FOXw0t)!sOSdNJm}y-IzZ;ytxe~NaZV>^&9Oef#t zc3`~M$K`0O_858|?U7EIhSEsSG@+;19&Q)(;Ctq52Y(MK@Oe=An>(KemA|?3c~JSA zJD&%oxKa7+d>oyQ!$(Gwhplbop`3i<2ulp}Xf9~NrIQzmAIlqtiz7Y{2=AfWyFsJA z8`^b`;7?1-6>q6W_?VVXlXjKyj}2RA{kvXvuP?Xz zB$?g&^Y3pq&a6m=!G&snZP=-JHiq$Rhv4m>$KH?rZtLawJnfIZ4xG=^d3a-|;u)OB z+K``69B_m7Ufk&K7V0|Bi?M!{!Zh&q^mh`yoxLB2erNlTY3WpeYO?yx&^LPtxAUyMA=O&e;-r0C_} z9Ys#=L5*tm9z{Djy7MS<@}ahJa=!41>sb~2s@_Ryq24_~{C0YI7x4J{{EHz!_d| znXN;<5bp|er2c7qSNM`q`V&v|kEM6Jj?$klY}=o7d>^fSUQE5)9qHZTyTTklPWxJO z-oo(mLioZ$xLydKh&(P|*&GDm@wLt=xx9M;vxI%>yt`Mzd3Qy8r@t|$2}cc)V!lI1JjB><^f|oy!M>>rc+!9^Oc(DT z(9WSgCEn`UYR}>Pzrba7ekbkFjje2&^3mtp;r-tk+RuId*$47CuGMfqos?$weraaq zXAM1n_im)23Q0DodXIWi?5;BvU)Yyv0ElpBY5A0gPXf@(b3VlD6QIl>>5B#%zPhU@Qyu9yE=lS{&WK8&eR9%u2U!Pi!@|j+p&%dbGeDRVV z7~~w`xDO*fgo_aDU%&Oi4}OqP@H(nDYd*F!ov#CPJ+&9%^@wLuiuY{k{M|p!^Vp*P zZZV4|yuZ(yuY5-4L%~kfVvzo<#19V<8~PC9`7Y-0ZVQ9hXAoxleFT1H`>t5elzcV2 zro^|#}Rw`Qk21RP>htfCJMVA@cV0>W`B4) zRWDTRt?e{d2=ji_(oUCXK7U_DmPU0>tBb5t>r4GZO!-RX zXW;w7=f`(%fAZxHl>cJ#|Ky0@EN?*+&Qxtk`@9}1CA6>U!_aT6okPDtn65TqvdTM{ zwEs@+^NgonFn)NwH#vUz$B&Wz-#te7-#SM4J;w;I=Sjz3-}fIQ{)dhc z{@uq2uj{enr+?cq;?Iu}UfChVhUqcF#pGotY&o=?a)?)xhzs9l`(YPmiyYSIlva4#m^$NyHdex!S5M0a+4 zMap-2Xg88m*(t`)xk_JcqK4yoGKF>v`J7*r&hM`8vS#xJq@)bRcpov#~)`dlv2((Z%^^?)4Ev7PBWzspPK zWg5@=&`}P_SJEkRVe_Y~q3N7Q5P!3NYB%}$`OGR*E2|ytc=LsaRX<#LNPN;m&iVb9 za1!MwIz=N@w+IEx`Lj zpQYC(%#wuaiJD$cPLUtOE07s()ON7_7ylkO$1i5|d1F`)vv$w4d6Ha@`=CGSc?OqX z_gmWA&aGru3pwH47q4I7AB7w)pQrxto$A-HE=RiX9;LKX5r3mw<;cGW-so0B!#gS6 zCP)5G%AATI&K9VC^6v<)JyH8jyzX!a`ozz3<@f9Ut)IJPeg72w&DWK(eVXq5FWaI0 zDBFEl=q@L}uJm_ny<8s!KG^xi*7p6DWXM+@)cm?FBlgBv?bU~NV|s1kHzohDwHwE! z5&1|6ocHgRe78!n?6*-ATt2E4bPLmO$+w!ZD$5o4Az%3@`BeSN`;;T{ts6UEew_A` z{K^B$r-xA}T<2W%8yBjd+kU>EU-x^Wjc!XfIT^Lz`u8M3P6b&wPC#{t9zOx{P?ObH z#9KPvbHgw6?+5r7^wib&@sV(J{yk6`pBb(YD}C|8c_=m)Q>y;mLX=O}2cM{F9e*KV ze}|TOjqr}Qx=jmYn68))=e3o8rdR#@C&LdZe5c7@cCLo|uU4P+Sb(3z%ktPizWYP; z4=OXb8Wks;!E_H68hn8?KjyD z)1#yE?SLTib!L|fmQRjV7x1srPruLNYbDFq%~)NpWR;oD`GEItKR4alzaN);ex8nc zctm^YvkOvh0yf*r@>xI2?7RryJt3uT7uI~em`LHWoli*na($L?{@$Ojdy>C&xaT8q z`TdWGpY1gLr{)CYjJZ*c_1FA5OMkCKqa5vro%1y8{mt8<)20y4=L~H|*VM;K@TmIO z?!!~gx@h)oO~;(EC_j`+Fhrd^`-Z`vhVzhIZ#UJ-izy~X@ymCtNQ`;Xs4 z&aHnG?T>Pz=V$$%aD0AgMEmPAC2iXOol?H@wew5~CVrmH?-hG|(7!#_ZdB%QO}(8< z*!h+(v+;4aj$`>UtKaTJDi_PNeey-xa6v!3LC|1dup&P?-EJ`b=ko^6lSf;3T~L@` zz5?ft+`bqq-?|T(P@!bP&xrE*IL>+e<^tT@2yQI=OAB=U+&J^CDdd|t&U`l&^8I&Y zua8CNy@h-~7-zm6g?!%`XTAf4e9w$C-;;%Wyhk*ic7CRi@9)N$FDbP9Uyd{1%tF4; zk27CyA>U`lnQuiQUp!A6tKGL3@;yGz^7a+-?T_-sp!lxo$zeQ2^)V0W5&{P%O^|V#->c;im`*xT z=51xXa!7yygt0A!_}y|pnRW!rAMG6*)?**+rEHh#SAXxv?LD`9{JmWtr?Xu;kF0f+ zl4v}wb7e7D9;}k#%yKW@?gAx5q&n;hV>PrNl+kv57SC~D*O?kMU(qd_^ zxWCJM-T24$Az#=&$FY5^J<7>hEH21-r`aV9UoSLyTH8>1$HGrU#Q!7okI??19PJ0` zq}P?m;B?X*@*P^|zqfA>-cMnAv7B~t_Fb0a>k4h;i>A4^Pq96U{Ol=x^a#6Nv0U%> zG5@~GaznlJyPfHzO(m`edwrVy_fsN=vD~QMyg~R*{c|GnxgNy2h`_sE^7tZM*IbaPZeA?r-E98-;2bPb1mcp+nJ0h>h)U3myR%gtnt2h zKH+27Iv}5*rjGc$tl2)}*Jrz9c^*aH`qzOtxTDFL%Xw2D-!1K3)CWa<=K7#0x7o$0 zARND+Jzn{}Kdz6-G3R5{D5KHg{B!;4^xz#Nl~RRQ!8e~@$9jiN6!?ewj~t)0UmiQ(K2oZ%zRU0j?uF#rIWH35 z79Jzt$e9f~_!nR9*}EwB74dsYzcX&RziWit@0I*7q}*pQUkh^I)KBA|58Oz6h4zWZ zKaO|a4$k*-@+GNPv%K-kMLni}jB@3i2;`K`%MJbNsPlFGz*Dh*joUt4QIT?+dT;!8 z;ze=&tbJPOu>Q+>jjfLW05_W56zidL+muUthLW7G)b*1h9bvue4kpR|Yz`vK#91l86q_~K$9sm9X z2fv+f&adJ)6X>1C*5^EA(zx}@f8fJtUe6*uF5iBxrbWI?--q@?@vK-8&*0h{^ZttWhjjh3<2O`(c0Zx(#mm(m&R?Z|wp<6Q z{8j2_%e7zU_Re3nT-(#%1I%{oenB(7qWD8TYHjq(fVWq|dA36RQV{|(9S<51Wiak}k02u-?g{%_W#oV@oK^ZB{6 zU(71jG`gP3p%n( zF(#hxj~h=)JS}vbtNbs}5wAb7$Fklpjp+#X_041EkL|EB^M`!r>3d(}DECL$XbgM| z`S*^QKQ8wN%pdZ7W8C?^Ga}#1L_dV}^Ig(xa!!!##&zWH7Vf#71`ys$I2i5!@?OHB zC``V-90q-mt8I$c`Oo-sV!5+@lzg#{lXxFk=;C@No!{>a`-WYrrvu#)zvbR%p&q_o z?(}$n@pppVPVjr5*^utT`Mu!Gz9*2Mq#elhFYEn8bZ;ZSGC53oo8PmTBH`gZj8%TH zN}k`(XXc9!SUc=ff8l=dGrNbLU9NcYg$l?c(hy%O*5 zQQ;kAEq_SmD(_M`%Z60$@~)Bc?B6j6a<}V%=C|{cln2(coM;EncB*`b{%7~3vY{s= zU)kO>YQjCG^aZ#l4GsbZ*M!r0H^0lG_44-&n{dj9Cfs(z&(Q$=7VRSI5H@Z%`>EA` zvGYaoXO~&O?7B(tWS3dLwC}Ovomq{ye(ZY4&lCIicGA+BT0W`;5@i4Gk3RkBPcstU zgv`FTQLQr-bZYfcf5l&|%l4A=zYJ9gdd~E~@OsH6?>e)8q?5TT5BahF>+77%x9#82 z-;Yy1r9utc4~lLS_;*C*<&SDU*V{hdnl;1Pf0w5FdEmyK6~UXYRJmx})h*#{t9VJU zL+{b{$?l_+quuXTJ)HNO|B%M#_Ku+2vpM=9-QXJx?`|z;aCt@I*$>GNo<|VBL+zki z$3JVk?X~v1d8xo>x2+JL{AWv~ldRl@ig#dAN$jX{^5>G@zpuO(_@U2^Y=VCQ^7%WJ zu9wO8%fWa5?w`wRZK^7$cJQwQE^lW)4?Wy3r<0mH|>vX;mqE>^Y5tnJ+p8Q7VSpI{I|mQ^@aEyU$$>%?;yJ!PWT@1-QR%- z@0^%Eis34NbA907Js7~dBh(iI9i7rc20FU*yi!LMvFOLPj>g|4G3|Jh_U|a3B3e$~ zND$z8iM-S`fOlRvLZ%%H<^6a6u49Z3$3c;A6|*5=FJ% zIZr`&syf1RCn?6C3jA{XW%_A)E)4aeM8!2}QKN;^)M@h^sBIpyS41VegN z&bOrUT<)qRAkM4+gwNqkv^3~7(#qm7H;pfZZc=Ff3I}^uK1DEX` zw>X{}$j8k%ewxHnI!Cq_HNSs9A%-WU>-jjIn%m!7iQ{J=9_I%|PMhx&slqM3PsDz9 z0Po)puR|s{??-+QmglS8QBV3j-S5A-owEsW6#%YBBhz1H=VAtMT21<4X$EM8e3#~G ze=EHjA?Ok0Ll(Sua<%#X-654Trn7&RleZEa`BUwOrEcwqrE|0&md>^B?vy0HoT%N% zeG$q9$35|ZjODT3??b(7$uAOZ+w_N#fpDz%KALIKz#Mk_O(JK@W=v8@J zA>jesr=>ilr3Kob@qQ-dj`?CaV?8yzO!B3rdD^c_^QB)CK9)1WYgqZncM+w3mwKds z6F!zR!fW^(!+(nQ^U@qW*9!Pp&Iqqz?Z;`UqWv9wr`)BbQ{;<4{thMK>AW9%xc^)o zC%qptUiHXafoE9zIY$AN2i04Z5GJ4fyPt$teTB&k9K&%xW*Gkful5JS+HXm5wMTA%V%UWo<_CvMXn9ly^{g`rh!;PD6=sz9_gh#k`!$yQ9 zh<7#hM}C{xOSe&a6faBcKUab+{W4#8K*ndT1ML5V<{_ldTjKSi1CU?8KN-g#l=#Df zhjigzm}mMqYvO-0de^|`^@OL(?K^&M2hnaLHSzZ{INxMHT8)NeKB<>BN0L3J_3-?C zNGGSlyJ&T`KI{W+9?VO14*G7yQ7>fun$GzwiaC-M-$ko4H{hao(YmPbES`2hInQ<@ z-K6uR_&xBYh=g-}==-esmS==-`4+RYwwT>z=g(PB0t|NPdpPlXSF#SWN6^YW%rAg$ z*Qz$JKjEwAF=*n-*e2jJZp46DSj*uq>K06r~Ed1 zfI9NyQ832!pwI7py(P>S?VYx4$oOFIbY=FPU0=^>3@JbSyG~)enWN=7pE)1iiYTvd zRj*%5n2?kc@}UO3N0(hA-iZC#!>AA2mCo0FSdTwI2X(yJPUT0q|3;*6P5iSZ?CVa< z|6j=O@7DXhGseFef;3F!1?TI(v79lUa6b?G-|ta+I^&-L-s?9j0sj4DPiMQJI?`rG zj(lf1;ZJ3GM(^Xm&GZ52ak}BH;sw1yc^K_}R;AG1*G28kd`}kE8M}d+cES0DeEm_r z;WujeKHu|u*8V<2Zr>|mJG=&kp`q@JgL|Fao4iBFqKf-qgdKX$)@#MW{TG-25EMdwUn_y$_ zg%aM_TM6;}kuTQyRK8f}SGj-3b@3W$+ib4kvw63_capE%Vd+Ny%11P;WMVyRyM+DS ziF}LB;|6_QHa5gi%TdE=N@$$XC%)Vd5cDM`c?4ciDqHx9b z_I};2J>Pbe_U@0{`vK#Ry+@KgVC~`G^|SBnh41=3p!E26{jzNyw)Wj-{5;;;cbnt0 z_TA>?S^J`GsdzRXukFkFNP8b&5yTAB`S+@GUvKJKXYHfy?CnE%w#T4-_d2(B^7UTV z^T*mgt~b~|mqqQ9P1E{hexGZx>OWsM%@?bjg!f-<{UF@uvUOM2oBm!az8|CY>sJ2x zeyzXng(L(*CQ|(17C&|igt&;BMI?@{?IY3xIf@} zyt#j1 zaE!kY0_^c))%UkXsW0C#Z{A1K{@9M*y)g90s_(6mK6-s`kLv66y5Ha=0&ZZ!OU3>i zm{1Y>BAw79@ov|8zl`0w(XRUT}BQe&TpQ)ZCBSAB~sc`?eD%p-z}nOn8-y zcrl)DMf+F81G53J^QEA4!YrMKPUx0-=&{fj+l9nSlZEuH9zowCE9YgRpJKXBZc{&> zPaO*#mlyC*50Z{2N6=9bI^y!bR^W@y*VJB!;r_e;$0-Npbp_+68uCtIM16Utn z{b(Q3rKN|>_j3(8Kr)?hYpOV?GUUlQ7p=I6oXH^~(A~TDq*TK9Prf zx<0YR^7SS?_?4Dkm&_6W^~qfEOA=pBZV@<^N4Rn_DB*$98MdCY5^+i&`$IXoLDC7Y z;p-(#c=p4zbaBF$z*!&dm)A-<;WfNo!h}cD0q#OupDEdT!_@(v>E)y@;k0yt^tZIM zRP+$>vmMLHTLQd>-)!(pY(3@|WZi-A9KU?sn)GP6X7I00D)`0kZ+DAdl6ER5t0kTA zr{KS@U#F#4+4|bz!us0E0MGXF_3N~Bo~+pNd)?Gjq-TMozb3$Ic)5gA$me8%J6Go4 zgxCJ8>(-=4!%GbQEP0tMEuAgz`VyXUT29WFbi!-+JcC~(>t5W)W4|Ii`$;)b`;PD$ zR(;1XhE1gFx);Ng+j3IHU+qWi;ot6UxxpO_u{FJM*NS)@V-1z!6({(+H zt)c1EgZkAp4Ns6TYo%f8F@K+p`DaL2-=$}`B4NfVJTZrRlK2fZf-q~X=@`}#o)*IM zBuuI_o$cuFuMc{|)p0#c7M4_IS5XeZQ~|m1TPj zOqn41GR1vgy2d)?m-B_+?;|O0*SVgS@dx&T^P{njy`S}GuWk?jS17O#X*96i_kH79 zvREXGb}RKxJdgea_~PpfH6B1`dK);NwIE%zo0)zqROLo{w~2Q6wUry+#=MmcH{6ul zyG@KAxTf-U#t+=E{+4_Or2x7H@wFQUHuLvQ1O15SFD;imCVhltd3!-$JkKwt?~dro zZ&LhDzrU~L^E$?}-@1Ly^@-zuM`aSxQXXNPAAS#n<2282kS?}Y)y^}dQ?xy^7h(PJ zezr@UR4G5C-k{g{ayQd&(sY-@*xu%iY>)TzB)-oR!+jA0q{C&}-IGk!9M(gXpP8K- zeK(4uTs!<&csrml0vweEoS$p-da-@0D8JqO=5&b%3p?grp{M8Y`)r|^HrX!{PYdY@jLDK1LT5z zf%q@q+l(h(wI>fq`ap-xTRSQ`Z^ikP6e(%P8nF+U|GIld=2v@ozvX|4&RcO#hV#<2 zqbBx0^L?c-Pggtl1D0>5&RcPQ2EzjKU9RV6kngP#z2)S7gFjvDwzT6iov(IWA@c^7 zb4Q^ZwfBGB@>O-dihP_`5PnaDpZrjJ`n>^O=Bpj6WWGxH`GxxHd}MooXFH`GuakKR z;U^aG>wHP;k#@XR=c~YvqJ^HbZfx?moZKaN(~j5cJQZ})BqZKlQTvvYtp;~lQo*kj z{OE>HxR15v#}HI(Kc%#lw zaXyR|6X9jr?Q=?esAZ*OCl~ml=`2Ode@P)-@#}n;`TtKLUDp+;B{ctIh4k|g zAKo8Su?XXbzjy8X3w~dUb2^znVO*h{bKLpzcgLPr{w-h$$NBEyR%$zxYxB!|odl)N z19h`}o9Bdm9Gh?S0f;pkD4n9~0VUR=IUnKtk{tDOGQ3C1a{c^BeEx#_S9#Zh!_3cl z^okER`*GgYEAgx^^?u$}32-y-i{WO5_yr^KA20E7c|7mo_Xda;O$NNWkM8$kd_KqX z2h*c+*bgR=PGq{~=4Sci>m3Ms|Kd6wvL?LeR)O#HG{U_V6K`M77_|4khxY;qj(j3N z9Ny2Xb6)@Ds64J+kZ$7RGotZ6shqR1c4EHG#q|I%($7yYe-|p`>uSUMgbX=Sor!y;B`LmJQv4fmLopsBTCle z4Fx??OkWLH!hsA~HyeE0t#9wQa|rCeH&h01C2jrv1A~4Zf$=xqG;lNH>$hyU(buoS zzJEBMrTfw`A4Lx9%&GNlCl8c^rwV-heb$$if+M}>MRMT#^l68FC(ZZADVNMb__M(W zyhEz|cRfg>8_w@#(XK}p*!6m^H|;o8(zEG$W+|ISX~p`<2^H~upU&m!-H2s=KPQ@Y zEKt1xBAA18JcW0`U0=j{Y%Ape<HBL{OJ^?NIuMG)%p`ANg{7|DW*J zMtt*gbd(GHgI=_A0&VV3JR*3S=WAGk>wCWk;qU4+?`!Q>dUhH;pkMk~UBj%$$3VWX z3m4b-;`=1qVX(M7xAbceUjfSgu7{<(vE=>V4v!o+i}LbJs1>*IA#(3gzg!!}|lg%(Jmy&G|Ip4;1k0Jnf+XPkyGQ zRXWcG{HxpIr)DJF>qQ@OKb-x8_&-;G*Lm(e2EW?&g)i6nHsJrRK##V^HiNf$cgg16 zfWN!|uk*Rw;NM{T!f(`hH{jP4=uv*k5D5BfwlBO!=iPvxRlu+CHyZvvop(c?D9^0# zKeUy{4F>-v+ZTR|&btBss|EZzU+g#dH|xB+^j4jB1HN3KU)NpM3OvjIj{-iOH@_*Q zuZa4Q@4qwO-37eL_sc`ROA2^3{q-Sza@+KkA^q_Jey!)lA^i(&^IsU!Ut7qp_0s)! z(*N~By2}0HkpHPdy2_!=zmb2<2)>*Z^8I6hF7{&IcW1e`6w;Nh(?b4%Lb{eqYfwDceG7cJB$1~wSZscg4#p#zpRkX`Mtjf$nj+tP`yW>o8wL~9FIq07XY3u zFdCeU=W)59^K`%y54PRpp2#WY6CdMod{umg{d?ftuch`}#R;u9raE+-;q8rhbpnzbi#Ky$Y!= zuk>$-!p?u*;~^gJm*M+>hP)3xe};QJbp+u2Ji&VCAf{L6^DpA5T;O_O=u=WSpP@fI z$XJ{y0o~LSo8Vu7a9Wxq@wg`>xTq@Qd$33pXHu3oR`rPj`A~W;*x!Y`+fQS3PzFtQB3r65)F6QIt zhxRDo^K$&$mA4!90duC4N9v!r9y3Oiqwn=PzI>9&ix!{w{Wb3=F3<5i^j_c|77ef+!4c{eh_d40w@zj7zCjtA~y^hJl` zcthvwv%G)DmZK;U1sLE$=haW%fN<;-y=ULip49zOi9^n}Z)%dNLhigzaHeEjQF@yVGkgG;BV4Ky(2WuiAJH@iW<%TIt;@d1Cd9!{_8^K$YH;jgz(KA+q`d-4Gn`ZL7C zd*8aQ60a}Q{s{KL)e6UU?8Q&gaV8Ac*j_mZc-mhh>=o1hg#Qlm)?{^{DUW{MFYf>E z`!>qmrsdV3#rey_G2BBDKjM3Fy!XNW{by1CX1=q4hx;PWME#cQvQzdq?M>3T5qX`@ zMZN9(p!`*UZ1EPPQ($D=mzCPgLcyS5*t?&o&u|;^Y zKg0fV3HtCs_=8&vAHqcG`@G&ivN|H+)=pP}^L--Lhl13E)AsM|7Vu=y>_E2*a(g$m zoSY*7PG`G%v&UDb!}x>i16@)N_*)Sk+@kBuz8<{^M6*79@C6ROz%Bfd)HjCX$kGaD zd;y<0ZzA7Nl<@5^{K2j!eVf zXN>v7KGY|FpVF1D*ZSn^wSHcY+}@4yeS^nA4EgW#EcW|K)Svx*1;T-Jz&)jMHl%nb zBmNNR^Z6v<=<+UGH;&-;37oE9vz*nx*wh%|?CPv^IB{C>pyy8`6r4wOqD z(MNp#=wbJr55@74>EDJ)$@}fBLQPiDIBr@y*AWTF`NN7|iRiX_rHo%4^KG%xOMOq5 z+kMpBz6a~&@DDky8F}^XJZWJXyEm_3_#7X>%O9EvhH$!4;Z!<3IJnc=B&6QDSm?2bK9&$9yU1%~)QFa)GV_dDHfF zeI{}@4*3|5Jp2x5^KoN%yRaejNA^>S+@R~5g(|Nx9Z$BQgY=EiYi;!WQ>K@G83U>7 z)8@LvQ`%p4D?MC4;Cvxpsd7)daRh#Q$Is^@`AY3a;eFbL&OfC;=J!G1jrIQD8(r{@ z6vsE#Yu$+Ys$4Y3vnPb^=QFOw?a%VYJFe+?sCpuc&PIhz)T&E6miSx(5(@=ew+8KB@h?i6^)^)=&UY%x)pI7j8dT&oZci{Q_ z-lX$uR<~B%*JJ#AjOVMBbloG{sr@wDt?k>X&6fB(>$8_DU2aFuTJgBh75LVz>5UV0 zUPw5WoKF0`Bf>8w1M;_D^I1Jv4<=VJr~W{%(CP0q_Mus6m*y+A ze)*N!-)jCIXSaaMe)}Ipc4S%t0dTC($D?@a3rY&_^UyI&$jt1k>|wK0U!(ok>+SS= zy|P`_Uz6p6C**(7^4q&eKCcaUj4zI_mb`k*{G|UQ1^P*^iXP z?BR;w&)%~@{QCB@#c#a-eDMd(j_yBB*FpRJJ-92MQM}>3VC~=j?m5S^-Vx*E69OOW zLmkg_Jn{DN_N0D19rdWm>d8nw%6y}>2lLHGy1w?=^|9K?TSaJ}d6>$tvjc-J?se`+Niz_Y7~1!q*d zd&TdA98ho6N;+_7rYG9XhYz-?Pgz#Cpclr-H(bbvB18KO+J20`!(Y^ojk+=*HTr!1 znAL^+WbnP3&UF~#_5GX{`ME~nv-R2^>kX~H&wu*RIHEtzj;eLoJn??jr)>LmJPVzMr1mVtTNkM}57zmi&XrM>eE-)aBFV(dWr7mtkJC zO^U-f_9e;h<3i2skx>54R=(+B*7H+QJzejI{^a%3>YyL!yN}LKZ=bZLXc?sv2EnMF=QlF$apDOSshuQ6|ayD3yGnVIa=K68)HtpZ#)bN+U zKMa4+>dAVeO3)M9&wSs4@obN<&ol=CIN}ky;crEFaIx*D7`?2|LB{*O72psBJi0&7 zTJQGtY1u~s9^uC*<&$3g8*xvF`yI45PR9O-%ek-f4?hNAIL?cnWWTLzn0P43%=iCd z!8W#sxSvV+dL*)&;`2*yMm{emUVon&mGAK^hwf+cX8Ud6$Nv<0`%~O!DaygI$la=A zlson;FOT|&qBXco$3?C?x~t$vzKqfh{crL4vI>KUhrrXf^CWq<1Y7ai`KlJYD-Vla zr5>hhzMuW1#OJ>5+@d0G8Sn4^)+SJ@sDG$E5MQ*{A5^;`8&bM_{HZ0^EBrP~ze9o}^b5!P<~YAz z0Jvtv5=kE^B0b`x_``rtC+PxDIr$giOJ?7%OsBqH^2ha~MxKxSY{|d}dykuXOX}G# z+3?**?k+`e(<>6LZ&SV7-=*`zhV2Xad#rWaKk<2^zoVPosr61L>NxKDiec@ix?kVI z&#On{=W?OP>rH%$NAdGq0Nc^e4R!iD;YF+^>}>qs`d9j!;k9KTfO9k!SMB*e zv?EJO&HndyYV+fC{i0#xh40Ige)bUGpPs#e*kJzw3FGreRj;R0X!QW^ls@J6BN9wD z0gn8l{-eLie9!0aRU*FG%ft)q?B|qypE$_7if__R-Y*4; zTJrx1JuZ(fU-ZeBbgGqiM@0(scfucs+9AD7eW~{|{d@@Jkk0Ej{D_6^du$xf3DV?) zjdK?x0WKqPa9(f13q5!*k}m77i0|Kx^LB31qx&3z9+M}hKP`O(^`4e^en0Qxe9G+m zkJ%pW&(sfdP+~3lknk(JW@e%M_VQdy9us)hgD%^r{oLhq)@G~kQR?I4P-@=+WtjYM z{p@_I&U|Dpxomt0mhNe&18-n|(Jp)8xRuQ_??E<+N<;zb)UfI92QG z{nPah$Kwi;Hkq&Mkkb-hmv_GSygldz3JY9Vcd>mI*8?@v!#>_+4_o_e(|o?J=krU) zTgItpLJX%0mt9toAK4XXa5%0rvglgrc=7$+|8OtjN^N()7ePHwc>fMp_L%Co;cJKu z?LVaBj@x7GM;dSPlP-|3?@ziO4|-Y6-6XrhU=L}WtBCs$xB%f* z>jiE2jvU9|csyDUbhOllGlg4qpZflNXO3fs5mlYiv}2^4UR7*;NRx6*&e_hgPC{nj zrs=8~^nw3e^;tetWhgJ5O!=CY%(iuy&Z`wJoqCSMd%KY@q6f;lUNmd@A_27J=kR_5 z%O}Rqnm+*hK>ABmJ~`AlPY4X>WPN<;L-cH<59_jZvL5=7^<8EB>4DyS8sT!H`H)2;RSC8-bf>>;42F3SZG!_rR6 zl+eZ^mV)x&v3-b#?c6xWjw=U7KHPBt1O=5oU|(&kL`L9ee{p=M*KxT z9#TCX)+;|?a{XSFQ_@!fWVTQHLDl9{*W(WKJ81?S2pseuSX15!H>E~m-y^HeV<3cU@<$zD<*=zMR`J6?C05@Jbov*3U$*}07 zx}XVssLpuDh;qxx771s2w0~qfl+P)?vr1R3Xg_7YqML>9xzhQ0i{Up&FzKA5zQZ-n z(lFQKDY>6DpX*o$LD=-*!z50~43zf0|!!Q)gPd;iS(Wq81M;Ou)~1NPq8J|RQa*|@Ie{loQ(@bSNR zUq#e@a@|Pq*(Q)w`{o zkjVD=aqXv5PAJIatI#QbHH_$_cs{_-#})V8M{75?bNwEPx8vX>WmJB*jZ-Wfj`kvd z`nrSLkAw53NxJXXyF9nZ5j#7a+cnt(ir@93k28S|m!C&f@3?#gI;JRLfsTdR&VD{P z-tT#aa%JPI+jEqYf1#W_rgG}vO-xI=&f@*q#|b}2knL4^xGzfz8bexcT7qJL^ZoNa zBvO7-eD{TJtbO`1_fMg(>0GalhR5kV`o8J6ML+g&901@I9dkQJ>g#OT zd77U2{(_CiVZ5|)itTa=Kz$vE?Me>0JbOFUl9x-t-oDvBwcFAuKPT}%Z}IaTowsZG zem>gU-_JvNzwmvL2I!#k_sm-D**Q8MYBR|?7qc{sALP>o%s+=%pubUx+3@3eC7Wnf zovFC@-cd@PhVSnbu16x%8)YS=4@#Z*R=p8_;M`v4x(E3)e2zpX>j5Y8BE!4N#zUSz zJq(a)kKR)a_#f1KeJDoo&oewgIvqbrx7f`#4@oCIg)r73qIy$aecjUSt~i|y;(VmM zbs)d5JLZobJc4ArvpHGl=J^q7QhuL?E-igbP7-t6riJU@*C5;t5>|UHE&aaSSm*a? zPLX`)$(MEfT&(L4_TRsN3UPbO=ehp93Z~x#UbUtV0W0El+e7xzrCv5}ZUX-pUNuL+ z64#TA$G?_%^84_S*|L96{tM5idv$>3h*mVxJZ0A$$#Pw$r6-P5QvU zv*0!%A5pTM8Sb=nw_8~b>FYcdf8dy}6K+2I65J;EoY^v-^0OB{En+{Pl9slBFR*9# zJSpv5z34uqqFu{o53V70*nxNH{Kemu_V)7iu*}BU&dUWnX;^()>_N~g_TZWC5J2DO zsjj$1!n5vVD^ZR%i|_aJium)D2ZUa?hi02y8s2{}d&ccJAAf3z){pBC5F`A5os`3V zS;4PO<`1A>lajQo>ooqpkm}=UGH$*F>3)99`H`0OJ5s|JArX#xfrJi}XGuG zhhKv4^ZaK1^Q>I`{+oZNgXK!UHu)xBD~O?d(04srq^CBaid4`GIM&DYF!l0QhIcC; zvz`03{kv6>5T0@;`WrM?yVbyFJpS4K4$jM%UB!4xN?BeNBHv~RTv|R^;#qG^KN(O> zde@^6mcxF)5jxhB6@g!9|i z6DA{4`sE4%1N|rfj_{<5#VbVzO+O2c&Bz} z%riCLtm8R~5Kk(2$S?N9a`HzevO+uz%f?SBeT6x%aD&gakSyItk=?OdegHjIuUf1Lh-j(={?r#m%2`E;njr%J>p z-;WRd-^z8pNPeCk%~yT>JltpPhCsswJFl+gvflIYb96h;?B(QP$-w;r+6{G8ugSnv zvloD#{WP7rMBvh?uTpyf``jb!1;DAjKq(^pxoR&=T_kj*Q+w53ctDaxPCkz^Ymihr z??jBAVTz!$&J(12RvdYIDID9eJD)q1mt5;eelIjuymh4Z$doj z?Tqq?oq+seC%_jw0saMm+Y4Xpg!dr;=X%lk>2@Ubr0NS40LL)(1@#D9#`m$uJ-(t) z+9Q-d8DB3YR`AW}PRr*>JzK|Dy@?+5J@U)=YV(?A{xhVV)A9*|CycMGEXwuv8FhRu z&{LD|)FNM<`E|UQ55HAkXnz@Xd<4JPK4p2uv?-U=8`7@$^P-H8XfHbQjVXmBwr2;T)^M=khDST%A`orrr?BiWadD}F7FX|)Z&Cu{wm#FXiq~%24 zi4W`7yH(zoTp@;QxHswVF7iE!XA9%nsX!UVf0Re(^TSzJoTA~S;w7_JtKVsMKlKis z+hd(~Yq;??_5Iv^AM1grS+}KHdSC3+cQ|^9TI4&XCu&;zc{}U%gMV+{^B+%rdwO<;j#?g1YZvXI} zl$5)ie>r|v#P{{I&Serz8m2d0&#njf`AGV#`PZK`TL9DK-%u;aIpXPNTYlPgq_bA~ zuJnr~SLk|7u^iv$y6PUup44=}4ByYZYMaH|c^A@;u9Q?SQhm4N?0?dJ*R61Y{%IO+ zrCa-HlMg!Y^>H9yMC{P3wr-KzIa${m<>Vnrr+!%at4)36=U4rHdW!pzAQkJ43)H?a zeeHHjt#p^#BZk8F11Tr?mn>PdP0CraNEzefL8rA#W0NGyc^7FHFq=Nd73TMH1}1No zdvWDtgJdX{6T=f=$s$_A^f!y|`rqyFhLR=cC}Md?C!Znf!Rh1+lJ6rYx3M|0`}h@? zL;89q4`}@h^m4p72zk1Gh8h6nWF4TjKJ-VUf61aZGZ}Q(#UDT2vy(%}kxrhId<*`t zR$InbO1O`EL_vmekXF7lDz+x~W&_+~%&eaY|hkHI@su?;?? zdMaNIhBH6f5&x3h^p@LIZhz2zy(t=BX@5+N#w%Z6r(Fk9<$M~)eH(w#1!cXV>{ z4(IkKakAciFV^2dNhc_u{2Ue6Bcwi7kIo)qY0^`cQ3dV4LF0M6Mf98bY!8+*FcoW^ z;0wcaWxM~`Y4zgpMYzeRFTjq}CLjWC6PSXi#NQ_=&bP|RB?8wlJDK}wQoi|*BUQ?u z^gS(Kpjp1oThb|~NKAH@CiuShCgjJzWG~1dJzSqA>8l15?y6hWcYgT2T0iFz@}qu| zAHL+j+Vbmg5!SCW3KraRFMp=ypC?{&tmSiFR6*9YGruDJX4pEydeocz_jOE{6W@QB z{fL&=hxQh@9u3a~^Nxr{RsSmE+a~aVa($7#G<{<+AURgZv{V?eD`E@pzT*3Ncw|FD&J92)U+k1MH8;YEt zkM#58az8p6x61NWRkR1{HDZ3gSoZ~=OS$A%yK?W1%JuUnF5lst$1bfG<>*P&$JdLf z2C=0U?(MeB_g9`Ta+NRc4gG_wZ`F#ef1RXwJE4E*D8oR1r13Ugn=g(J12`u#jC9}M zu6A4|`DU5ilrcim<;Sg%^8B7$zEHz?*U~@-;i&gUyf1j%8m0HT)#6v@oIT!TSFC>}xch<1*_P;Lp`~w`Vy{ zA{lx}SZ!)Gg8I5%^lu4m1ftM&Hz<*d1L1Td`MnEvzgkH!7yfsU%u zFKzuPB{;Erp7y7{a(T} z(5Lel_UBk1a~wJiS^Rtg+xh&sznNX)=PX7$?>;c$NwE`Lj(vZg_)bMT2l-j2^idy^ z13IVljxe&4i#j^v#Jsg3{@MK7*B|NrRqs<|GaCn;Ag!T zL~`x#v@#$2^9!dp4~Ozbjw341eonMiZypNyc0}(9wA+VJz1h^y&rWOh*LHgO?cjfG zca5-jx?1(}I>48c*9tv;z9+j(&$s)&M)pR#_dY?_TPTNMWjIgi=Rn-<&(?@oC&Lc` z2u|b`C2T@IYF_FKy4>FdwD;HDo~`%UEw_N_Dl)YpQqsf&jW6OL>45>ShB-nB!p5G8bV}*c;-A@YE&eV2hzh~I( z>|v*Sx3+V(?-?n-Sr4V(-;-jwjPY|dX-VmIJ?8QL9)rVk-bu^uanT2qZE7RvuuH|0 z`*#)m{4C(;U;mJPM`bU5v%FdJlrCSd@pXvCHAsZ>@q+V88PCkW{seLt>9+1r#x4cJ zYkRamkEVAx-t3F|CH2IF@Y=WXu-9?sh+CyhF(gg&)-%VboKC710zI^REV`+@kk z7w|tGy_4mVpO;1@TnP2CyaM^*SMYz6`Lw&()41Ls`OW_F^@lkBTNky@Pm8na`A{!9*Q=|} zv9Qs%>Ou>nzWA4{>d~;vXRZ7<(*ImessBFu%^x0VCvPA*=(*|~9arLftH0bn-|DX% z7vdF1b8{5k$d-#tP- zR6%%?`8}lrM>>C`a4f2v=(@M|BgmG?6UTi$ho=#pWCGmq4)J83ycP7g9Y465y%*)8 zT@Zbwcn-_oiJ)9kWO~X|W#7uz2}$o(#8bYu!LOdE_rEExjHlk&S~wT-Pq@z$?53pv zg6qS7IR^}Sd-1zkQhiN1W15d2UhX|8moD#8{Sez7Qolu-?)2qdBm1rIvwFWGoqr#{ zV~F~o3No*HIrag(-~Kf6`@k{s`#jY9$I0(+|DcuM^%nU~rGbxCzFp6{oV%WUG35Nd zaq(TxSvBQc-vjt@$ocU95WZh|jC@yl|MBsCdmFxID&8_*RDG@!<71WgSk9r+lAei2 z)8CxEL!XbKzfX_(dxe09bCs=n+}`;QdR*oG$06VSKV^I_Jx4yPJpcIkd~U>NzmHiz zlcPH9khv-^eGo>N#7S+U&ZB52RS<4|2h-v)&eP!Yahi6+`w{kY=!~bM{h|G&s^OM+ zmIfPRG<&Eb$w{z>kYDT}>xX^FM>>37MY~M;6F%xqyT$DZw>O&hP`4ls@A@hkt@h5u zZ;D;ZaX{No=dUk3z1IJgEU`DYg2E=fN4MX8=RYI+ZPfaVV!v6rN44Jy^tIS;X5YD7 zjAg%l4eNexzdd((AvqUACq#z`}&)o3-W#bKBRNK>^%6_5YKvILs^qGJo_dM$KMbB zTh0qF(Rl7#pvZ*hw*DcS7j<5%=^O4=f8+W&@`LCJPx;{s?dwa<&pyBlf8Yy$R%dCi?`P0V{U*Gd`cs^zXexv`W_-k6g#>>RU<@3AKqm}RY3HPgQ;M(c?`y#lk8->6X-x=e&;@`bz2z;fytt+e-o%XLk zd;jHeu!$`7{cncpsBalxlqbs3S0g#fY`-(Sv*qt8SU-2Ua6E3O7vG!qeG=mTji~=; z^GqJ8RN(x5>hZkKbrss)?@{zP71w8S|c9R9!Uy?LA) z#hL#vX)ev!#xh_K#^83qAP#%vTQ-+`B7?Do4=m1+JR@5JGb3dVEQch>99cmQloKsU zSdkD=APEXNP!a;#97H(?%H~qYrDT&Z$>vb9N3^;4KGj_{)6d6aV1L=)>-)#I8pf@6 zJx^6vf2z8=y80;Fe4;{+C4b=Qn8%SVzyA*Di2RClDsaDOA*J*G+V{8A`9qB3E+$>< z=O3ZBIu9L^=OfYo5Ps@=kMldNC&SGC6@~BZJjJ>$l+P!KcFZZ#-A(_9^=fOq=nQMU zbcwKv^sN5(AXXcyM2K^n9YxO+#^+9WU z>UnH&KZmN_i%Z*oVP0>l`8CyiVB$W2h@qZ~U*cM4rmNmN5YKm*`67Mn`4aWZ&gwq3 z(D}O*L2P#sr5g*=KeUK^&KH05T!cYu)$bH~i$xu;;y$RzZ){AQwJ08?XT`Hv^ixHC z<_?%hsjB#qja9%W<5Z&=t|39+#k%mYx;bt?w70lV824_k62Xt z>U*?HTyq@Xp>3(>996jbu7-M!T;0dT`$$WV7kfkJWlCR^!_t21`P#Wr5qflcuf`oj zy%su)^Jfc=^M9j;N3D6k^&Pujc|KC#neX*dBwAFtAENy?h2~)6(Ou z3Mt}=au#+=3E|beb?Nc)dRj(O?U}lND`Ym$H!NL8Mm-O9h!PXKDC(JbqGXZmhwdX5 z{qS22`iB!e zI1a@3ILKtKRsTnv2ZWA&vV0e96drWkP`LOmhxjelD*t_(Ln<7pkZIRzsll@7rTpG2NvD)^V^?mWw)G=C@lJohlE@%@J?ww2li(PUT0WJiJ(p zE>OLuKe214EvANxmJahyIqfg~X8y;EQnUM8f~e=kRX)V=WYFK2&Y#*&(q(Ai?74iO+8BS|6 z{7y3&b6iF2|B{X+j=z$>cppYAPfu8DG45j77n^o*J~P`9OBTzCPOUp-d%?@w(h~q-o#dC2^8kjmb!k z^~r*_YPso3|4_Z}IMD=E5BlD2*_KY_f4&*Ox9fK7RL=oNE&r+OddjPd<^Pv2iu?;* z#r_SCSve5x-gG|aI{IXLEY9PiKI}YOrE8c!c)g_UFShLJJfh~q!Tmdp#&5);o+sw^ z)~)l~tb};_RPWES(tqrz{j{DVUNmOem$aQ?mZK;)u|J}Ii*i-R!Ok-+zvQ^J7VV`$ zKSlYA^{ukKQ_tVss?JLr$ViLo|EllPs^^}CezqmEbh*`_sdjhzxlB4xXc75x(t7Tw ziKK@hs&A@Z8YWJ)52sC)zjfdprCZ0J%sO_IZi}sSroKNjRX?qH$yB|b-(k(qJipC) zu2Fq&MIGn7zIhx=ucVC9vNX2ZTz5E*nA;caUXcFgx1VQ*t8u(TwA*42)$`Lkcbn#^ z>mp$nDb5rwTH2Yy&GY>X>4;sN$=|SrKP>CJXg}Hc-cL@n9HKvw-@dRQ>gUMv75?me zFa4FDs7GQy)Ok%kU!~rI6LzsbDqPeXcD|SCiEwtlx8*B9@kP0ap4=kY4pVh9&*S@O zE$VwxY=oAj@_ADF9;Q`3lx~p1=euP2oFTld`frwxtS{=jW%l;bEFXD%*u%~8nIYUP zpBchEw7r?qH*Db#Q)a~RD|BGxV>N%~bB$*CSk=!lb^V6ra{?twiz*M%k1@;VN-JEw zN2#7e5O%YCWIR#tS^3z)S^3CtQNE&l7Fmy7JH&Og$l^X)o8=p3|J7mGMQ3cZ)E7H3^zTe#q-qvBuM7a=|^ zsvT3;KZiwyr{$KEwWiaYnVvYWi=>wBvA$dMy5&~->ifNFewwG3Sn=k{@=@PK8rw6S zo=9i-1nW9YeRorhdre)JMlJt$TC1t=+1ks;)WteYI?g7YOkKoDik2nqi%nfF+JC0W zO3!`dC*E6q-KsfOxXiEWwe-^Jq<_>}tM^3Ie)V4_=No^}vWxAC`_HQUVg<{7kjw`CeMzoWyW}Mn#~ZE8 zgszHuZz4Gy?;V{O8Htbf9!ieh)SDWLjUPyk4lf-~CWpollN00QJvQDuG`N2> zHhQ?XKRFuj9UJZM9UP|=Vgs=ht;c%fBNM~%(b#x=+31+smRQHe$K%7PabrAb#0Cb8 zLxbZ9BYAUt^uSQkJi~1n9Zim|H#UrtVK_cM*uPU6rD5C1&9R}uferor$%&Eiorfsf z(z0=4aA?U532-8E)r~z)P7A|=^Yyzi;s#uH4d1mtTzS+ z(#D0xrVZf@o3`z_y5q{n*Szb|8;#=C2Nx{7`^EdbC+~UT#>9udc{r4LU-0+uwf2EZ z*DAdYL!d`_3I8@a_+x=`!?C8+UpzteN?3#8yf77 z_YTL0`xB#7QwK)|;%S5GxRE?y?57$wFt*+pPsEL(_=qt$X3TnWZsjwVex-N(3-gw} zoK6IT=CfDJtWhWODZ~ zRo1Db?1zhR;09ZUk2Y=?JxE6n)kf=>+&gm9Nb=AKSJZYqk4@|!rvqu6AJp59mQ=JB z1EhL#z?7WYi;>un5x2HN+l!MX#>5C!j{Zb!|4`iMPY%Sb3Mbl)1A{|D#-T)#4EsqA zYIXkJHf(Hsz-q#hy@SK4p)tzV^yUsxQxs?0iy4~-$EcY+YzXhTkjOmzjnO!j;s|9v zHe&4#?L|DDqLPdc3?2TvvuUmuKEGlerWOICEkQ&F4@xk%K#z=D9I3Ny@b4VOIJj9_ynKGhO??E#85u*64 zsz2>NXf@%Y9OEOg;dpIBo9mRJ{K^ZLC&ej9P7yT%LhwGsz*!a7yG^R)F)V@7mGawHx#=$M>{|J~V}t`7ZE&CFOY9fNT?wqhwd1&@y&{@F67j)Vxkb;XN=mZo$!h$)SP1 zq4s2^~&n`t%t|G$bn61#cupzPvore;y}J;ii;hpDgn1N!}E`n!Ps zL?2ajk3|>%VzP;@xVU~WXc5!S@1`!;HN;tAr@xaa>~>mjr$6Jui;OiCCq}=oqrY?L zPkdVSPxN;!{T7$CkJ8@&{RQanH}rQC9T&eN`$qZ`P3NT)HbH-4WL8l?;3ysD`wvrFJ4{_SV}IQ68_7{aj!zjr zVHz{2!Cflatj*MOpl;Vq)X;1djnJOK;rPJLiE+{A7t8t$snjTSEC;0D`t`fwH&QD@ zfoAuxS0!Y&rz!L7JVxEufxi7B*|_KpytMCrYU=w2;-ZIV_Htj^J3c^tspQDZrW#LM zr^7xgOMR+CO%dg3_@%dVfR6sx#9w*728XR?Gu}tNZQ9s)>}9h!GHK1)uwi0clt?PE-mpq2KJd~pV=BVSW;8`7uGk1QgMI(A zvYL+fKUH%&CiR3y#;9-d%1dH2c{oNFFmciQcxeSx+T69i?RO0`G+A=Xd zX!ee-ijNK+pss+?Pn|UCD^M@_l@%Uc%$X7UR7Bc`84^ZNmUbs*(oLA?&q`>+lh z(M{~9t3En6k5MkE=Pr6HG1VhcQLJjK;!wp(B&oA^n7TEiuORwHY5>G0`G)!@sOvs5 zPW=$J$z$xvXtJNOm>lgDHT2j8KjkLR^yDe`L0sF4y%g7E$Jn&=yke00ZU0-@HH%L) z05b8-)Qfwi8QB#driNLm{>rr86~8%o(^Q=QX-U!by?HQ-PV*}(F1cHK&Ewch*G zt#y=5izQQ)RrO^Acx8$A9pk+53aXTB1FYPTzwMH6y|GVR{7hfPZjooFuz9}RU=8+& z3&*RLA06$LI$LtQ%tl!9R*V_bXMR>q`=6w2#d!IY*|q&Ea({WJO`~_dB}6ZD@#r~zf^iC zhvmyMWx32?z>0NDml+IHb!G^~!e{xgj5D_cV>I>H z0AlLmJ7qRNMv_eC(2GiNR1T>bV>G4~A2nO zJ$XYl1Q>2!^(10+W{i!~cw>yNf#~`Pw~~ROXnIx}@BmJV@uLSc>X_5wgRweUvY~= zj3|$aE{y1am{+e=sER#yc#Q7Fh)OH2h*juF{E$JTyzx;LfWoOwO*h2G)b`|vK8c{Z zgOm+f*OcvO%MNj?h>okFsXIYZXI?{O!HS+T={&vf#*VFfq-}VRc7+bl80{5xcMW;f zeUx>WjxG{knvDsemRZUo)|lFJl~d8TCY6#0WIF2li#9`z#A|3AidCBp(Ei0H2P7};?| zbi{~KhUJK;DsCLe7558hcjWN2Ai1x7gChr$bm9>~=4fXsN#!R42B+`u$&l2<{+r@r zM0D?nd0WA}mq4vR%(!{b43LL{xHBoPsp$5?aEdghn{2cJaaBig#ZJ?*iN>gs!@KEp z6Cdf1i<^xhYPz?Z_Yil}9kcC&!-M0Sr%EBdVdU_RadBHk-qE7_T*=YH)AuCI zL3Fy)B}U>Wrf*D6wKG%^=r9?bpj)~FF?lnHPDpfSqI<)}P?Bz#(wfFt4pZpJO=JC| z$+5Ae1M!>brkWWd8a2|5PVMn@yx$z37bAVAOvBPGlnJjH7E=aad zubxPb$BekVFH5CylW40cyY$N}HQ{UBqv%7L3x`&jA^OggCle!n3^lq z*`Rw3)Hue+#f@((UkN%b(D3r~=7*BWl-LbACg@(B)ms@7g=_fY%MLCx#tsjQeJ3@N zsdGffVX1lkwWUCj)%_I8+Tg^nl@OJL*)EGay@#oFr&EWy0SY%q4yJLsJPw&%6l;Xi zx(lO@8S5mvf0VA0sj(VN#noO7P-Cv@vze|M1W|#5BqrU#pi`#25fdM<-I0mWT^K5T zm749YoXu%8en2##)BQ9$0f;+AW?M8&M-rVaca9mpBov{yZ7gcnVsG{+) z&1M~?PKTTPKEw%&X>W zs4~ioh%03IbDOAvyG6a*VO2YkaLBB5)0@~%b!it>rJdB1n-1Nqst0X!i>Nf)#x~f) zreU9`CL6^#wmj)>F}qkB&Ds&B$|1MCnd-&{YU{R*>>Z0!s++7kadEnDt!~L}u*zRX z*gJhwHbi&jY&ac*6pX8s=*+pxsvBliSZ`P@5Ow|3BNOsLg7ei)cgumkWk6>~L)_1! zer$~HLW*HI8Z|PX6Ja-Xmi1HdB&l^iNaat@qll*ZAoZ;#_AjIJ_tNF@{{A&9)~y@Z zzb@V%Sh2EKoObCjIW)4=zij!6Wh>1Hqp?Hs?4q6!n7-#lw!WL={nYdyl@U7s(}OZ} ziWKKx^Q!4(?+72A{()g}S~sV(RWO?L;r#L8cw?r~Q8aa{mhdO8+YVYX2JlT7SU5Zn=N? z^5rX*uUx)r`Re6smaknNSiWwBf5q|@D^{#rv1-NY6>CNa_!2%%5|&!tCp`?v1;Y2RjXF7TC-~Hs=%sstNp8&uU@fwUC@UYnHEBv1a9(RcltSS+i#Cn!uWMYyE4NuU)Zr<=RziSFc^OcJ120+I0bcV0mCg zU}a!cV0BC$^tc9slPe=UpXOPV*0 z#d9Ro2+@N@k}aLhnAGHt8)gB}y=)VX+9K8HUU@N0hmyD?7tbXA-(0NP_xJqkddZ~? zmUgk&HaAFpBk|A$b@C_14=fE>cMQj5Kg_ylmvvd5|1GyE4=NBd&Y0cz+GWd@U2ood zwBm}f0oiA=o&pl(7~M~8%!s%lE1o^@P2E+XA%NH@U1!o=NO~ad0)x5+6rH-CG!$T* zW5%4ZV6Ccjl!?Y9#7)~?^9n{ZfK=)ZXIn={XQ!*H)7{lQuV>+`Q)Vxi<2i2j+;&gf z@yDOgeUkI!cCYi4wgp|MIv2VYon*9~*S2)lGN-?7xod^qPjMqgWOpLhH@%U7*kf5AoDF1!AYw~+DUpZ?4;Fb^Qffwr;!Z zhJpAUZ+-WBzx?&*=FB^Xg0}6u_PQJB4%nOD`az2F#V`N(XFqSwnYU%zKsI z^tZp;{Qd2BzVX3_o_hL=UwZEO?}zfAefF8JKeuhi&V5(k(0A8c?)m5^pLqJ8pZU^v z=bd!&wb%XEAOH4ZX86@V`tfm#Mv@Cp>wDenKl0eEpLz16lTTl?_0k#SwH4?p(A(_eb-yFb1!cyHc+&!T_%*4JO$vGba1yWDd< zXZQa0cO%KQ7hSS(OYW_^4^C9ST>D1-doR%EgN(jc-S*@5+cvvTZSS0S-u6}PU2V>;&aQbq;kn0m?d@u7U)a;#=5Fh1b5ZS`-QLkQtJ8Vh{Ei)6 zr*`e@a&?|OJKVmhjouJzpVv8e_WJhImh>6J?KdvTR6A}fwJqqp?XPWDcb(Mj?LKk# ziL-C)?CD(4d3D!$9b0?OZ=c=nY+F9-{PqQ%v)VErB2(}3E7~#-x-V>-+je1BzZCgBd@!ZUt+Hbq}lv(q$@9605xS-2*oVPpk)T_p4XTGywc1PyLj?9l| z|KYuDYrBtJcVedO&V03_$9q9rPiMfr)jhj&eAel0*R)^Vow?n+u;--i?d_SnJ0E>; z_Q~zbA80@F{8?SIJ32BCd5-*Nm(w`6ldNxU&pg$3YTMj7j!vhOcFxt&)#Y-#yInmU zvs}ludz|xJ$9J4C??mT(*U7F^<}Bp9mqT;H1g?e6cm zzUzA4+35I*>xK47*Kdtxd&~8wwm&;(pMAl_J9gf4|NZ}T%NyVRuJ=9u={J0|v#Wc} zMHgT7@3n8VpXgn)_NsliKJt;rKD)Yc{6F0FmiwnFqo|8Jb`Hd^`{Wa+F6?sm%sTPp zHS5+FKUn`>_uAZBi(NezTzp{gp0~|Q_C5XE-(9o+KmPLK?mhRtds*+(za%asp3{IzEbU8gK~)sl-ZdEwW;d-03Uv>RtEIm@>)us(Fz z_VDh#SBbh8?T;V0X)OJ^Tkn4Gk;h7v+D9H6Nj~-V8(wuwM_c>SwgYX>-esBFPHS5} zcVYXP-KTe)*Ri?%xN|d)be`FMX1mY5YSxZTN7iOt#z3n|+-CaTB?DpB+YueU#Ea+;V-4))pcIBLvUCZ1(N6y-H`FZYhPg-!+!V^#K z-a#AKJm-|Ip3ac_?CyzK8!tY$^Ma0^&MP~e9iFz1%p3Qg9&-0&9=hRGTW0li&N*Ry zXV04R+fUAX>cWBDvqRlITeqAVa_^qAt*a;VUt4=lYrAyY+P34|J)P^idXB6)rR##W zg;zP}u9$QCyAMpv%6#GO?frA^@Ow_W=aJhkec)5Kt?N3s{kqPxdbalXI!?H)bZz|d z_H|wJf}%>?+j8IWopZb2_rj5tbDgJk9@p+Z@}|4mZ|a!S*4^cKTlCWI@e4Em)idT! z&ENVOaVYHTJ|*)HM=ourf{W&@?{FTeoqO9a zGJia0dwWm2>-Kq@w_lX`+=ZRa_Prgau5ukY?)>(F*;n;sJ`y->&iU=#bVPJ!?z_F- zKCf*~+oATpPCCBk&TbFT&iUN0+Hqvh?9(VOYuv|?Yj;=Xt4n(B=sacvEgR}Sae+x~ zwAs5dFU-Xiw|Um?n@IJIC(TP6@wk$B(Es*!!|~RRsN?z*3XbDXHWtk`qKkfae&M`x z{l@vphZ^U*iqWN~|2ewM@i$}5{Vzt>{MGrBHO`*JYtNkXleLc?7hBisePEq`VJ!6T zr$4YgxGENI-uS?kJClodz4yrnb~&Dl?T&xrf!&Vh7w>U2ezNx?KaK7C_0JYxU7LL1 zYQyo{tDDYSuc66RyXe6kr_)9MIYYDj^F7WuwNWmYv;7R`>8D;hYkhaO)7$RsrbD{p zytWJ7=X#yST8hx_rnac7$90->y@=lKCYK)90;kKhj*k6y7qxxP(_L-OS%N#r!Fi(V zBx)JRo6>eWyV`nOr#mm8xU(sykCLZU+d8P>=yJ_6Qx#dFjk*LcbgiTOsjZym3_07K zl(^IFywd6Fn(f~2bal__+U7cy(sMf39_OSjcFb~~+3h^g?(C#YxlVDlw|Uy<(9cfi zTqkMYcAD#S`Y-5mcDbFdS=~-*k)0E+S2=HPYj<@!JKMfbB2aF-M2aqVXOGM2U$ng4 zPu$`3b}Y$lGio?G2VL}-R*&Hd zyXf3ac|XO~;k?(i;P^Stv)rf5TGr;LeRH|ac5Wi&U9Q=*U%k$il&Z_sLHm8K%kBKF zkWEa%=<#^yl{n{5o$sWVT4*oZeQoW|4^a9JSGaBKtmW;uIM>WQhxW6lZ8@dc<-Dlv z%nqmfV&`nvs%|Hb9zFZ4;YvI;eD4b##bd&d#|GI!!s8m$Y9=;f`gllj)_Kw)PIU+tqb?`#ahk zYui`2oyR#(>Tu4bROgu~b__TR6z8ILQlM+N%Mr~qtqx)?(QQ5lCrCWUX1y^)^OX;E zJLKzsrekZi^}PTA;@uauWS_O@SoV^%E5FP?T3bjjwNl8-byWIACFkUN-Eg<#RJk$n z%$!>GP`G^k$MFXWoFffI3STIHpRAl|eXRVMFEWxnDBoc$$ftwc)b6N-9?hFt(sEw7 zKijtdOWLL5q=$&7^igYJ%8G~kXlX68)?UdwN2d4VixjuRGCPj7{mJiGsUFK-l=hpF z-RAexL~>uHi-GwvU3>WVDE#yp!hcHP-WkGQpm3#aJMF*H`~mVkQ~KM(KS*I}yPu={ zSYIiy9D7pTQ{Ro8Ac3X)jxh=!kZIjbWufY$J^U@l2!FnFT0gu0b(C-U$`wohJ;w;Y zn+iegn?0R4J$2+w19vh-DQuQ?c_#3Rx-BexCe%w(Zz?z0J=x z-tCaD4Lfe2@Z)71d-zu=Og^&e!0^S={{l+KzMpo#Z;_AMXAD=`+QVm2xv0EjxN2+c z;hp3!p3xNxhO6?mhf`}lqrV7O{u^n3RGks&juIDEaRU~ABC%<+8%xzg{ytWa8c% zd{p>FGW;i0Z`HASfWl6kA^deO5w7aIJ)Jv`;s54ig#QbLucSY*EIZUabmHN?csl;aJAiU9iI088HF44Cl(A>_01msOY&3uh2g5cEq_h-RNej#`7acS(}Llu z9k7RgpZt^#7_R!Uqm;g?lb<1fl|F{6^zGplTlyHT(!b#K)AfPe9d_<>PWM0U;V}wV z?Q9>#SLGq%+j%$nb&Eh+vgD`QY;n$4^$5e2-XA7^(VnYil34YTg^xNeFkJO7?cw*5 zzv^e$!|$VT>SCIUJ^Z~CVpzcr44=vWpUGG4r``W^w(!ndr~6+bX}jMaY<~9ew~&6S z?Cs$X93%W&6h2cvR@mA#dpd_H{8Et_S}eE+Iy|Npb$wpFQynpuX%(^BANz5+k;2tEVk^0-JlVsqrEul5m;9AZ zXV{KQd-&NDuG&$1_<6?&7juQqUvP}@OO6q~=@{YLDO{D6J^vznrhHy; zjBpx1o6%pqyE#)j;{2oPfPK4z6t3E5d-#woJVW(C)d;l~CGXyD(E%zqRX?AicxMVD zEq7A5>Qe|#6RW)anEVV8NXsWFe3tdod=FLq#_%5LlfHlE{AAy2<>y%T#(Q4cUVEAN z)t8B1mhp{;+*9q7T`x6`cq}`PH#R?P9cKwjPb^uvR^yFf$r-thyn!E=iAUU1$1lk} zwS?qHw1i!?Bldg-KWLG#)8(|esI`EKw5Q0f+F^VA0)>kO^YiEIbU6!q=Usd}NNi7~ zqt?RDXUmTYS8HKUNW1TiyxrbRe4TKhnAB4)h-Ep z!M2@F>JO;nN2IG3yWVQt)j{+1D7^+Ko*|ukDO?>tBFIZ@Z=aVD+tV8-rsz}4{Wo<_ zr6mIIf%NS2#0dKXkRI|!!2TF94ew4ZdE0#P_I%~!_^q%jCDd9(cJHw2C+6p4l)im` zM0}-_J$~ee7L|Twt@FQ@>tk%Me7Uu~XDEHu_Qfe5>RfxQd^&z(rR$Yz_wOuz^v%=h zP*tAl6WGJ=p>S1pueX&;g0`!!@t&b{?B!i2ew7eNE}Lk)Ssj-m2)phvEf!H8BDQb$ai}Lxl3n!!gukE0 zhwbggH=*Bx@o{@!q4d->i%2g3au=4{?6&~b64RUc?- zwWP2#tSULR|CNth@l|=L<43hktxs5Xbq;;ZN}iRc40=T?aoitItx{sJ%k=lihCr0R z2oGLkg-2#v$%($7+6ODd`d3`{%oHv(oGDyfW6cyEJVyBTV}uVLBmB@Y!ryX?@b?`f z+|h5oFwkc{UFn#9S;1jGVC@)74)qNs5B8Zq=o#4l)Zyvh!>Os?^k}X1n;v!TJ3tSs z^~rY@=tB|aI}2t4H_=0{v71(`USkqH{7z4W_nB|R4fKhRx0%5QDJk(zLmxfXOfP<@ zEsJ-v`=~z223S@rM@5#K;yQ3xR#atA0H@>ym9l4nQw9k~%aq+Paf&^QIs1U4@&Zi7 zZ-%*lWfy1vZq9k#*MT*W!Kk8=$;FD_(gQTb^A8?qy!?4J9$e-t5sp7}lJXp3|1FPw|O%}(nCs>S;9(3CBH7&rr*2QC3u zfxSIE{n9MXRp1t|XEyiu0SAF|z*Tz0%f5dN;3jZDc2Ja_E#SyJo}T*z&IYg_I0NjL z^P;NlHGs1x@$@Hw^Wvjmw5a$^;IfQTwQ4C<( z_OAk52W|of&*$;8V&K!3UIDlaTmv@zJbrXJ=QMB*xCq<=HdgZV0>EM51aKKRAO>`8 z`x^#M0B3+}z=btDy)tkOcoI0UmdB5X0c2bLQovc@0&o*Jd=XDC0h|HO15X0yFXri$ zfUCd_V80j$x9wj8xCQJ9a(^Fi8o08Z``3Y+z-}>cZp%*u*x1GG0pKuj0=Ntu+|ARA z0H=Vnz;)pKUY=eFxC-0=_Fu*0PwwOFh;a4;N3P-a6mS-}0Nez2T+h?1-oUv5+yeIW zasMcAILhq_;0$mccoMiJZkX8Wk7qw;A8-&j2W%YV@dLnN-~@0PIGW(;rGaz6Mc@{& z`zD^A0UQ7h0~dfpLp;4Ga2hxV+yG9G@bo-moPEH#32rX}SAgrlzMFac(jm@O;0ACD zIF#n`J+I;H0}cX5fQ!JnTX=d!;3{wf*ztNE-wPbdaC;QEayz%zft$eYJGg%YID99! zCxA1+dEiN4$6Y)A8Q**#HgzXMx>6h4{b`;1qBcxB%P) z_Wz7;F9aL~P6L;L-7oO;4B#+u0yqPl2c87>{gQ7l2pj=U0hfTIzvbzrfh#R;_lt=N zZT*!nZ~{0BTma6V%G0X?H-J6oaR2aX&I#ZwZ~?diTn7$Zz|*f@%((&F0`^?O{iDF) zAh#!gGr)P^N#N2(o?aEW1?<_x{e8ee;2dysGmr1y!r1^00B3<);=yxU{qkJO*#{g1 z&H;zS1L(H&qQGh39B>0TcNtHw2wVql0=qBg@eSYDmpIBM4; z44eSY0M~#syLfte;3{wfxCQJHF9y(}#v7x+l|9^E2W|qp_j3OTa5%>83E(Vn0k{HO z2W|m-_Vex4hB!|GyN9{m01g62fa@t9zX|MlHMjeKL%>ns3~(N}IL_0r05^bJz}^WS z-w*7*h1(5aKd|Gq+&}nw&Jp0^ZQNb~&fmf9CEyBh{Z8(m&2laPJH(5ew&TGI>;q2R z!~Gj?V;!d@<1>gp7 z=@jl?1+JgU?M>k9Y201_t}o{H$a$Ot=W|W~XMqdARp1tIU@4>zZ1}l7xPo&6I0sw; zt^#LP^Yr}dI6KyJ_5%BWQ^5WUc>El2;394h14n^Nz~xJL{BjU@1LxvK&e=_zy_-2V zfy-OCJ+PH?8MtsMw>N+@A#V3<#2#+10~hvkyXPv-4d9}fAlr6+3r9HnujU*9E(06abN?`K2Doqo z_iy%b4o5jBfYZQ^825MY=WGB6fWyEE;8L8Y=Q+SR2pl-b?fC@f!XW1|a1D48xRB=Y zYru}f+-|&vbM6+-OHZUUFz%j4I8CxIRJbAK;z>H%)A0=Iyh z@8kY~2RT(&Mjciv)rBl&I4z^&iyOElfaJWxW5!2VzG^rFBy;L;1+-~CI@3E&KH4!H1Z9={A+1D*tS{D#N(0(*YX?JeNS ze{g%^kDTj&%S22P1d zOl|$g>RQge0B8E@CG!shm+13vEIr@`a0}QYCSs*U>FERZ2e~~BTmyD&;QoH#@J4RW zY~tJiZUMVDbN?K0F~sc^;5u*<*u9O%FI>*K1?=0-?Zy?H6FWG!uH@|5#n}fO1TJ08 z{R1)1Vc;lm1~?Bq2^{X{=_i2Gz%}6fjXZt{xCT54>>lFr4d6tQ+b3`4>^Q{P1MCM5 z0q20tNsVpCi&so?Y-1mA8n~R{{x#qxu=@!2j{@g_E5ME0czpLAoD;wq;2f~`P9DFR z)WH zdkQ!MTm|+%$m9EggTOgp_ai*M0UQL50B1hNP2%hU5c#X0jd=LT>K*j?fNIpF*kxV;2i1#SShfU{rW=}iKA z#fL;~$E)XSoKw$ouGcs>f!*KWb^|!^U2ZP|H-No$?w|f1=L)dzd2SB^hk>g<3n{)k7oE?AW>;n!0M}Skni8kxaan)bW0B1eiUH~ouXO8Fo zdEg?j;{@*SK8dpdobz&f5x5520*)@>@zcOr;K{!M9y};>p++G8AtmpO?aN z64-Guw|jwed%3*^T)m3h9s4*NzyV-Kiu(tF1Fz=x6mSl>2pl=Y<7a`(!1Xlu550zS z5x4?e1CHFna0s}O;r@XmoD;~maeMW4&W<}cdx8DHA>iseczic~yx-p6 zaKDRl2sr&gZZ89u9^v*TaO81r_cb_IfPFvV_6D%~XWX6u&i#tptN+G1{2R`p-*Wc+ zj&rfeIq(P0HQ>O1fW5`p_uriBz~w)2d;ZUy9e?FK>9oEyqt1sV7w3E%=UhAIU6sXV;~a0}S8ko!l0o2PNR`*h9*Z~!<9oLiDp4cIt?$M>Ac*#{g1jsO>dJ!e6Bz(L>$a1q$>@$>?~ zVc-OC8Q6a=PcH-<1x^E3ffMKR^fJH&;4*MwDUV+Ut^rR12bS^prC!ce;0ACDIOON? zE6X|8ft$eY72H1pTwBTQlfaHu-0lTV0B2Tn|2%LBxC-oD!{fWxayEbiz+vD5a)75- z2Ce~50teRd_<{AD!@vpP3~&wDdm&HH4_p8)16P6lm+g2j1Dme1=w>Xx2J&vyTA?{-NWq_;5zUmaQ-SDzYOf%$L+ZY=O(cG zYHs%e7q8)V_qCk!*KuwEd#>kp132Hu?S&}k8n8dc?Vf(%IOhm(3OEB?19lwb>3M~m^0*@aCZa%>6#``!&fz!Y_;39DFA)a0YI00M*E){wF+y^;( zKE&Av9QYWwhk=`);CA;XITt_8xdNR38n>5#o5;^|fA{w}dx0H4;C2Hz1MF{b{|Imf zxBy%O_WXpW7X+^T8@EpayMN8?25{bOeLr?;yal+{!|jv6mD${02lme4_S6E-Sz!0+ z+-?9zfg3cX`q-3#mk4g+U^E5J=)_qBX`QQ$mq4cKuV zkM9SL0%w6+z~1Y5dI8`Fa2hxdTn4TKw}3r2@a_A7!@w!v9B>IZALr>$0y_?Hy9YQ8 zoRZ&ZR>xBfxN;*;&wUf;5O5Z_3hW-@@q@r=;1cj8ut5{Q+K;CQa1OW%>=@zk1He(> zEN}_94(v$s^nJi#;52XnxC-0^_NMsug1`yj9B>)90qlM?Pu~w50nPvyfos4mU}KbT zF9aL~c8_uY2yhX&4(uN1@uNpLhi>CM30%9K+f#RN_TI_43Y>Zaw+H`$a|5`P<@WGh zoQ=CVSAa`z`D*z*{-r+^)g zb9)rH{BdsgeuA^F%sC6}_!PHCf%Cwr&v5@7a0|HjH1~H`I9Gvv|IF*A99`qPXCD8(+$pvUvRDhM_%Ce#3X0OFFE`F zjdKpz_%*kefFr-*_A+qjx7_ag9p?~mpv&snsQyjE%{kP=xdJr*gY*A?Mm6&VGZldkJSBaO5m*FQ3i1;o}@UhjZ~<&W`gr zCzf(f_i`?*1YXbCaRKKXa2+^t5%>38%sB<@xP;qtz=0sQ=Yf42xIG121I}*Z{*%Dz z&D`$Z!a2O1a{{=qi`&boR2xjh1$15Vt_{WHJ?;4*NH<{-3Rk4^%6|B2gEz**oDa0}Q| z;OY5+Bfv%A3b5k=o}L#tQUrU6vmZDGTm)_adp^q33j(Kr3&1tt7O?R+Pd^Nt0WJYI zfIT1M>G^@fz$xGya0$2yJPGXnIN!bxI0PI8&HxvHE5LQ&7O?jdJU;>82yhxW4_pSW z1Gj*^Pw?#rfg`|0;0mz6%+pH%mw}tW?oaXfKHv~=8Mq1T{xnZ71RMnpe1`jnfg?|H zdluMuirZ7b1>nrn+&>Ro2liCBe-JngTm-HIyZ@P|7XVHG=YgxhEnwg0c={3GEN~IH z3fus8e4eLo00)7iz!~5Ia0R#l+yeG~f#)Xx905)P=Yh+>b>J4T_lvN7;0SOUxCtD6 zhNqVXE(2%f+^tqDhoky69=`!>Jj?BY8s`dd9e5JB{4E~e_%`P{a1*#9=U%m9QP1SN zJboBB58MPU)_Hu#_c&*PE5M%TxqlwG1nl`f_s;^ifYU$V{xx8SoGaGyqWKLQ+&}*l z&L!Z~Pr1GDubdq}{!4#1>6LVp340jz~P15o;#g$ z@C?q0b2w*#Tfm-kxqk}zJZ>)m8|QO-3b+F7U&{Rxz@cT_ZuD|?Ea%(;PORYe0&or3 zv6B0zS98t*H-U{c+`kI!Ud!zUZ~!< zAZPam&K2O)MsAO6=Iq$Qxv`aV?o!T?5a%3lVjH(tfg_i3drr=ctl9_9c5aUXSAnBf zaQ_l;WGA;*fa}2SF!wir3&3^cD|!6XF3uU?;BIbr@8KK(j{GCHr+_oSdEf$Y8Mp#m z1+D?tfg8Y+z)j#5u;)I$e?H(Ka0ECCoB&P%XMuCTMc@i>6}Sdm2W|qp-_7^e1MCC# z1BZa4z-izda1poyTmzm2cD#q@-wW&q4gp7j)4)04B5(z`4m=6m0(QR_@(=6-4giOM zBftsZG;j{M09*#H0Z#%u?&tgC0rmk0fg`{v;4E+fxC~qaZU8rd9sdOR2R4BHz#-r$ za2hxVTmUWuSApxmO<+d>_6OJp8~_djM}gD8Ip8921-K5}1a?2b^KSqLfWyEE;0$mc zxCC4UZUDD{J@4cB^#KQgBfu%(EN}t13|s@A1a`ci=g$l52Mz&8fz!Y_;39AZxDMO| zc0b7TYXAp;!@vpP3~(N}1Y8Af0JnfWAK>}*0SAF2z$xG?Z~?dsTmx0( zu>ZgYupc-G90ra8r+_oSIp6|t3AhSe18xAffIW}${r3R}fg`{v;4E+fxC~qao&><113M}gD8Ip8921-K5}0B!-hKg{!Q00)4>zzN_Ka27ZRTm&uwSAlE5lfX@2 z_ec2td4PSue&7Ib5I6)J295wnffK-K;2dxsxCC4Vt^wD9o4_q#_hVc?FR%|d2pj^A z0w;jez&YR|a0$2!Tmh~DPXaqie1F}*2CyGE2pk5E0;hm8z&YRoa0$2qTmzm2ZUVbM z%J<&`YykU#L%?C+2yhfQ4V(ea1DAlyz!l&sa09pn?0KB)VF3GqgTP_nC~yim3!Dco z0+)fSz;)nB;1;m^V|;(Tz&_vra0oa8oB&P(=YWgA72rB>1GoiTmiNzl=+?2ASvG4; zFY6F2zD!>NZqBAaT9iF=Jm3o(1-9<8~i#`7&;=0!OxU zdjhz11-H9*a8B>!oCP-aaC>zh=VqL9CBfPEYR=g-XaDOt*YDxn0?y>X4(xp!w`YMv z@8I?da3;^~h5I;r-p#r29?rD_XaD;-S0CbBdW3W3QO?y5b8Z2n4{|mh;_Q2bbM*<%iKjUGKhL@H14O{@O z0ehe4=>>ojz=5BFznsrr)%Tp7Z(ea-&Nr{v=(6TBRU87&0GENQJv@HlRL(76pPXM_ zZO^xw`-gxtz-8bjaDFXM&sfj7A?IgT+poy^!xfiyasP~*Us~DAz)fJEoPS#RJLG)P ziUYtYV7Hv#S@{Qn)4(O*x}4ux#rI6`{Rtt<`J0u$SI*z8I3?$6R$Q0!Gf%Oce_3%; z&cCdL&#oLjT4`Ky$F{shiJFXzT7oZSmKmrvsyKA&?2xD4C?_AKS`!@wEf zh@Agd?N0`{2;2Y;t>fDZ%K3g(dRgG~Mcls%oQr}z&e<>L+f?b-=ob^a8b?=r~EyC;OV7LwB}Dx_7ZS*0k?-2agG2d0^FVpayB+|F3b70)b^`a zb9*|*xdiOk&+Sp*8gNd|U!}G;30%FAr{}ndb6|*bM$S*A((@hS_9$=>*pue|8Q|by zZqETv%K4t`%(77S9tt{ zoS#P7TXKFF#a=l-i{kVjdHlSbk3`u^?H%R?oZ>(S=cD=@tnOUa1O}%MpXJ0 zIe&=aNnp<@Jic!M=Mr#1&M%_U%bmsj^K$+WWp4s|&g1@BIX{T#nbcO&AIRv z&QUoZgNmQKpW9o&srPfc`%%tKIbVWGuklN6&!2C7|4!L!z@ZDdy#ZXjnAd{ z*|C>%F~Zq@HRsZGoCETExGKLs`TbeNdEiOli2Q!6@=wd}sVa`h?~f`j0_Wev^OL)W zbMUR4GxB?pD!m49QGPE{*@GYA@e}fUkjiez?>{Q8%kMoZc0bGGSHH#CFTdZY{6q44 zii%UfdEheeB(P6@e^I3u0j~a(=cfkj_%*i&fU9on`ztDa$1KkNIh+gf`-#dweLA;? zFXWsJa;|UXTnTfY1P)%w?FryKa2?pai^op^mm}QnJHR<~Gw0SJ&cWAmt^ymka(hdD zuSw}wFM(Ztk4V`A@_RyxQ}TO2io^2zK8n5adpwGR@_RdqTiw>18;T>xac-Q-xhlU0 zqx@6y`!0&J7jXa9#hi@|oKu^DFXNm6ZeGsqj_sT?z>Qtpp5M*6b`|IFKF+zTIp={} zF>d$o=Ntjf0at+?{XBjEI0ak;ZUB1+czR*rEN}(51?-RW^b)`sU_*W%MAZ-D2#=q> zopTbeZVzfk9POSL%y%9{8RFMWW{0m{_zyc_m36l zJ=XIBiYxOt=jHpZ%077tw^tW%t^=1(<@PFYaUr)y&fr`(aBaSpEGTwKdJdLie?#heS5aGnfuu3f>| zx0`cl59h*FoI|$zlS04fwcPH#o^!2_b0o&u(a+hJ;G7ub>>1)59_E}I;hevjb2-h~ zYrB6c_NRIWw@2Qb&XkTan*@pL2dSXUBz{eb;dI z#yFR4wYjQqDWiQG37!`Zve2j`6uIcMlvAd*)fN67&vhpw^!zJ&YZwGbTVi60?xICoLh1}L8WKL;CA<`IOopb>|FwU zHfP^CoCD`^E-vF-_H(YT;9OtDIlG3lC&0P5j&tw=&P6$&m)igAK5kE6%efHaJb93_ zFUdK4GiT3hIoIWUE^7NFIX{cyN`d>k-^bZ_Kj-ETI9KI-0xG?rZM;GpFToq9#}fn> zZPy28`{5M-TJ4Q!S=>uF2L?FTZ1-b?|D^4HhTyR6{(<0tZG2s@$0z=s-d@Hwek?3a z+xV~GyluQzaLG3QDtL0y^!^FXZQxwqKi%IG_Ta&37D{?;*Z(4BCO&N!Y}l?J#g&Kq zj_Kb9_zh|0f5qk%w(=#8XT{a$1k2{tP93B}PAEk9{Jhp5!KD2B!=`h!1 zu&jrN&2?;eu-~z4EJ5DmvHj$e6j3PUzi$z}0`X_nCfZM{n=rLbNS)MHti4i1I?_)O zMLrJf$R(`(RO>Iv=XO;LkNP3kb7?K&TW3$|hsf_psC9V(kAT}>N@kIF72or5Yx`&JwXZIQ`M zg)F3BB8G}z{G=6MtuykuNl|CTqPDN{zlOrpzMBs6A74t;LWd(HS*>vUDqOF%0$KsB zfL1^&pcT*xXa%$aS^=$qRzNGD70?Q31+)TM0j+>mKr5gX&mKr5gX&mKr5gX z&mKr5gX&mKr5gX&mKr5gX&mKr5gX&mKr5gX&mKr5gX&m zKr5gX&mKr5gX&mKr5gX&mKr5gX&mKr5gX&mKr5gX&mKr5gX z&mKr5gX&mKr5gX&mKr5gX&mKr5gX&dp~D$TLP%Ns-*yp9Hv6~mbD@SGIz zhI9ipBhBKS;WBiCu26Y;sbhs@#qng(O)peBO?Lh1?~!gG z=S9wXMUjnn%s7(ES?rDxG{}Ag{lDjYd7h2C-Xr-e4$JkYN0WC+xokXtqm;AQ%GFRZ z>Rb5(DVL46N-<~gK!ry%4B}sH`38>5ljK3|MG|kL#-lAw(}V$l5em@&P9ILm`?QTn z-$sO-K=JT?&TZcyv>^Qk;>*3mavVQPVE~mIMd{^fcwSnQ}I?0!`OSz;~ z>!Wrc44@eFg6{E%Nl5gQ=>EOXQxdw8sgy{;=r5lpaCxl8QjHt21k$4R7Bzi^#@9&< ze!YtF4j?j6Z{+^U^?1BOri&-Yk9d;O+fvD&pAv(BM3Q7&T*&EHF6?nbBk-7 z1FLJLxQjcKpM&MOZ}((@%O`0(OyUvq^8BM*5*TvYM|xIXBry1S^+TjbinqL6(ycz| zEfsN1P-qH(5ehX2ujf~WdOm>q0^unO+o=7IvpmYnfIZcdc!=_`c{@Lkhsg7!d8@#~ zmEWs&2s}vTP}jw9QnypmPgZ#~D89ONlCJ!UOOk(t;)_>EJ^7j!^AG47N|rZC`T(MT z7x>sFF!*@u&_HjMzuQQ7<0%WCe|&7t4WOBHf&4{gUaa7AruACe2}8BT5;CvhL_1KJ5XMeSwOeHT58 zMVyp>FP9JXXeac!gR64`sGsjuz4{=17x>3ee-um!{)kd4i;uFVHy1cWscb=}dW$SbMcxxBAXhJQqrg z`mPS}#Dgh;0{SgNV&lj$B9}sqv@0Gg&&@t<6VQ#A2rq^D=V(cQogYs>6KhAkq#IpU zZYJpm1d`8<;SBlQOB^guK6kVuQBYjV<3K)l4EbPy2a)YSJed8Pd~S$?MDn>~*-qti zdGgZ$4|R}CJ~zz0h~h$SINKl8OH~pM>MRrhqrS-H0WyqwBPRwI&%u(&iNXN}9g(Z0 zzmgyHMD8UXCKE?6YL(}pFJh_$1}7t?T42x{(SHcQ54t0+RbXI>m}-Ghlkw5~3CMHi zFlr}rg~k|aLt; z+BjCogR1fHQmIT%t{$B_9i`t*^H8Yvcd`+Guov#@#`d@Rr=zq-!(f^u}tSR}L z2GReT6Gi`P#)|&eG>ZP$yiD}J=H;x3`I-sRuWBZ-rsiu-b4OE+`I^bB$@!XB@zfz- za|UaAzGkWeY0#r_89hQziChcQi|30A-SsSTXZz=~GtWnG`7{0VsloGzTOsw1tw<;3 zrhxitE7HZ0LHeIBs-)vM${)E?eYqcJo{!|`VxUm|!xvVTujl7YzWfQnbF&X9m#at@ zeM9=MGkmLKe4{KGS8v!X4i^?#QsD7FQfD_;X_F6d(M>!Hamy<-XF*j^g$vR9+!)$cIrUEa13fvMc)t|jEi2#5Z$rI5B|dK>WkJtttrLH> z+{t9~y1*VP@8|KvKLnJ!hnnX3Ajz(*_8)w%r!?pv;(X25sRqQ$+_fAp*YRM5jtAH2 zcyK-S0pzW<}lZ)49XU-KdMFY-0FvuBmB`7qCODLn@}3>fwgFzgcL%fa4JdJf|O z%D+_MkqXx<+@SC%j&FCcpul$`$7|gfj&I9hBmn-g`WzaTuUYF(=J+G7k>fkuzj1u0 zdl|@n?C&&DVU+ox||w-E@w>;9k%17kR|a*L=zSJHy-Dxg2kIZ{YaL z?u{IO#hu6TSKSPb?{?>N{GaXuj=$zEik^ED5-t2o}{-p%pD?rM&I=@xVRh+D$(qb}z7S8gfCkGX{7U%UU{ zc&~d8$N%fDp}0`(M|l!sy0$RF}B>|5madl+^ua)0(P>|NxZ^f2sR!xuCBQ4eDriQF9?ek;RkJ&bWBa<_YUF2lEZxXAD=9=?>} z)gH#U6S)s~_%epy=i$p4UghDpF}%{l7?&b3aW6c{BV z9z_MlI2iFLEAZ6}qm=?LW*A%%7?edkiVKW!GU8EQ;H3=DrN07W+>F>u5Ew0w*ozPt z<7mWQhQQY_3@sCQ8O8I+n$}aiSmS)|B8POu%Q-Hv1oF8zx$797=^&weZkD@&<2SPe z^SRmXCWhbQAmM!OVs|sgmpEuZKKEAlUXJHDXh=Rc*S(+PB5P1Scd7dz!>tY)md{=0 z)^L2eg9hevZ*#YDJkLQx^SSvvcgW|iU=7aa7Pt>{`r92eJfFMLeT3t8a1Y4m-s$dS z_+1V?B%fR8?&7$Odr&^N$bFpQcDIh>t6YiWcXJQS=dO003@>);IbPy6a2z}I;CybW z+r)9=x;Xw1x0&Pjum#BHu5q7a_*w@Gk?KjhO4A7qF@R1&FV0eIsPhvRo z@K}cXd3Ykjq@WZ)&#USG4*{S67y7a=-F0ENbK) z@i6*D^x07`bnH7$aKb{>#H3XZY(L zUdM3R!|11x`%e#dF#J^yqu)mE%N|Dmjoda5qaR1^iylUQj@;)xjD8)t&w3dBJ91k* zjD8-uPkZ|yl($Zhg4>_Fr;co-f<9*`x{t)La_bLMAxB^ zjz>wI?3<$eF`Z(IB){yRhWjbl&mUex<6@8x>s5CRN%x21(Xe{h&l}EhJo;FLDI<_oL>=byz52f5X;aBU~;}~ypTD`<4NqcP_GdV)q z*ZL-DpUI(hC}$_R_TwLMhv2hyK+yjf$-?Y-$_L4pGu=sCavUw~Nt#6u;!)fz zmo(}+ZNN{f?=w`N;WxR2>%FHQnR6z0qs#c$Te+7XV!5$Z%4PXbjn4Wi<=R!wSvp?` zIbIjYu`m1@ScU$+l*=7rxxdlU%%RBjj|Wlih2Zm>4wBD5t3rQY^y`OJ%Jn3l7oy## z_o3Y{1RW>!fsW9geDWap7?xXKrCeX+cGn@6yS+-ef26$s`j>QE=!uSyU)TJT(f{y4 z(*L%9GWzd5Nc!J+5cG#~JLe$Ey%7ET6G6NC(%(+0LVr)?UI_Yc3Fz;s-@FiXEbjvy zp&lGjg^xYaAC|+*1cx%N??1$HPaI;o#}A_13n8C39He~iKM49m`F!^f%iVK`<^Hou zxqqZzT;B&i6UjV3!hC2l&1?>4-tqA&?d?mySzD!CPkajHxu#0FzSOts5X)UxrQAQ# zzCQNnR6hSmIvxn<=!yR?gdMpjprbGP^ZF|C?1}zR@6J5La<4kXa+9i*>q*`rolRBB z_0+x>LO!bl`Se6bNPoTx{XMn&g`j^)Kz~nkg!Dg6M=tv654;fc&kgAB3;%yrh5l^2 zV_7bC{{4(Wx(=r6bV;MEkA>^3I7g51rS2!``qy*8^Yrc%kDY^!hw1v8tp^Sly2{u@ zqR@0BR{3Zh@CuG9&iR5qdw-yeO&kitY1?daW}W&PT5^qbUDw_twDY@mt`+5GWXiqg zQNl+!=LhLV&o-`&&daWqA8|?7m6r?swI7!Bq)lR5Uo-xJudg~aw!AbpMb74z0g%n|Ns00(w|OUPwvouQWXB8-5ZHtJ+-qM zzTX}I-;>mz4WF$~hx+klT2JcjIo8MRxz`8nXC^n$y&<2Yvzgl8!uD{wFwEY!FnzG| z@+kkw<8!p1A^Xh5bL-zqfoe#4>$_nzS9VZ!U5|Ih-&sJn>*yE}R#Y=avpUl$G0gd@bsE ziuXnAxy8WuQp#s=JQUbSjzx)Q5*|p_&ZlGliH^NL3qFFvrqP6)0^ZX@h>M~p)}FX1 z?`@>~)93nLXRLP0@-aQcKfE7I)%f%CkRMta%J1IqrgVGyGvgoV1!sWwEB#VEG(AFk zCo#*~3mEf%!`D+Bmj81=C-@FJf#;8z^zoXG@eJ*oL2y{_S18@;3-RCn6{!qvIZ;7x{rVr29uz@`DfP5#Yn#zeqXySy2w_xYg?U z3*j^Tz+?12nMt3k_@Bt6uhsPbqjb**EJ4&_hDQe%2K|=;3)8d`A%BhA*tQi|~Z}fjq$H4ViS~TL-0Alk=67ZunC^ z)arX5gIojQ&DRXk_a%N?@2`Ze#8(rk<)YheuUu%KOuj6e-*IN zE$3k5{jHGiaz07UD~0JLqMObuvpqAsX#dYRUCt|o`Eg>w?w1JDi3CcQ^Ge3wVv!Ol zK^bE4ie9f9`Kxdka+5e$HxDVKhyev2Ymbp*>@`s z_zwhU`H1v$XrKu5y)%%T+0U$hgL1V*hxt#%!KE8Sv|;ie2~xNhxBzns;sv; zu;137P;ZDYU(=uaQ=#VRXNf(m?>5ez&GmG*W3S|Nv15Jl*JctO+3{u@8b`tW&jQ&Y z1mhe0BdUhSm%E7O@?3uG`C#+#ZtvL#djAJ1U*O(Ocsr#$?r+#n={P_3Ntc4u-x{h2HEuD~6Gy z0REtz_)XEZO%1}6YJ8kDE9IB@wcz9YfREtY-2r{($C|wHd@jj3nWuaud&zvA2MSXC zxBEGO{~hnT?45X4T=cHX%G#bSXCX!8*nas{F@9fq8U0W{+Rn>unT99ie~a3=M9YaC@#93>%Dwld}UdV3%V_n1Ygpk=ichJGw+c9-Iup7#M8^) z@vinQ6Et7lE`Dz3$inkt+lk@e#~m~V#d=$3J8_=2)6VCWr*d|;r9onU zE^wH@wPPi=b(Y!-6h2AfEf}OJSpQl~bc25D=b($*p>&#jk*}Vf%_F`dK2P~k*7oB0 zcs$QZe?Cv!y`_y3DU^-A(-nTV#HKg3mutH6cQMuTZ&2E z#~68z`j{V8>Z{;$w!SG+elbP$^gr|y@p;A%}S+etABhCFP*k%*Sa0gD&Rdg#w#Az#mj;{Q>+2 zYtGa9%k>0M@O&gb)f0T4@~gH1Pl-nXNOZ~7@RHMgPk+8x=_oJc$9|m0IC*Dg{DbL( z-9IKX{@wVJ)PJ!40eT9gfY#0e21W|mdW?RIul!u~5#>*PDb_RP-bB;$@+&nTh@oKX zpJt~}?rhX6!>ua})Owe3cHh3HE5H@Xce|t;zs;`OJ_hjpC#{Rx`#2`Ya!JZzeuH%) ztal+`+#Q8j^%CW;8JY9v0c_nG?F9t|T4O-4_Q#uKe8##Wo}m0X%7gs@ghcPhOs*C< zt6v90*V~^XUGMJ;T_*{hHa=ziuh-5QEYHzCH1U#4rJ>ed@CBw2;|(NPpm{uUfG_Vs z{Ya#cj1_?=^8`K^zKo|Lp}eMte9?QUY+e)6g&MuQ0=gE2bm@8hZt{8_`7%4KzX!fF zO_Gj3a+>hV-V^cnxim<6?V0+#ff!D~_zF25|K>{ncr-mPtKEit`h|9(9;NBIjx$NK z+{c&9mV5fLdRyKg`Axpozspbt3XGrZsQGbrFQ~mAk=>_#%{1wdX1D!)egVC2r>g~k zm%8(_DPKgdQa(ui#s_Opp+@X@tnb?-L+d%C-S3*%`yG1UpxNJeg5a}$ZT-O3nXEl_ zzaZ#)E7^I|!)!b4KEDF3gCRgpXJq7r@eX)?Krf6~du^Qc?Se2V^aanidco6|@?Q(f z*K@UA&x$7sT<9+=S-rLAivb@0o{8OyXz!UQ|7{;HQ9ZYI7xb=agR9L8|NTvsdVe~R zh?BYX(g zkKnqQ+-?0QY1DmY+ppJi8MYsmG%BCrv{LZzO+5!be=el+RKc6-iS+AKzr{Y;zGhaR zW3}6?HaRTm#^Fiq>CDu7=02n`l1@@n9V-!~>22&z*ly_hFt3p2tIa%#YP^F>V+6 z6#7XFI}g3Y`<}Oj{gm2A$0(St-;+m_JugM~-q2I>PZn|H^!mJR=XKz(QWbnoXKzNn z#}Oa8jj!fU3=_QVdLGEeqi*L1r%S$WetV|9O_R}@l-|%E;Q7$?f(LeWc;;UE$4Kx- zr@coT+k2I^9<^TkX{Xx3HG>vp-O$ouJb z4x=yf+g3$>Sw6O@-nZAu+GWTe5)=2AwSj*2CI3f*{C>UJsRi6%OTrd3oF+>!9U6@Z(dgzoJ)hhv=uD�c^-bYB}?YD!g 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 a#eWyEwpjBiXveBD$PZKo^hKCXVN+ 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

ZfAggyy&VY!bV-*yC_vJR#KM zI8W-))o1wn{W)W;k97L}+eoLP;M*zAv$G}6bFkzaO-@`dfA5W*!kEFFJ5Iy~GDP2-~@^e^Vuq@APT>2&(|sCb_9sOaT*!e8r5uj>SC z6gM@lLOys&gX`;*Z#mvO3R#L#mt<^fhsj;1eJs!K2uBANc{tb)sQwT9ru?}T&+Z6^ zQ8wtCy1XRbF7jjTVLPye4gK!zfD?u%u5mQLIJoWeSb|JUS8Uwb2S#}~K2Q-3m}ufu!3ATk#G&ToOI^B3*#UOZ-a zFK&US@%eUm3&srZc`fj49wp@`Z|}k}!~5$NcsqpO+wogFW_V9;fww&e?~4LwynaYL zpm5-?Jt7_+XDYYgk>?AQr}5*VaIimr%y=Bqf=8a89xWaUrzocnbmL zO`Z=QEglM|7`1;frsNyf9M(d`D|Fvs`~W^{WY|2D-GUZt4D`- ztiV$~Elp~#?*;O^elHz7RVoVcp(mMNcTkMpt>foW_{#l(*R}A~P|jY=kov~YR|=;X z={bCH-RAAxzpC53z3Z2{#dYj_2aYo)p=O)|^G6~O(lzhT{c;WYO6LLMhQ(=`rUxdH zy7)caAEo%C(@}j_(Q=9JOR@dS#YpEJ+VBYUywmgSfSz%~@R)Fn;?dY+ z^|=19`3(0f2W&ngMi;)g0 zLOlLVI8S{W+HG{fxd;ysk(B=Rxt3PG4e{%;^)N@GJp1=xDW`l%efzdxy=2Cp&i^Wp zamxS7hlE4V&h-o7w4QIP@*US_8D7rkU6xip5AhU#YJjZ*jt8l~;O+POv&hHzN$C1= z_%;1?)uUYZ&IfWUdKK%cgkR%^+TEn`22D3rKPA=IYkENKZqj{;qWw)Ynu%lkg#PH~vSJHq*i z>TQ#sknY!7KmGcx^k=|ec>3$Q-`4N13jGpBR63mt#Pv_EH+`LCG5TU>{Db}yy=eO; z*k8rl!~XJk)Ylb%J5P*pDu^8LScrdH`C&>S!D zQ{Gu$Qr3O2A^n~Oe=sSleaQ67G?Axv{bKu(Q~Rp>o^ju-*+1R4oaq;x=V;e2I`4sV zu?+voD$n)E(vhWA&Q_G4rD_sXuCrE z1kQB|hvgo^1{C)zv42hU5%3Z}Br!j=%`diia_0A`zIA%UhDS=Ty6IKh#~9nW6YkI8 zoJHa1P_Ebmt}k%jl;G7@QU4m}yQErsG@M=#YeN;|*3jZYS2=Nm>w|YAHjlToWhwwT62fv+>I=>F-}?zXbigV}$%)CLfsofL<^?t?MPS zagXY^u)a?EYxou+v-oe%ok9Jje3H$(=sFhmYv*yucNFgv6wdHeeRKURpZIippQ-wL z`Z@F#!A};);QIABNGD$2zOz24MU2b!Jj0fDa2~fwDDX=sVtqf-?9VH(jvnhLq#wcW z^6n`R3h=;KnGeqsxoxfX8PhEHr7JVOb-exD4d1_!oTT{sxk{kB@=JNU*4NPU7qP!y z)6HG_dv&wES1CT27uB?#-w6FHX_tS-!NPTht8cSQ6SzQm_d2edU|9vKiY*cDId0b2<1XP`7YDO=N!+^LO#NI zKJ|A%A4;IpC(QRZq5d{JGk!NZmA@+Of?uuet9(JzO>1w};&1~dAKi8zM%nXwKL1_Y z7q&z0H!*yP|5w&z=Y-|?JftIr8KMVHCjY#VR05rhuflv-UL^UB&*htg{9!)g!TP5o z-{mWfe*?G+a`{~jzRrE+=${R_-=Ut;{a}RqZQ1v>UFn#{v4$)iDP8RzAJ`|+v#!^& zIM`0hKh5$RpO(8Ut@On>!O}+e@*GQBf0XB1`hdKX@*+#`xAX!_TR)cPTY9qoJ{1kZ z6W0~*Wa?x~E8cz{8SW{x{FHX)pJwSUODo>VRB|tWSG<#{b1bcRCsXHITJcV%&a<@Q zm89~mcqda`zO`M+)WwqjiW{_F^YTeO0#OwC`4vPul%Esr`~A7^FR<^w#CO^+Hf+UI zwRcQ&e}LbAlGaCI$MY=6>jAt^w)b&o$Y+_CLeXe=rluDH99SzV9dx3+w_2Kd1FW9r zCv`DxCA4M9VFvH}ed46aGLBq`^31#t_49q&`S=IV@R|C)2KBHhG;j{Ejd;~t;e0nBv^bULsuhV)Y84Vk} z_WWwoUu*agU*h5S53jKM@Tl+jB&X~98W4@25*uH7zi=GXwNPO)r|$=1d}CKL`%XDN z_ZH<7ko)1$^wS>xZvDz~JCW`;J?i!X{;u>{&qQ5cLVS-y{j-l`YuKLY@_x$E@{0Ob zXoFvSf~LLy$ZvdzH~;i=Tim}{VfuZ=Ne=gL$secZN$b9zxT)t2C)HhoSKPc;-tNb& zsO;5rS@BM)7T2k3{-mt=g`d;W#lj=p@{s_O^`+@i#ho4CIuH62ud5@Cr zxRzlQx~sp~PWNL3!IbX(O7~aHP`p5&fon7(Dj$AJJWS;j;^IgN!Pc( zmHK+0^e^^5>bqh5JVEUP;t}#4>l*d<>r_v~Ym|;IpOlZwmO`(XKjZ6=`TY+s#P`4t zq8yd%9xK<=;rO}<*u_Zo3C6ctzukX{^_rSC{&xR3S?~O;?ZLid$u}C`4uif$iH58G z5Bb2`LHz%SxU}>4@GNb&`|UNOLyzq0R5+v@<$#nDy}@&nXaw+3PsPEx2EH$ne2D*A z{2-Pmefiz>HuH7ydjS7a0es$@Ma~ZWA{?vGa$no;*0A4|u2>(f^gNkZD_qu>oXpyR zFX~wt;(M}u7QFCN3%;~r9=A=-Qh3Q(3MYB9mP_eqcBC}n2>GF3)tS)iAFc(yL;}xU z`id??x(k0_V{eXk842(>@9yZUd;NFp4^Gp_4tT%SGz;T#{Y!ne zASZWQ;AgUbLEbhy5}%>%r$5WT!v3J2N_b0i@Vn7hmZf_`j;=PycGI?e@x4a1L2;`XYlpe9h zpcCp0#{<4^h3&m_KJ2jFpWu2Zr1vi7zuxe?THmDm#vI)*Al{c^%Mxikmy6|NK5dA2+ey?YVj@mx0bVD;&R%*X4?E z`)-YfHRj56ZLu zX5lx&S<+N~V$D7dN#3md-o{sNRQy=(eCTt>)AeR;rv6?!NbP;;pb4TEoL~H0ym+R< zPtLLT=~~X=b!s>HkoDg57PNarzfk>?q~da>{TJu&u{Jp&Jjzi>U-AdPzXkn~+QrmA zF}@lwJ>G5do%i#)mEV)9<_r6SEe_?t+jYxI?FV#A+7Br`<|=*i{xju~`Q4tq&h80j znh)u|fN$_Q-^YOm`TXsBHG}KhkIm5U3-Ou1^c2?0hteUa01wZJVV0sm0sf{>-0xsL z2%|^7euMNo95Pahx>+3i)>f(>T(w-~sV<)-9>w;D^jL26zwG6V@9dHMv_E|OJeAtk zd&Ugs7R+b&x50U)!0R8<{r+M9kA%;_i#y>{5jePqNARf)jUBHi;e2_4BjGv z=l)_+UaV>J8^?n0D*?Z~-Q;%m#{z?|aBFqNyRUq!wxh0e=__x{;j!A%#{cDYlD^#h zn=8s2^!IV#`QZ(mKlXlB`NcX4f#Y&RemW9yF4wE!Jlylx9*d{A9Jn5H`AOE#SG?-l zZu%p9yxlGb@sRdo>5!-E?@eugZ9wS~4=SAG!qepUcu?t=T-ar4g`ZqV?+kisQ2Vj( zLNox+iW?Z^fGsfn+V?`Or|+y;@;z=UeUr1)Fvm@$Z*mq}i8xzR>3hXla1QXSIEhlt z@zhJ@U2E)+cJ`h0N=aYd(D>sOC-q1g_wUH>$<&4Vdwsj4ub6t3{XS&B!IsPh45`?Pq*{2o?B6?|4{J2 zzK#Eny>Ef9tE%$8x5;h8W27Lrgeyo&dBiJ^fC4c-2#8RFBT)&Ih?3ij&=%B$0Os^C znihmw5yL|)6*c!JZBhm`B1jc9(Lt?_I>BKyK0eJTYIPVVDmu|Y`PP3u&e`YOo3w?) z2;c9!zrxPiXYaMwUTf{O*M4)jy7XfXFUv{2!}c@C@xgp{PU;!zt?Tl$~uo@*FHi0te;z65q~+=pYT`2OZrt6@shr)B7Pg=Z>WeL<@oxF z_|;r)V?{jdt)FY+c<%-lGre;s{W8V@=mE^{*-wTKbRMUh)0177d?kSoJt#vts9kCQ zfO%ec0@-v6_bXVB1-@*$jXhb|J$%p5<_!u`-utK%q+fQgKQQdtxmC~`_0ynV@pY=v zkHC(s;(Q(H!+3|4cfE9+*@gch_^)je{54pWrSjG{FdQ!jdb-cYV4t-;2IGT1#$)p| zw4YYtoq}J>w{dbDuh9?uKO;HOJ+PcFwEssiUH+PWk&}+&BI5wcXZ^2N7P+DS?WURl zZ)2I{RpM%K|GEL`)o*jtEu(aWlALSe@~PxZ>SoU9tsCGF@9lvgx)&*c@kb^_gE9Kq zyF~V05z2r0YWVTIyiMt}9j;S3q(3iwT2Be-2miEzLgafX<;$i%%ir0)qhR_$6TPyu zFaH41OV|EGpXeSNBqhCV<XJ@U%(y_z0f6w#yavVZ8WZ5KV)`Ec)j zE4UoIU(NcwR};hD4N@=fx_W_CzY0YLBXVJVzDnXz|L%`IeSIT+6*{$@y7k8R66Gvn z`3Q6AehVhRP3Q6l>1Rm?!ge(v=|_cb%zw;6zt#!tmAkln=-DcYLjLcTs_5f-N$;k6 zn9@;u5WQD@MgHf}x^4$+H+>%!dxQJ`U^g&+qiq7@7wCNKx<*FqjflKxordvc)3U$D zyS_`lzptCaP=1%P-Uaojr-JF{9Vl{~OMYHi@Q=TjlXHDf`CpRbw~4_W%mv~@j336Q zOzKgo7x5N9w70l?AB@QNQcgFwy=kqG@8)Xqb?lAl!G~DB+8?U?A>Z%NdQb=7>P-Ar zxn)v6XS$0yv5(%h15B5CY^ORd1e+E2GV!Th8CLDO40`z~^G{ZMW%rRG3hzkGLS@4&Ag zIP34UuTb#*4d{A==*p!2mCG-buj8)b=1m1GFz@4*PPiuF6 zr^dHw`WC@c%nSZZO8oC#$*sAe7oO{wRQkp53D2u( zJx?cr(9h3nJ%jUVTF*21Gv0;ZdS+5zWPIiaVH}7SP4ANmAC~EOP3Mo?dZ7RDb$;0P zP4_Gl{MnlQ`HyT(1Gi_iH%_0Iaf+*7Gt__iI)7y2P+!+y0E1tCey7Ms_eEiyVA>g9 z*?bq`yIvtQ;Qtw39VELS;7P9h)ZNti>d!5IAX2`pD?JnC&&*N(QKx*m=a2d3@*DGe z)z+&f)IWN`P2swR?JMAYac>Lj3%>x?IF5f;f1VsDCazkOCdA+B#G`yrWA6>)`+H;Gu|jVB4Zb%! z=Vp)}dT#5l_}&-GFY7(B{}bQe9{Y~@zKrhg#P^Hc{Q!g?Eiss{q3@SE`E4Bu`3g=v z?CIa%;PC%wLP9^A51#M->_(Cw{Q1R>UIO12$v)HhBWXW$Xao3yeKR({rTtcR!5i^8 zHQ)W&n^aFe*H7!JdmYB|H9J)grt0rh3NddAdDA_89P9ccz~lDMmym&Q^>mQFd!7dLD12(&c_(R|)DV^5;8y#-`i!?uF=XJ?ehp%*B z527REnRtEvnHtF4^%48%1?L*tMJ~&TK>GPD%LTS|g0@zH59iNh51SdL^JEgXj7r!h z@}=`o47=qsed@n}4_eW1pO*h5%}?2xpW7XN z`bSX#^z*M5MDh7c^MkB^fSxxx`9a@;0il!B;Yn}VA%gD&^72xX$bUrYgLx?Qvo?Q+aS-UG_W?OwJ?ZL( zn;iQtWRahs_TuK{jOf?{siO2d_B7GoOiJfz3tCUz$LSS_5%jZpAg`eH)O|pn>Y?p# z_HWSdWc%=Q^>z~SED4?9?*-W3J}h+6J&H`fHzME74ve2Jc%Uaup9t$^``mzMZ>&EM zAMmqwbZmApuClW2jwky%0oGSq4`^HVIwDS?cW&cHKKCU@gmYM z?!$Oc%892(f8ojr>G!AfXcwq5y<@_3+5U8T-;B#G9wqu@?I@$;O?Mp_d^Y{?%0d_H zVH06MIbZlV`VHmtEsU1qkA^%(R8O@04B!4u>2F!V3GKe%!&L6T3)UaIR0IGRKhy&& zQ|IgVpguLfR&HaaaG5sBq;^GY3-r^)+ZV(8po6!X93Orc184AV5&idW6@~PhCG>8k4D|DxCG>8sQ&>Vz zmIvrNN2hulm+~LI^$i@F{N48AQF{ShpvTwt;vdw?>HQl7QC!bV4}x|n7YKt6cWe@w?m4>?A!0KbDZ3%s+PNycq3T*Sr1t<%}>`SFCSUc&FH# z`WW3xm$eI&b0Xmj>JgLE?zHo%SUaDk_OvJMe8pM2*UrB|^Gk95&)3dZ#M=3nDZkaz zd%p0++h6zx`Ea{AQRHLmjP_m+`1A>9-`dl`Q>uc;#+R-hOpzYkPi_M=8s`TNpb&JN zL|gmabg;Kxu#Z>zMehJgNI$x7O6=_OfrVf_-)7@WI*%-Ra#X#1w|$(>eg=H7c>wPK zO=tUapReWE{&U@@=(nlAwm+jK|4z%%eY$>&>Sx=ul&^lN=_T|X6uW*X_<{OA*-QMO z@AR*7pAzX3eu3R-6xj9;cGOYFM8EUN-$wrNE2TNK>v|zz+pBu z`y^&0ux`Wg8Xh_TZ15i*=lY;L#2ni9y8y=b42=R1jweXxTb?6yE`N^D`I6@doiBWj z(7D%hgwDsWer~k)pFBtC{Kj*H&ikGtbPhg~bgEzOw@gZZtbT*d8`!xxjKisGOTjP6 zQ3r?q_-)iLXLcZnDmg{@U%ocWD1Tb{hG?y1z2qe=75D*8cd@NPp}v5x*wzTlKsw@Ze|jp?1%J z`G4lOkzd8@b-vzDQjKqz0RrDfs1Bg_7UrAQ+ulol)_9)?B>m2;s6w^DJ4rcy+>kN{&&65S|8nV7*^|JXR@GrB6{QH-u z$-hye6ZKp{^+frn?h*eQwcR$%$vF1`~pVIla%Q&fcJuwR3iGKXz^MGNy-?iRSbC1}|yO{5l?S3x3J@&Lc)7$zz zw3~fZ_;2mi>}Cc3%FGsC*N^M%&O1ZC86G>&Q`zoUsor+YskhjX554;D+3NZ_7Sn?+ z)z^2oLSM%iZ>X;_4z>CK?@ip!cVA!MScPAqzTT_)s^yF*pBB;n${3v!F?}U+xt=95 z&_Bt9)b7}cWmWku=kSAmThA{C=Ui?6BX)kOF#IEt(-xh7I2pAie%d^U_W%BQY7frb zU3)Odc!TxdrHnS^`cGtETJP!Eq{5k9a+Lh}Ez&;@TVXuKb5c%19(0qQt;+?a%|syHU6iS|G!oK|C#P}&GPLjWVcEbNk8bt zju`);7vSqZy$bp({I~PTW}l7!t{-*^%Rwd*cgIeAtUuIWJBPkI{TS>S^cI{2o%`*M z-ijE){XurFfI59b5#dKG=_%I5W@7W@2hctcuO$1DZNE63lald7PWS!m{H-U$p$Ogq zAF%lAvl=juZj=u^MT8xefqx26C0SbEgUT_25~w`uth&f5&IzG8n8)@y_PGz9|a z2R*E#(5*M51)ovU>;Jddw=n2g%QJ_hX()<;-;s(E7PT`EI7Sm~Z9K z8ye=&Z)p~I_)dY_ngre={;%ID{(VvRmH3?+-=^tX1Wz$9_^lmPtH0?Bu0}(>>0dBD zbL+W@_{8$Z{vwq#;5(?^fgiUA`kx}cRnz}__@06~sduhk>TUN_*?sc!=s)}@&~*v) z#qqc53HJ29gKGNE_Q~1DK+EkB{cj?^0Pjt#|FU1##lHgStLVSwyCJ5}4M-p8zuGTkaJR{Xc~Bn_Zqy|6AwLf19@{l*P}Y z_pn5+L(-4=Et>=${-(&iP1>=yqyp~$<$0o%JN z%4h3zp03Z?{UPDH-v*_tOTxBQ61H?pnD67zwFjVQK7HK4`Z&q?LVc74Zm%Tx{9xWq z%L(S)w0!luy^_*Zu?}haIVE)Jxk#5zv(Jx_-!PYb4)yaf##7Y$8oZ%L1#ioC4m}+w z_-$hXs~_ffj!HhgAJp$uy>1hI^jic^F)#S%(@&H0#kdZYVg9RK@SW_yqd75dFGicgF}W=svZ;?mBk16ME$MA$J45S@ain>2>rc z@cv{o{Eh*p$Hl)d(pRy&mT!vkx%zfCaznqv^jh?6KD&GKZt1nyOS%tS^mgb$4*eEsXWsC=0=G#!^S0bA zaOVmRi@Gn>@6`AB|A>{-2V?G zNcYNf=#^3mFBW(nyE{R00$sH+yIW7?kw3xu80fX5$LtR~dVUk~J9=&Ra9_uIJ^N?S z=jt`z+g(MkE#E)H^t6HK3H4g=alcLu9q4~oEIsNqpZ%V^mHi2>U#Qn&zvq)P=y1zj zMdgNijnO)d_w-$+`SkkadGtE&r-uIYkC@)@y-j%^ll+UnaJj?!{$}vrroN{cytk?A zHl6k^r>1YQcRU6EeDybdxtp%Ah|}rXp;g2u$mLa3Pgnnse~S9wOm?uEU0?1)Ph);Y zsae{$-3vR9{#$?K#q__O%CmWsK>r=%Xqt|9H zO@C~@l-@I8e8s%9YkJQ_%4uojklr&9xUE6pEjJ3>S2Bz=t$T)kiuujzZx5M2y@Jd0hRx4z7kG>4 zr{B4p;i8@!^*c4*?(Nt6{EK?e|9pOm>C1=TF~6TOMSOz3f0*_uo16jXo}&IYkUXpD z|4YQ4E5Dni-X&?zbRU$!^Y|${2ruZ`9@GD3iZAHBr-A-Ee#&O(m(w1;3D~jcjjI3q zvHpuaaqW3G(pS-c%U2iEXUq?U`Y-sPhn9XpEIsNqpFMvw>;Des&wTn{Vb2M#Tkh{S zRkP=lDvwzX-G0gJ`IpEp&gG}fZOkU65u$_0@@=bv|H*r|h zcTW6Hjc?QRErO?*7yPbVnU9V=f5%m!+@LoTRF9|PpP*l?rqAD}_L0Oo&b=7dIsVBC zDldt3ocl=LPh}nFla$ZZgD#>c)aPdIAD~xV+HOW;=?8Y9&uP}@0hV*9&-)WLDp%!K zZ5;!2xaHmv(P#6!MStcScV0S=K8N#!VxON4>oz}mdlmbw_6U0YHdn7NU^WKtON=)w ze6)nV-alaHjFA6q>Z?2GG)y}svHR6GmSKBSU zhpO-dhrxWbxS>!)`LKD#G!H}19m)T^i-TR|OMioznymUdb}w3?7c3W*8%_{)tbxN^c zu$Nf3w0(4T&y49k^1qnm8T!RfFrH$5O6ooIIES`x*BgFJVBI(1Z4tZZcM9L_y)M5~ zm3f(i2MddFLJv;DL&RULrrzU%idu%|A2y z@7D``Hohs=3;n?R?=ifGIe1;W7}1AbN~GydrmcP^|Iofs!=azaKOF!3C(Ex;{@cje z)w?@L&Y9E?nVvwdOJj09Qsw#vt`4t1f#2Al1IZox29Y0N{La_-j#`P|9l5413GK@s z%k_YmTn`ZX<8p(ZU`y-n%jx&e8aZ9ea*}slOitD6_c^j-;Xb)pra#=5G$V2@i=1HZ zXGo5w59nthv3io<{cj580lr;Ec�c)81_S#_J`-J|g^j3SuC#X*p=%>3tR0&mYJ4 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

`U4zMq(AyZ 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 Result<(), BanksClientError> { let data = anchor_lang::InstructionData::data( - &gpl_nft_voter::instruction::UpdateVoterWeightRecord { + &gpl_core_voter::instruction::UpdateVoterWeightRecord { voter_weight_action, }, ); - let accounts = gpl_nft_voter::accounts::UpdateVoterWeightRecord { + let accounts = gpl_core_voter::accounts::UpdateVoterWeightRecord { registrar: registrar_cookie.address, voter_weight_record: voter_weight_record_cookie.address, }; @@ -345,7 +345,7 @@ impl CoreVoterTest { } let instructions = vec![Instruction { - program_id: gpl_nft_voter::id(), + program_id: gpl_core_voter::id(), accounts: account_metas, data, }]; @@ -364,7 +364,7 @@ impl CoreVoterTest { asset_vote_record_cookies: &Vec, ) -> Result<(), BanksClientError> { let data = - anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::RelinquishNftVote {}); + anchor_lang::InstructionData::data(&gpl_core_voter::instruction::RelinquishNftVote {}); let vote_record_key = vote_record::get_vote_record_address( &self.governance.program_id, @@ -372,7 +372,7 @@ impl CoreVoterTest { &voter_token_owner_record_cookie.address, ); - let accounts = gpl_nft_voter::accounts::RelinquishNftVote { + let accounts = gpl_core_voter::accounts::RelinquishNftVote { registrar: registrar_cookie.address, voter_weight_record: voter_weight_record_cookie.address, governance: proposal_cookie.account.governance, @@ -390,7 +390,7 @@ impl CoreVoterTest { } let relinquish_nft_vote_ix = Instruction { - program_id: gpl_nft_voter::id(), + program_id: gpl_core_voter::id(), accounts: account_metas, data, }; @@ -434,11 +434,11 @@ impl CoreVoterTest { let args = args.unwrap_or_default(); let data = - anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::ConfigureCollection { + anchor_lang::InstructionData::data(&gpl_core_voter::instruction::ConfigureCollection { weight: args.weight, }); - let accounts = gpl_nft_voter::accounts::ConfigureCollection { + let accounts = gpl_core_voter::accounts::ConfigureCollection { registrar: registrar_cookie.address, realm: registrar_cookie.account.realm, realm_authority: registrar_cookie.realm_authority.pubkey(), @@ -447,7 +447,7 @@ impl CoreVoterTest { }; let mut configure_collection_ix = Instruction { - program_id: gpl_nft_voter::id(), + program_id: gpl_core_voter::id(), accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), data, }; @@ -486,11 +486,11 @@ impl CoreVoterTest { ) -> Result, BanksClientError> { let args = args.unwrap_or_default(); - let data = anchor_lang::InstructionData::data(&gpl_nft_voter::instruction::CastNftVote { + let data = anchor_lang::InstructionData::data(&gpl_core_voter::instruction::CastNftVote { proposal: proposal_cookie.address, }); - let accounts = gpl_nft_voter::accounts::CastNftVote { + let accounts = gpl_core_voter::accounts::CastNftVote { registrar: registrar_cookie.address, voter_weight_record: voter_weight_record_cookie.address, voter_token_owner_record: voter_token_owner_record_cookie.address, @@ -526,7 +526,7 @@ impl CoreVoterTest { } let cast_nft_vote_ix = Instruction { - program_id: gpl_nft_voter::id(), + program_id: gpl_core_voter::id(), accounts: account_metas, data, }; diff --git a/programs/core-voter/tests/program_test/tools.rs b/programs/core-voter/tests/program_test/tools.rs index 77a13c8e..4db7ed52 100644 --- a/programs/core-voter/tests/program_test/tools.rs +++ b/programs/core-voter/tests/program_test/tools.rs @@ -1,5 +1,5 @@ use anchor_lang::prelude::ERROR_CODE_OFFSET; -use gpl_nft_voter::error::NftVoterError; +use gpl_core_voter::error::NftVoterError; use solana_program::instruction::InstructionError; use solana_program_test::BanksClientError; use solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}; diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 8c815bae..7a9b5ab4 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -1,5 +1,5 @@ use crate::program_test::core_voter_test::ConfigureCollectionArgs; -use gpl_nft_voter::error::NftVoterError; +use gpl_core_voter::error::NftVoterError; use program_test::core_voter_test::{CastAssetVoteArgs, CoreVoterTest}; use program_test::tools::{assert_gov_err, assert_nft_voter_err}; use solana_program_test::*; diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index 8af9a37c..3dee2542 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -1,6 +1,6 @@ use crate::program_test::core_voter_test::ConfigureCollectionArgs; -use gpl_nft_voter::error::NftVoterError; -use gpl_nft_voter::state::*; +use gpl_core_voter::error::NftVoterError; +use gpl_core_voter::state::*; use program_test::core_voter_test::CoreVoterTest; use program_test::tools::*; use solana_program_test::*; From 28ac89ff2b74263707581f873763eb61183248c6 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:26:38 +0200 Subject: [PATCH 08/18] Fixed the cast_nft_vote test --- Anchor.toml | 2 +- programs/core-voter/src/lib.rs | 2 +- programs/core-voter/tests/cast_nft_vote.rs | 2328 ++++++++--------- .../tests/program_test/core_test.rs | 10 +- 4 files changed, 1172 insertions(+), 1170 deletions(-) diff --git a/Anchor.toml b/Anchor.toml index 1c140a32..d1992ed0 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -5,7 +5,7 @@ solana_version = "1.18.18" seeds = false [programs.localnet] -core-voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" +core-voter = "Gcore62Vw7rfgmXMG8T7B9Ye2smpE35rk12RxkuMNc6a" nft_voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" gateway = "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk" solana-gateway-program = "gatem74V238djXdzWnJf94Wo1DcnuGkfijbf3AuBhfs" diff --git a/programs/core-voter/src/lib.rs b/programs/core-voter/src/lib.rs index 4d2b9871..b937994f 100644 --- a/programs/core-voter/src/lib.rs +++ b/programs/core-voter/src/lib.rs @@ -11,7 +11,7 @@ pub mod tools; use crate::state::*; -declare_id!("GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw"); +declare_id!("Gcore62Vw7rfgmXMG8T7B9Ye2smpE35rk12RxkuMNc6a"); #[program] pub mod core_voter { diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 8c0ad98d..e99c2498 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -27,96 +27,13 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { .with_max_voter_weight_record(®istrar_cookie) .await?; - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - let asset_cookie1 = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - core_voter_test.bench.advance_clock().await; - let clock = core_voter_test.bench.get_clock().await; - - // Act - let asset_vote_record_cookies = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await?; - - // Assert - let asset_vote_record = core_voter_test - .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) - .await; - - assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); - - let voter_weight_record = core_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record.voter_weight, 10); - assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); - assert_eq!( - voter_weight_record.weight_action, - Some(VoterWeightAction::CastVote.into()) - ); - assert_eq!( - voter_weight_record.weight_action_target, - Some(proposal_cookie.address) - ); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - core_voter_test .with_collection( ®istrar_cookie, @@ -129,8 +46,6 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -145,16 +60,6 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - let asset_cookie2 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - core_voter_test.bench.advance_clock().await; let clock = core_voter_test.bench.get_clock().await; @@ -167,29 +72,23 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> &proposal_cookie, &voter_cookie, &voter_token_owner_record_cookie, - &[&asset_cookie1, &asset_cookie2], + &[&asset_cookie1], None, ) .await?; // Assert - let asset_vote_record1 = core_voter_test + let asset_vote_record = core_voter_test .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) .await; - assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - - let asset_vote_record2 = core_voter_test - .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) - .await; - - assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; - assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight, 10); assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); assert_eq!( voter_weight_record.weight_action, @@ -203,1062 +102,1163 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> Ok(()) } -#[tokio::test] -async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await?; - - core_voter_test.bench.advance_clock().await; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - let voter_cookie2 = core_voter_test.bench.with_wallet().await; - - // Act - - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie2, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - // Create NFT without verified collection - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, None) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let voter_cookie2 = core_voter_test.bench.with_wallet().await; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie: program_test::governance_test::RealmCookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let collection_cookie2 = core_voter_test.core.with_collection().await?; - - let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::CollectionNotFound); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie, &asset_cookie], - None, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let mut asset_cookies = vec![]; - - for _ in 0..5 { - core_voter_test.bench.advance_clock().await; - let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - asset_cookies.push(asset_cookie) - } - - core_voter_test.bench.advance_clock().await; - let clock = core_voter_test.bench.get_clock().await; - - // Act - let asset_vote_record_cookies = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &asset_cookies.iter().collect::>(), - None, - ) - .await?; - - // Assert - let asset_vote_record1 = core_voter_test - .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) - .await; - - assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - - let asset_vote_record2 = core_voter_test - .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) - .await; - - assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); - - let voter_weight_record = core_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record.voter_weight, 50); - assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); - assert_eq!( - voter_weight_record.weight_action, - Some(VoterWeightAction::CastVote.into()) - ); - assert_eq!( - voter_weight_record.weight_action_target, - Some(proposal_cookie.address) - ); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - core_voter_test.bench.advance_clock().await; - let clock = core_voter_test.bench.get_clock().await; - - let args = CastAssetVoteArgs { - cast_spl_gov_vote: false, - }; - - core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - Some(args), - ) - .await?; - - let asset_cookie2 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - // Act - - core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie2], - None, - ) - .await?; - - // Assert - - let voter_weight_record = core_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record.voter_weight, 20); - assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); - assert_eq!( - voter_weight_record.weight_action, - Some(VoterWeightAction::CastVote.into()) - ); - assert_eq!( - voter_weight_record.weight_action_target, - Some(proposal_cookie.address) - ); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted_error( -) -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - let args = CastAssetVoteArgs { - cast_spl_gov_vote: false, - }; - - core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - Some(args), - ) - .await?; - - // Act - - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( -) -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - let args = CastAssetVoteArgs { - cast_spl_gov_vote: false, - }; - - // Cast vote with NFT - let asset_vote_record_cookies = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - Some(args), - ) - .await?; - - core_voter_test.bench.advance_clock().await; - - // Try relinquish NftVoteRecords to accumulate vote - core_voter_test - .relinquish_nft_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &asset_vote_record_cookies, - ) - .await?; - - // Act - - core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await?; - - // Assert - - let voter_weight_record = core_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record.voter_weight, 10); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - core_voter_test.bench.advance_clock().await; - - let delegate_cookie = core_voter_test.bench.with_wallet().await; - core_voter_test - .governance - .set_governance_delegate( - &realm_cookie, - &voter_token_owner_record_cookie, - &voter_cookie, - &Some(delegate_cookie.address), - ) - .await; - - // Act - let asset_vote_record_cookies = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &delegate_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await?; - - // Assert - let asset_vote_record = core_voter_test - .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) - .await; - - assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); - - Ok(()) -} - -#[tokio::test] -async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error( -) -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - // Try to update VoterWeightRecord for different governing_token_owner - let voter_cookie2 = core_voter_test.bench.with_wallet().await; - let voter_weight_record_cookie2 = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie2) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - // Act - - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie2, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); - - Ok(()) -} +// #[tokio::test] +// async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// let asset_cookie2 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// core_voter_test.bench.advance_clock().await; +// let clock = core_voter_test.bench.get_clock().await; + +// // Act +// let asset_vote_record_cookies = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1, &asset_cookie2], +// None, +// ) +// .await?; + +// // Assert +// let asset_vote_record1 = core_voter_test +// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) +// .await; + +// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); + +// let asset_vote_record2 = core_voter_test +// .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) +// .await; + +// assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); + +// let voter_weight_record = core_voter_test +// .get_voter_weight_record(&voter_weight_record_cookie.address) +// .await; + +// assert_eq!(voter_weight_record.voter_weight, 20); +// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); +// assert_eq!( +// voter_weight_record.weight_action, +// Some(VoterWeightAction::CastVote.into()) +// ); +// assert_eq!( +// voter_weight_record.weight_action_target, +// Some(proposal_cookie.address) +// ); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// None, +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await?; + +// core_voter_test.bench.advance_clock().await; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// None, +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// let voter_cookie2 = core_voter_test.bench.with_wallet().await; + +// // Act + +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie2, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// // Create NFT without verified collection +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, None) +// .await?; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let voter_cookie2 = core_voter_test.bench.with_wallet().await; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) +// .await?; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie: program_test::governance_test::RealmCookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let collection_cookie2 = core_voter_test.core.with_collection().await?; + +// let asset_cookie = core_voter_test +// .core +// .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) +// .await?; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::CollectionNotFound); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// None, +// ) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let asset_cookie = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie, &asset_cookie], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert + +// assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// // Act +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let mut asset_cookies = vec![]; + +// for _ in 0..5 { +// core_voter_test.bench.advance_clock().await; +// let asset_cookie = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// asset_cookies.push(asset_cookie) +// } + +// core_voter_test.bench.advance_clock().await; +// let clock = core_voter_test.bench.get_clock().await; + +// // Act +// let asset_vote_record_cookies = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &asset_cookies.iter().collect::>(), +// None, +// ) +// .await?; + +// // Assert +// let asset_vote_record1 = core_voter_test +// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) +// .await; + +// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); + +// let asset_vote_record2 = core_voter_test +// .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) +// .await; + +// assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); + +// let voter_weight_record = core_voter_test +// .get_voter_weight_record(&voter_weight_record_cookie.address) +// .await; + +// assert_eq!(voter_weight_record.voter_weight, 50); +// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); +// assert_eq!( +// voter_weight_record.weight_action, +// Some(VoterWeightAction::CastVote.into()) +// ); +// assert_eq!( +// voter_weight_record.weight_action_target, +// Some(proposal_cookie.address) +// ); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// core_voter_test.bench.advance_clock().await; +// let clock = core_voter_test.bench.get_clock().await; + +// let args = CastAssetVoteArgs { +// cast_spl_gov_vote: false, +// }; + +// core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// Some(args), +// ) +// .await?; + +// let asset_cookie2 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// // Act + +// core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie2], +// None, +// ) +// .await?; + +// // Assert + +// let voter_weight_record = core_voter_test +// .get_voter_weight_record(&voter_weight_record_cookie.address) +// .await; + +// assert_eq!(voter_weight_record.voter_weight, 20); +// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); +// assert_eq!( +// voter_weight_record.weight_action, +// Some(VoterWeightAction::CastVote.into()) +// ); +// assert_eq!( +// voter_weight_record.weight_action_target, +// Some(proposal_cookie.address) +// ); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted_error( +// ) -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// let args = CastAssetVoteArgs { +// cast_spl_gov_vote: false, +// }; + +// core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// Some(args), +// ) +// .await?; + +// // Act + +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( +// ) -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// Some(ConfigureCollectionArgs { +// weight: 10, +// size: 20, +// }), +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// let args = CastAssetVoteArgs { +// cast_spl_gov_vote: false, +// }; + +// // Cast vote with NFT +// let asset_vote_record_cookies = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// Some(args), +// ) +// .await?; + +// core_voter_test.bench.advance_clock().await; + +// // Try relinquish NftVoteRecords to accumulate vote +// core_voter_test +// .relinquish_nft_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &asset_vote_record_cookies, +// ) +// .await?; + +// // Act + +// core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await?; + +// // Assert + +// let voter_weight_record = core_voter_test +// .get_voter_weight_record(&voter_weight_record_cookie.address) +// .await; + +// assert_eq!(voter_weight_record.voter_weight, 10); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// None, +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// let voter_weight_record_cookie = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// core_voter_test.bench.advance_clock().await; + +// let delegate_cookie = core_voter_test.bench.with_wallet().await; +// core_voter_test +// .governance +// .set_governance_delegate( +// &realm_cookie, +// &voter_token_owner_record_cookie, +// &voter_cookie, +// &Some(delegate_cookie.address), +// ) +// .await; + +// // Act +// let asset_vote_record_cookies = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &delegate_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await?; + +// // Assert +// let asset_vote_record = core_voter_test +// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) +// .await; + +// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error( +// ) -> Result<(), TransportError> { +// // Arrange +// let mut core_voter_test = CoreVoterTest::start_new().await; + +// let realm_cookie = core_voter_test.governance.with_realm().await?; + +// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + +// let collection_cookie = core_voter_test.core.with_collection().await?; + +// let max_voter_weight_record_cookie = core_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// core_voter_test +// .with_collection( +// ®istrar_cookie, +// &collection_cookie, +// &max_voter_weight_record_cookie, +// None, +// ) +// .await?; + +// let voter_cookie = core_voter_test.bench.with_wallet().await; + +// let voter_token_owner_record_cookie = core_voter_test +// .governance +// .with_token_owner_record(&realm_cookie, &voter_cookie) +// .await?; + +// // Try to update VoterWeightRecord for different governing_token_owner +// let voter_cookie2 = core_voter_test.bench.with_wallet().await; +// let voter_weight_record_cookie2 = core_voter_test +// .with_voter_weight_record(®istrar_cookie, &voter_cookie2) +// .await?; + +// let proposal_cookie = core_voter_test +// .governance +// .with_proposal(&realm_cookie) +// .await?; + +// let asset_cookie1 = core_voter_test +// .core +// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) +// .await?; + +// // Act + +// let err = core_voter_test +// .cast_asset_vote( +// ®istrar_cookie, +// &voter_weight_record_cookie2, +// &max_voter_weight_record_cookie, +// &proposal_cookie, +// &voter_cookie, +// &voter_token_owner_record_cookie, +// &[&asset_cookie1], +// None, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert +// assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); + +// Ok(()) +// } diff --git a/programs/core-voter/tests/program_test/core_test.rs b/programs/core-voter/tests/program_test/core_test.rs index 13ca914d..c9fad36b 100644 --- a/programs/core-voter/tests/program_test/core_test.rs +++ b/programs/core-voter/tests/program_test/core_test.rs @@ -40,6 +40,7 @@ impl CoreTest { #[allow(dead_code)] pub async fn with_collection(&self) -> Result { + let update_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); // Create collection @@ -60,7 +61,7 @@ impl CoreTest { // instruction accounts let create_coll_ix_accounts = mpl_core::instructions::CreateCollectionV2 { collection: coll_keypair.pubkey(), - update_authority: Some(coll_authority.pubkey()), + update_authority: Some(update_authority), payer, system_program: system_program::ID, }; @@ -71,7 +72,7 @@ impl CoreTest { self.bench .process_transaction( &[create_coll_ix], - Some(&[&coll_keypair, &coll_authority]), + Some(&[&coll_keypair]), ) .await?; @@ -88,6 +89,7 @@ impl CoreTest { asset_owner_cookie: &WalletCookie, collection: Option ) -> Result { + let collection_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); // Create Asset @@ -109,7 +111,7 @@ impl CoreTest { let create_accounts = mpl_core::instructions::CreateV2 { asset: asset_keypair.pubkey(), collection, - authority: Some(collection_cookie.authority.pubkey()), + authority: Some(collection_authority), payer, owner: Some(asset_owner_cookie.address), update_authority: None, @@ -123,7 +125,7 @@ impl CoreTest { self.bench .process_transaction( &[create_ix], - Some(&[&asset_keypair, &collection_cookie.authority]), + Some(&[&asset_keypair]), ) .await?; From 3bdcde04a2aae357d113c5e3e65d0ce30fc90651 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:10:35 +0200 Subject: [PATCH 09/18] Fixed the fetching of accounts (Thanks to Tony's hunch) --- programs/core-voter/tests/cast_nft_vote.rs | 3 +++ programs/core-voter/tests/program_test/core_voter_test.rs | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index e99c2498..4588fa44 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -76,6 +76,9 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { None, ) .await?; + + println!("Asset Vote Record Address: {:?}", asset_vote_record_cookies[0].address); + println!("Asset Vote Record Account: {:?}", asset_vote_record_cookies[0].account); // Assert let asset_vote_record = core_voter_test diff --git a/programs/core-voter/tests/program_test/core_voter_test.rs b/programs/core-voter/tests/program_test/core_voter_test.rs index 5ccef041..9577797f 100644 --- a/programs/core-voter/tests/program_test/core_voter_test.rs +++ b/programs/core-voter/tests/program_test/core_voter_test.rs @@ -520,7 +520,7 @@ impl CoreVoterTest { }; asset_vote_record_cookies.push(AssetVoteRecordCookie { - address: asset_voter_cookie.address, + address: proposal_cookie.address, account, }) } @@ -563,6 +563,7 @@ impl CoreVoterTest { .await?; Ok(asset_vote_record_cookies) + } #[allow(dead_code)] From 857e61d89979715a886ced0d4a4ec2e1d4f93251 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:21:45 +0200 Subject: [PATCH 10/18] Address used was still the wrong one, now it's the right one --- programs/core-voter/src/state/nft_vote_record.rs | 2 +- programs/core-voter/tests/cast_nft_vote.rs | 3 --- programs/core-voter/tests/program_test/core_voter_test.rs | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/programs/core-voter/src/state/nft_vote_record.rs b/programs/core-voter/src/state/nft_vote_record.rs index 95742fd4..04c5a662 100644 --- a/programs/core-voter/src/state/nft_vote_record.rs +++ b/programs/core-voter/src/state/nft_vote_record.rs @@ -34,7 +34,7 @@ pub struct AssetVoteRecord { impl AssetVoteRecord { /// sha256("account:AssetVoteRecord")[..8] - pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [137, 6, 55, 139, 251, 126, 254, 99]; + pub const ACCOUNT_DISCRIMINATOR: [u8; 8] = [14, 166, 191, 239, 186, 156, 140, 83]; } impl AccountMaxSize for AssetVoteRecord {} diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 4588fa44..e99c2498 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -76,9 +76,6 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { None, ) .await?; - - println!("Asset Vote Record Address: {:?}", asset_vote_record_cookies[0].address); - println!("Asset Vote Record Account: {:?}", asset_vote_record_cookies[0].account); // Assert let asset_vote_record = core_voter_test diff --git a/programs/core-voter/tests/program_test/core_voter_test.rs b/programs/core-voter/tests/program_test/core_voter_test.rs index 9577797f..7f24b331 100644 --- a/programs/core-voter/tests/program_test/core_voter_test.rs +++ b/programs/core-voter/tests/program_test/core_voter_test.rs @@ -520,7 +520,7 @@ impl CoreVoterTest { }; asset_vote_record_cookies.push(AssetVoteRecordCookie { - address: proposal_cookie.address, + address: nft_vote_record_key, account, }) } From 34dc316980201e90830b0ef0563d33eb7415b454 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 12:37:02 +0200 Subject: [PATCH 11/18] Updated cast_nft_vote tests --- programs/core-voter/tests/cast_nft_vote.rs | 2323 ++++++++++---------- 1 file changed, 1163 insertions(+), 1160 deletions(-) diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index e99c2498..d896f033 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -102,1163 +102,1166 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { Ok(()) } -// #[tokio::test] -// async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// let asset_cookie2 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// core_voter_test.bench.advance_clock().await; -// let clock = core_voter_test.bench.get_clock().await; - -// // Act -// let asset_vote_record_cookies = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1, &asset_cookie2], -// None, -// ) -// .await?; - -// // Assert -// let asset_vote_record1 = core_voter_test -// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) -// .await; - -// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - -// let asset_vote_record2 = core_voter_test -// .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) -// .await; - -// assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); - -// let voter_weight_record = core_voter_test -// .get_voter_weight_record(&voter_weight_record_cookie.address) -// .await; - -// assert_eq!(voter_weight_record.voter_weight, 20); -// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); -// assert_eq!( -// voter_weight_record.weight_action, -// Some(VoterWeightAction::CastVote.into()) -// ); -// assert_eq!( -// voter_weight_record.weight_action_target, -// Some(proposal_cookie.address) -// ); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// None, -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await?; - -// core_voter_test.bench.advance_clock().await; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// None, -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// let voter_cookie2 = core_voter_test.bench.with_wallet().await; - -// // Act - -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie2, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// // Create NFT without verified collection -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, None) -// .await?; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let voter_cookie2 = core_voter_test.bench.with_wallet().await; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) -// .await?; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie: program_test::governance_test::RealmCookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let collection_cookie2 = core_voter_test.core.with_collection().await?; - -// let asset_cookie = core_voter_test -// .core -// .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) -// .await?; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::CollectionNotFound); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// None, -// ) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let asset_cookie = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie, &asset_cookie], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert - -// assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// // Act -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let mut asset_cookies = vec![]; - -// for _ in 0..5 { -// core_voter_test.bench.advance_clock().await; -// let asset_cookie = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// asset_cookies.push(asset_cookie) -// } - -// core_voter_test.bench.advance_clock().await; -// let clock = core_voter_test.bench.get_clock().await; - -// // Act -// let asset_vote_record_cookies = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &asset_cookies.iter().collect::>(), -// None, -// ) -// .await?; - -// // Assert -// let asset_vote_record1 = core_voter_test -// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) -// .await; - -// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); - -// let asset_vote_record2 = core_voter_test -// .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) -// .await; - -// assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); - -// let voter_weight_record = core_voter_test -// .get_voter_weight_record(&voter_weight_record_cookie.address) -// .await; - -// assert_eq!(voter_weight_record.voter_weight, 50); -// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); -// assert_eq!( -// voter_weight_record.weight_action, -// Some(VoterWeightAction::CastVote.into()) -// ); -// assert_eq!( -// voter_weight_record.weight_action_target, -// Some(proposal_cookie.address) -// ); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// core_voter_test.bench.advance_clock().await; -// let clock = core_voter_test.bench.get_clock().await; - -// let args = CastAssetVoteArgs { -// cast_spl_gov_vote: false, -// }; - -// core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// Some(args), -// ) -// .await?; - -// let asset_cookie2 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// // Act - -// core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie2], -// None, -// ) -// .await?; - -// // Assert - -// let voter_weight_record = core_voter_test -// .get_voter_weight_record(&voter_weight_record_cookie.address) -// .await; - -// assert_eq!(voter_weight_record.voter_weight, 20); -// assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); -// assert_eq!( -// voter_weight_record.weight_action, -// Some(VoterWeightAction::CastVote.into()) -// ); -// assert_eq!( -// voter_weight_record.weight_action_target, -// Some(proposal_cookie.address) -// ); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted_error( -// ) -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// let args = CastAssetVoteArgs { -// cast_spl_gov_vote: false, -// }; - -// core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// Some(args), -// ) -// .await?; - -// // Act - -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish( -// ) -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// Some(ConfigureCollectionArgs { -// weight: 10, -// size: 20, -// }), -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// let args = CastAssetVoteArgs { -// cast_spl_gov_vote: false, -// }; - -// // Cast vote with NFT -// let asset_vote_record_cookies = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// Some(args), -// ) -// .await?; - -// core_voter_test.bench.advance_clock().await; - -// // Try relinquish NftVoteRecords to accumulate vote -// core_voter_test -// .relinquish_nft_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &asset_vote_record_cookies, -// ) -// .await?; - -// // Act - -// core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await?; - -// // Assert - -// let voter_weight_record = core_voter_test -// .get_voter_weight_record(&voter_weight_record_cookie.address) -// .await; - -// assert_eq!(voter_weight_record.voter_weight, 10); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// None, -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// let voter_weight_record_cookie = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// core_voter_test.bench.advance_clock().await; - -// let delegate_cookie = core_voter_test.bench.with_wallet().await; -// core_voter_test -// .governance -// .set_governance_delegate( -// &realm_cookie, -// &voter_token_owner_record_cookie, -// &voter_cookie, -// &Some(delegate_cookie.address), -// ) -// .await; - -// // Act -// let asset_vote_record_cookies = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &delegate_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await?; - -// // Assert -// let asset_vote_record = core_voter_test -// .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) -// .await; - -// assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error( -// ) -> Result<(), TransportError> { -// // Arrange -// let mut core_voter_test = CoreVoterTest::start_new().await; - -// let realm_cookie = core_voter_test.governance.with_realm().await?; - -// let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - -// let collection_cookie = core_voter_test.core.with_collection().await?; - -// let max_voter_weight_record_cookie = core_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// core_voter_test -// .with_collection( -// ®istrar_cookie, -// &collection_cookie, -// &max_voter_weight_record_cookie, -// None, -// ) -// .await?; - -// let voter_cookie = core_voter_test.bench.with_wallet().await; - -// let voter_token_owner_record_cookie = core_voter_test -// .governance -// .with_token_owner_record(&realm_cookie, &voter_cookie) -// .await?; - -// // Try to update VoterWeightRecord for different governing_token_owner -// let voter_cookie2 = core_voter_test.bench.with_wallet().await; -// let voter_weight_record_cookie2 = core_voter_test -// .with_voter_weight_record(®istrar_cookie, &voter_cookie2) -// .await?; - -// let proposal_cookie = core_voter_test -// .governance -// .with_proposal(&realm_cookie) -// .await?; - -// let asset_cookie1 = core_voter_test -// .core -// .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) -// .await?; - -// // Act - -// let err = core_voter_test -// .cast_asset_vote( -// ®istrar_cookie, -// &voter_weight_record_cookie2, -// &max_voter_weight_record_cookie, -// &proposal_cookie, -// &voter_cookie, -// &voter_token_owner_record_cookie, -// &[&asset_cookie1], -// None, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert -// assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); - -// Ok(()) -// } +#[tokio::test] +async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + let asset_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; + + // Act + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1, &asset_cookie2], + None, + ) + .await?; + + // Assert + let asset_vote_record1 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) + .await; + + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); + + let asset_vote_record2 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) + .await; + + assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); + + let voter_weight_record = core_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie: program_test::program_test_bench::WalletCookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await?; + + core_voter_test.bench.advance_clock().await; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + + // Act + + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie2, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_gov_err(err, GovernanceError::GoverningTokenOwnerOrDelegateMustSign); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + // Create NFT without verified collection + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, None) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::VoterDoesNotOwnNft); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie: program_test::governance_test::RealmCookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie: program_test::program_test_bench::WalletCookie = core_voter_test.bench.with_wallet().await; + + let collection_cookie2 = core_voter_test.core.with_collection().await?; + + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::CollectionNotFound); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie, &asset_cookie], + None, + ) + .await + .err() + .unwrap(); + + // Assert + + assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let mut asset_cookies = vec![]; + + for _ in 0..5 { + core_voter_test.bench.advance_clock().await; + let asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + asset_cookies.push(asset_cookie) + } + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; + + // Act + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &asset_cookies.iter().collect::>(), + None, + ) + .await?; + + // Assert + let asset_vote_record1 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) + .await; + + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record1); + + let asset_vote_record2 = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[1].address) + .await; + + assert_eq!(asset_vote_record_cookies[1].account, asset_vote_record2); + + let voter_weight_record = core_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 50); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + let asset_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + core_voter_test.bench.advance_clock().await; + let clock = core_voter_test.bench.get_clock().await; + + let args = CastAssetVoteArgs { + cast_spl_gov_vote: false, + }; + + core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + Some(args), + ) + .await?; + + // Act + core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie2], + None, + ) + .await?; + + // Assert + + let voter_weight_record = core_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 20); + assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); + assert_eq!( + voter_weight_record.weight_action, + Some(VoterWeightAction::CastVote.into()) + ); + assert_eq!( + voter_weight_record.weight_action_target, + Some(proposal_cookie.address) + ); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let args = CastAssetVoteArgs { + cast_spl_gov_vote: false, + }; + + core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + Some(args), + ) + .await?; + + // Act + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::NftAlreadyVoted); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwiched_relinquish() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: 10, + size: 20, + }), + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + let args = CastAssetVoteArgs { + cast_spl_gov_vote: false, + }; + + // Cast vote with NFT + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + Some(args), + ) + .await?; + + core_voter_test.bench.advance_clock().await; + + // Try relinquish NftVoteRecords to accumulate vote + core_voter_test + .relinquish_nft_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &asset_vote_record_cookies, + ) + .await?; + + // Act + + core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await?; + + // Assert + + let voter_weight_record = core_voter_test + .get_voter_weight_record(&voter_weight_record_cookie.address) + .await; + + assert_eq!(voter_weight_record.voter_weight, 10); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + let voter_weight_record_cookie = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + core_voter_test.bench.advance_clock().await; + + let delegate_cookie = core_voter_test.bench.with_wallet().await; + core_voter_test + .governance + .set_governance_delegate( + &realm_cookie, + &voter_token_owner_record_cookie, + &voter_cookie, + &Some(delegate_cookie.address), + ) + .await; + + // Act + let asset_vote_record_cookies = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie, + &max_voter_weight_record_cookie, + &proposal_cookie, + &delegate_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await?; + + // Assert + let asset_vote_record = core_voter_test + .get_asset_vote_record_account(&asset_vote_record_cookies[0].address) + .await; + + assert_eq!(asset_vote_record_cookies[0].account, asset_vote_record); + + Ok(()) +} + +#[tokio::test] +async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error() -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let collection_cookie = core_voter_test.core.with_collection().await?; + + let max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie, + &max_voter_weight_record_cookie, + None, + ) + .await?; + + let voter_token_owner_record_cookie = core_voter_test + .governance + .with_token_owner_record(&realm_cookie, &voter_cookie) + .await?; + + // Try to update VoterWeightRecord for different governing_token_owner + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + + let voter_weight_record_cookie2 = core_voter_test + .with_voter_weight_record(®istrar_cookie, &voter_cookie2) + .await?; + + let proposal_cookie = core_voter_test + .governance + .with_proposal(&realm_cookie) + .await?; + + // Act + + let err = core_voter_test + .cast_asset_vote( + ®istrar_cookie, + &voter_weight_record_cookie2, + &max_voter_weight_record_cookie, + &proposal_cookie, + &voter_cookie, + &voter_token_owner_record_cookie, + &[&asset_cookie1], + None, + ) + .await + .err() + .unwrap(); + + // Assert + assert_nft_voter_err(err, NftVoterError::InvalidTokenOwnerForVoterWeightRecord); + + Ok(()) +} From 002f314f5f27067ece3c6d11abf888a10bd237f9 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:18:25 +0200 Subject: [PATCH 12/18] Fixed all cast_nft_vote tests --- programs/core-voter/src/state/registrar.rs | 2 +- programs/core-voter/tests/cast_nft_vote.rs | 148 +----------------- .../core-voter/tests/relinquish_nft_vote.rs | 60 ++++--- 3 files changed, 35 insertions(+), 175 deletions(-) diff --git a/programs/core-voter/src/state/registrar.rs b/programs/core-voter/src/state/registrar.rs index b77f933d..64767b36 100644 --- a/programs/core-voter/src/state/registrar.rs +++ b/programs/core-voter/src/state/registrar.rs @@ -129,7 +129,7 @@ pub fn resolve_nft_vote_weight_and_mint( let collection_config = registrar.get_collection_config(collection)?; - assert!(collection_config.collection == collection, NftVoterError::InvalidNftCollection); + require!(collection_config.collection == collection, NftVoterError::InvalidNftCollection); Ok((collection_config.weight, nft_mint)) } diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index d896f033..45dcd84f 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -355,77 +355,6 @@ async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), Transport Ok(()) } -#[tokio::test] -async fn test_cast_asset_vote_with_unverified_collection_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - // Create NFT without verified collection - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, None) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[&asset_cookie1], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); - - Ok(()) -} - #[tokio::test] async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), TransportError> { // Arrange @@ -510,13 +439,18 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; let voter_cookie: program_test::program_test_bench::WalletCookie = core_voter_test.bench.with_wallet().await; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let _random_asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; let asset_cookie = core_voter_test .core @@ -640,76 +574,6 @@ async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError Ok(()) } -#[tokio::test] -async fn test_cast_asset_vote_with_no_nft_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let voter_token_owner_record_cookie = core_voter_test - .governance - .with_token_owner_record(&realm_cookie, &voter_cookie) - .await?; - - let voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - let proposal_cookie = core_voter_test - .governance - .with_proposal(&realm_cookie) - .await?; - - // Act - let err = core_voter_test - .cast_asset_vote( - ®istrar_cookie, - &voter_weight_record_cookie, - &max_voter_weight_record_cookie, - &proposal_cookie, - &voter_cookie, - &voter_token_owner_record_cookie, - &[], - None, - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); - - Ok(()) -} - #[tokio::test] async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { // Arrange diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 7a9b5ab4..f3d8d941 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -23,6 +23,13 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -32,8 +39,6 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -48,11 +53,6 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, @@ -69,7 +69,6 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { core_voter_test.bench.advance_clock().await; // Act - core_voter_test .relinquish_nft_vote( ®istrar_cookie, @@ -116,6 +115,13 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -125,8 +131,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -141,11 +145,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, @@ -172,7 +171,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T core_voter_test.bench.advance_clock().await; // Act - core_voter_test .relinquish_nft_vote( ®istrar_cookie, @@ -185,7 +183,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T .await?; // Assert - let voter_weight_record = core_voter_test .get_voter_weight_record(&voter_weight_record_cookie.address) .await; @@ -220,6 +217,13 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -229,8 +233,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -245,11 +247,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, @@ -264,7 +261,6 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e .await?; // Act - let err = core_voter_test .relinquish_nft_vote( ®istrar_cookie, @@ -299,6 +295,13 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -308,8 +311,6 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -324,11 +325,6 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, From e2a1d8b6c3577fd4b6b1b1048740efb4680bf4af Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 13:44:11 +0200 Subject: [PATCH 13/18] Missing to fix 1 test in `relinquish_nft_vote` and 2 tests in `update_voter_weight_record` --- .../core-voter/tests/relinquish_nft_vote.rs | 51 +++--- .../tests/update_voter_weight_record.rs | 172 +++++++----------- 2 files changed, 87 insertions(+), 136 deletions(-) diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index f3d8d941..3c2ac16c 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -202,8 +202,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T } #[tokio::test] -async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error( -) -> Result<(), TransportError> { +async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -364,8 +363,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans } #[tokio::test] -async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> -{ +async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -379,6 +377,13 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -391,8 +396,6 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -407,11 +410,6 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let args = CastAssetVoteArgs { cast_spl_gov_vote: false, }; @@ -453,8 +451,7 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< } #[tokio::test] -async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( -) -> Result<(), TransportError> { +async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -468,6 +465,13 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -477,8 +481,6 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -493,11 +495,6 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, @@ -554,6 +551,13 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -563,8 +567,6 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let voter_token_owner_record_cookie = core_voter_test .governance .with_token_owner_record(&realm_cookie, &voter_cookie) @@ -579,11 +581,6 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> .with_proposal(&realm_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - let asset_vote_record_cookies = core_voter_test .cast_asset_vote( ®istrar_cookie, diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index 3dee2542..d208c05b 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -23,6 +23,13 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, @@ -35,17 +42,10 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - core_voter_test.bench.advance_clock().await; let clock = core_voter_test.bench.get_clock().await; @@ -92,6 +92,18 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + let asset_cookie2 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, @@ -104,22 +116,10 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - let asset_cookie2 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - core_voter_test.bench.advance_clock().await; let clock = core_voter_test.bench.get_clock().await; @@ -165,6 +165,13 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -177,17 +184,10 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - // Act let err = core_voter_test .update_voter_weight_record( @@ -220,6 +220,19 @@ async fn test_update_voter_weight_with_unverified_collection_error() -> Result<( let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _random_asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + + // Create NFT without verified collection + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, None) + .await?; core_voter_test .with_collection( @@ -233,18 +246,10 @@ async fn test_update_voter_weight_with_unverified_collection_error() -> Result<( ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - // Create NFT without verified collection - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, None) - .await?; - // Act let err = core_voter_test .update_voter_weight_record( @@ -278,6 +283,15 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let voter_cookie2 = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -290,19 +304,10 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let voter_cookie2 = core_voter_test.bench.with_wallet().await; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) - .await?; - // Act let err = core_voter_test .update_voter_weight_record( @@ -332,10 +337,19 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, @@ -348,19 +362,10 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; - - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie.collection)) - .await?; - // Act let err = core_voter_test .update_voter_weight_record( @@ -390,78 +395,26 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - None, - ) - .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - let asset_cookie = core_voter_test .core .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) .await?; - // Act - let err = core_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - VoterWeightAction::CreateProposal, - &[&asset_cookie, &asset_cookie], - ) - .await - .err() - .unwrap(); - - // Assert - - assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); - - Ok(()) -} - -#[tokio::test] -async fn test_update_voter_weight_record_with_no_nft_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; - let _collection_config_cookie = core_voter_test + core_voter_test .with_collection( ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + None, ) .await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; - let mut voter_weight_record_cookie = core_voter_test .with_voter_weight_record(®istrar_cookie, &voter_cookie) .await?; @@ -472,14 +425,15 @@ async fn test_update_voter_weight_record_with_no_nft_error() -> Result<(), Trans ®istrar_cookie, &mut voter_weight_record_cookie, VoterWeightAction::CreateProposal, - &[], + &[&asset_cookie, &asset_cookie], ) .await .err() .unwrap(); // Assert - assert_nft_voter_err(err, NftVoterError::InvalidNftAmount); + + assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); Ok(()) -} +} \ No newline at end of file From 40deb34adb539bf3b4a97fb8093343ae09626dc4 Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 16:36:35 +0200 Subject: [PATCH 14/18] Fixed the `update_voter_weight_record` tests --- .../tests/update_voter_weight_record.rs | 69 ++----------------- 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index d208c05b..0d7a676e 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -206,68 +206,6 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( Ok(()) } -#[tokio::test] -async fn test_update_voter_weight_with_unverified_collection_error() -> Result<(), TransportError> { - // Arrange - let mut core_voter_test = CoreVoterTest::start_new().await; - - let realm_cookie = core_voter_test.governance.with_realm().await?; - - let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - - let collection_cookie = core_voter_test.core.with_collection().await?; - - let max_voter_weight_record_cookie = core_voter_test - .with_max_voter_weight_record(®istrar_cookie) - .await?; - - let voter_cookie = core_voter_test.bench.with_wallet().await; - - let _random_asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - - // Create NFT without verified collection - let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, None) - .await?; - - core_voter_test - .with_collection( - ®istrar_cookie, - &collection_cookie, - &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), - ) - .await?; - - let mut voter_weight_record_cookie = core_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - // Act - let err = core_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - VoterWeightAction::CreateGovernance, - &[&asset_cookie1], - ) - .await - .err() - .unwrap(); - - // Assert - assert_nft_voter_err(err, NftVoterError::CollectionMustBeVerified); - - Ok(()) -} - #[tokio::test] async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), TransportError> { // Arrange @@ -345,11 +283,16 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let voter_cookie = core_voter_test.bench.with_wallet().await; - let asset_cookie1 = core_voter_test + let _random_asset_cookie = core_voter_test .core .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie.collection)) .await?; + let asset_cookie1 = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .await?; + core_voter_test .with_collection( ®istrar_cookie, From d8cfb1938d21afa2b3bce76245ca1e4f218644cb Mon Sep 17 00:00:00 2001 From: L0STE <125566964+L0STE@users.noreply.github.com> Date: Tue, 30 Jul 2024 21:09:56 +0200 Subject: [PATCH 15/18] Fixed configure_collection tests --- .../core-voter/tests/configure_collection.rs | 92 +++++++++++++++++-- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index 1caf0bf1..89bf96ae 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -21,6 +21,13 @@ async fn test_configure_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; let collection_cookie = core_voter_test.core.with_collection().await?; + + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -32,7 +39,8 @@ async fn test_configure_collection() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - None, + Some(ConfigureCollectionArgs { weight: 1, size: 1 }), + ) .await?; @@ -74,6 +82,22 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { let collection_cookie1 = core_voter_test.core.with_collection().await?; let collection_cookie2 = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + for _ in 0..5 { + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie1, &voter_cookie, Some(collection_cookie1.collection)) + .await?; + } + + for _ in 0..10 { + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .await?; + } + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; @@ -131,16 +155,24 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { .await?; // Act + let voter_cookie = core_voter_test.bench.with_wallet().await; for _ in 0..registrar_cookie.max_collections { let collection_cookie = core_voter_test.core.with_collection().await?; + for _ in 0..3 { + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + } + core_voter_test .with_collection( ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - None, + Some(ConfigureCollectionArgs { weight: 1, size: 3 }), ) .await?; } @@ -176,6 +208,15 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + for _ in 0..10 { + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + } + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; @@ -233,6 +274,13 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; @@ -262,8 +310,7 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran } #[tokio::test] -async fn test_configure_collection_with_realm_authority_must_sign_error( -) -> Result<(), TransportError> { +async fn test_configure_collection_with_realm_authority_must_sign_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -273,6 +320,13 @@ async fn test_configure_collection_with_realm_authority_must_sign_error( let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; @@ -299,8 +353,7 @@ async fn test_configure_collection_with_realm_authority_must_sign_error( } #[tokio::test] -async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> -{ +async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -310,6 +363,13 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; @@ -338,8 +398,7 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul } #[tokio::test] -async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( -) -> Result<(), TransportError> { +async fn test_configure_collection_with_invalid_max_voter_weight_realm_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -348,6 +407,13 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + let realm_cookie2 = core_voter_test.governance.with_realm().await?; let registrar_cookie2 = core_voter_test.with_registrar(&realm_cookie2).await?; @@ -375,8 +441,7 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( } #[tokio::test] -async fn test_configure_collection_with_invalid_max_voter_weight_mint_error( -) -> Result<(), TransportError> { +async fn test_configure_collection_with_invalid_max_voter_weight_mint_error() -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -385,6 +450,13 @@ async fn test_configure_collection_with_invalid_max_voter_weight_mint_error( let collection_cookie = core_voter_test.core.with_collection().await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _asset_cookie = core_voter_test + .core + .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .await?; + // Create Registrar for council mint realm_cookie.account.community_mint = realm_cookie.account.config.council_mint.unwrap(); let registrar_cookie2 = core_voter_test.with_registrar(&realm_cookie).await?; From cb897af7b7ba6de0d1449e32c2a5fda3c7c81277 Mon Sep 17 00:00:00 2001 From: Tony Boyle Date: Wed, 31 Jul 2024 21:07:55 +0100 Subject: [PATCH 16/18] working tests --- programs/core-voter/src/error.rs | 3 + .../src/instructions/relinquish_nft_vote.rs | 3 + programs/core-voter/tests/cast_nft_vote.rs | 28 ++++---- .../core-voter/tests/configure_collection.rs | 20 +++--- .../tests/program_test/core_test.rs | 55 +++++++++++---- .../core-voter/tests/program_test/tools.rs | 5 ++ .../core-voter/tests/relinquish_nft_vote.rs | 70 ++++++++++++++----- .../tests/update_voter_weight_record.rs | 14 ++-- 8 files changed, 137 insertions(+), 61 deletions(-) diff --git a/programs/core-voter/src/error.rs b/programs/core-voter/src/error.rs index ca3f3b24..679199f6 100644 --- a/programs/core-voter/src/error.rs +++ b/programs/core-voter/src/error.rs @@ -2,6 +2,7 @@ use anchor_lang::prelude::*; #[error_code] pub enum NftVoterError { + // 0 #[msg("Invalid Realm Authority")] InvalidRealmAuthority, @@ -32,6 +33,7 @@ pub enum NftVoterError { #[msg("Collection must be verified")] CollectionMustBeVerified, + //10 #[msg("Voter does not own NFT")] VoterDoesNotOwnNft, @@ -62,6 +64,7 @@ pub enum NftVoterError { #[msg("Invalid Proposal for NftVoteRecord")] InvalidProposalForNftVoteRecord, + // 20 #[msg("Invalid TokenOwner for NftVoteRecord")] InvalidTokenOwnerForNftVoteRecord, diff --git a/programs/core-voter/src/instructions/relinquish_nft_vote.rs b/programs/core-voter/src/instructions/relinquish_nft_vote.rs index f395b45c..5cb81688 100644 --- a/programs/core-voter/src/instructions/relinquish_nft_vote.rs +++ b/programs/core-voter/src/instructions/relinquish_nft_vote.rs @@ -92,6 +92,9 @@ pub fn relinquish_nft_vote(ctx: Context) -> Result<()> { // When vote is withdrawn in spl-gov then VoteRecord is disposed and we have to assert it doesn't exist // // If the Proposal is in any other state then we can dispose NftVoteRecords without any additional Proposal checks + + msg!("Proposal State: {:?}", proposal.state); + if proposal.state == ProposalState::Voting { let vote_record_info = &ctx.accounts.vote_record.to_account_info(); diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 45dcd84f..ff1c5630 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -21,7 +21,7 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -111,7 +111,7 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -212,7 +212,7 @@ async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -294,7 +294,7 @@ async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -364,7 +364,7 @@ async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -437,9 +437,9 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -515,7 +515,7 @@ async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -583,7 +583,7 @@ async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -686,7 +686,7 @@ async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), Transp let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -793,7 +793,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -880,7 +880,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwic let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -986,7 +986,7 @@ async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -1068,7 +1068,7 @@ async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error() -> R let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index 89bf96ae..f1ed205e 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -20,7 +20,7 @@ async fn test_configure_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -79,8 +79,8 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie1 = core_voter_test.core.with_collection().await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie1 = core_voter_test.core.with_collection(None).await?; + let collection_cookie2 = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -158,7 +158,7 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { let voter_cookie = core_voter_test.bench.with_wallet().await; for _ in 0..registrar_cookie.max_collections { - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; for _ in 0..3 { let _asset_cookie = core_voter_test @@ -206,7 +206,7 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -272,7 +272,7 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -318,7 +318,7 @@ async fn test_configure_collection_with_realm_authority_must_sign_error() -> Res let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -361,7 +361,7 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -405,7 +405,7 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error() - let realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -448,7 +448,7 @@ async fn test_configure_collection_with_invalid_max_voter_weight_mint_error() -> let mut realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; diff --git a/programs/core-voter/tests/program_test/core_test.rs b/programs/core-voter/tests/program_test/core_test.rs index c9fad36b..761c4ff4 100644 --- a/programs/core-voter/tests/program_test/core_test.rs +++ b/programs/core-voter/tests/program_test/core_test.rs @@ -2,7 +2,7 @@ use std::{str::FromStr, sync::Arc}; use anchor_lang::prelude::Pubkey; use solana_program_test::ProgramTest; -use solana_sdk::{signer::Signer, system_program, transport::TransportError, signature::Keypair}; +use solana_sdk::{signature::Keypair, signer::Signer, system_program, transport::TransportError}; use crate::program_test::program_test_bench::{ProgramTestBench, WalletCookie}; @@ -39,7 +39,7 @@ impl CoreTest { } #[allow(dead_code)] - pub async fn with_collection(&self) -> Result { + pub async fn with_collection(&self, collection_size: Option) -> Result { let update_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); @@ -70,12 +70,46 @@ impl CoreTest { let create_coll_ix = create_coll_ix_accounts.instruction(args); self.bench - .process_transaction( - &[create_coll_ix], - Some(&[&coll_keypair]), - ) + .process_transaction(&[create_coll_ix], Some(&[&coll_keypair])) .await?; + // Create 5 NFT Assets into the collection + + for i in 0..collection_size.unwrap_or(0) { + let asset_keypair = Keypair::new(); + + let name = format!("NFT{}", i); + let uri = format!("URI{}", i); + + // instruction args + let args = mpl_core::instructions::CreateV2InstructionArgs { + data_state: mpl_core::types::DataState::AccountState, + name, + uri, + plugins: None, + external_plugin_adapters: None, + }; + + // instruction accounts + let create_accounts = mpl_core::instructions::CreateV2 { + asset: asset_keypair.pubkey(), + collection: Some(coll_keypair.pubkey()), + authority: Some(payer), + payer, + owner: Some(payer), + update_authority: None, + system_program: system_program::ID, + log_wrapper: None, + }; + + // creates the instruction + let create_ix = create_accounts.instruction(args); + + self.bench + .process_transaction(&[create_ix], Some(&[&asset_keypair])) + .await?; + } + Ok(CollectionCookie { collection: coll_keypair.pubkey(), authority: coll_authority, @@ -87,7 +121,7 @@ impl CoreTest { &self, collection_cookie: &CollectionCookie, asset_owner_cookie: &WalletCookie, - collection: Option + collection: Option, ) -> Result { let collection_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); @@ -116,17 +150,14 @@ impl CoreTest { owner: Some(asset_owner_cookie.address), update_authority: None, system_program: system_program::ID, - log_wrapper: None + log_wrapper: None, }; // creates the instruction let create_ix = create_accounts.instruction(args); self.bench - .process_transaction( - &[create_ix], - Some(&[&asset_keypair]), - ) + .process_transaction(&[create_ix], Some(&[&asset_keypair])) .await?; Ok(AssetCookie { diff --git a/programs/core-voter/tests/program_test/tools.rs b/programs/core-voter/tests/program_test/tools.rs index 4db7ed52..e3c1784b 100644 --- a/programs/core-voter/tests/program_test/tools.rs +++ b/programs/core-voter/tests/program_test/tools.rs @@ -18,6 +18,11 @@ pub fn NopOverride(_: &mut T) {} pub fn assert_nft_voter_err(banks_client_error: BanksClientError, nft_locker_error: NftVoterError) { let tx_error = banks_client_error.unwrap(); + println!("banks client error: {:?}", tx_error); + println!("nft locker error: {:?}", nft_locker_error); + println!("error code offset: {:?}", ERROR_CODE_OFFSET); + println!("nft locker error as u32: {:?}", nft_locker_error as u32 + ERROR_CODE_OFFSET); + match tx_error { TransactionError::InstructionError(_, instruction_error) => match instruction_error { InstructionError::Custom(e) => { diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 3c2ac16c..0a890ad1 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -17,7 +17,7 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -27,7 +27,11 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -109,7 +113,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -119,7 +123,11 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -202,7 +210,8 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T } #[tokio::test] -async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error() -> Result<(), TransportError> { +async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_exists_error( +) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -210,7 +219,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(Some(5)).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -220,7 +229,11 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -229,6 +242,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e &collection_cookie, &max_voter_weight_record_cookie, None, + ) .await?; @@ -273,6 +287,8 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e .err() .unwrap(); + println!("{:?}", err); + // Assert assert_nft_voter_err(err, NftVoterError::VoteRecordMustBeWithdrawn); @@ -288,7 +304,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -298,7 +314,11 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -363,7 +383,8 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans } #[tokio::test] -async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> { +async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result<(), TransportError> +{ // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -371,17 +392,21 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) .await?; let voter_cookie = core_voter_test.bench.with_wallet().await; - + let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -451,7 +476,8 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< } #[tokio::test] -async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error() -> Result<(), TransportError> { +async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( +) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -459,7 +485,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error() let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -469,7 +495,11 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error() let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -545,7 +575,7 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -555,7 +585,11 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index 0d7a676e..bb96e862 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -17,7 +17,7 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -86,7 +86,7 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -159,7 +159,7 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -215,7 +215,7 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -273,9 +273,9 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -336,7 +336,7 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.with_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; From 1f0700b9bba4dbfe55da676082b08c48a636b057 Mon Sep 17 00:00:00 2001 From: Tony Boyle Date: Thu, 1 Aug 2024 00:23:14 +0100 Subject: [PATCH 17/18] adjustment --- programs/core-voter/tests/cast_nft_vote.rs | 28 ++++---- .../core-voter/tests/configure_collection.rs | 20 +++--- .../tests/program_test/core_test.rs | 39 +---------- .../core-voter/tests/relinquish_nft_vote.rs | 27 ++++++-- .../tests/update_voter_weight_record.rs | 66 ++++++++++++++----- 5 files changed, 94 insertions(+), 86 deletions(-) diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index ff1c5630..45dcd84f 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -21,7 +21,7 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -111,7 +111,7 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -212,7 +212,7 @@ async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -294,7 +294,7 @@ async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -364,7 +364,7 @@ async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -437,9 +437,9 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let collection_cookie2 = core_voter_test.core.with_collection(None).await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -515,7 +515,7 @@ async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -583,7 +583,7 @@ async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -686,7 +686,7 @@ async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), Transp let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -793,7 +793,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -880,7 +880,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwic let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -986,7 +986,7 @@ async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -1068,7 +1068,7 @@ async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error() -> R let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index f1ed205e..89bf96ae 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -20,7 +20,7 @@ async fn test_configure_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -79,8 +79,8 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie1 = core_voter_test.core.with_collection(None).await?; - let collection_cookie2 = core_voter_test.core.with_collection(None).await?; + let collection_cookie1 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -158,7 +158,7 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { let voter_cookie = core_voter_test.bench.with_wallet().await; for _ in 0..registrar_cookie.max_collections { - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; for _ in 0..3 { let _asset_cookie = core_voter_test @@ -206,7 +206,7 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -272,7 +272,7 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -318,7 +318,7 @@ async fn test_configure_collection_with_realm_authority_must_sign_error() -> Res let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -361,7 +361,7 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -405,7 +405,7 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error() - let realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; @@ -448,7 +448,7 @@ async fn test_configure_collection_with_invalid_max_voter_weight_mint_error() -> let mut realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; diff --git a/programs/core-voter/tests/program_test/core_test.rs b/programs/core-voter/tests/program_test/core_test.rs index 761c4ff4..eaf37445 100644 --- a/programs/core-voter/tests/program_test/core_test.rs +++ b/programs/core-voter/tests/program_test/core_test.rs @@ -39,7 +39,7 @@ impl CoreTest { } #[allow(dead_code)] - pub async fn with_collection(&self, collection_size: Option) -> Result { + pub async fn with_collection(&self) -> Result { let update_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); @@ -73,43 +73,6 @@ impl CoreTest { .process_transaction(&[create_coll_ix], Some(&[&coll_keypair])) .await?; - // Create 5 NFT Assets into the collection - - for i in 0..collection_size.unwrap_or(0) { - let asset_keypair = Keypair::new(); - - let name = format!("NFT{}", i); - let uri = format!("URI{}", i); - - // instruction args - let args = mpl_core::instructions::CreateV2InstructionArgs { - data_state: mpl_core::types::DataState::AccountState, - name, - uri, - plugins: None, - external_plugin_adapters: None, - }; - - // instruction accounts - let create_accounts = mpl_core::instructions::CreateV2 { - asset: asset_keypair.pubkey(), - collection: Some(coll_keypair.pubkey()), - authority: Some(payer), - payer, - owner: Some(payer), - update_authority: None, - system_program: system_program::ID, - log_wrapper: None, - }; - - // creates the instruction - let create_ix = create_accounts.instruction(args); - - self.bench - .process_transaction(&[create_ix], Some(&[&asset_keypair])) - .await?; - } - Ok(CollectionCookie { collection: coll_keypair.pubkey(), authority: coll_authority, diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 0a890ad1..6ec47a67 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -17,7 +17,7 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -113,7 +113,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -219,7 +219,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(Some(5)).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -227,6 +227,19 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let voter_cookie = core_voter_test.bench.with_wallet().await; + // Create 5 assets into collection. + for _ in 0..5 { + let _asset_cookie = core_voter_test + .core + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) + .await?; + } + + // Create and store 6th asset. This will be used for the vote. let asset_cookie1 = core_voter_test .core .with_asset( @@ -304,7 +317,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -392,7 +405,7 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -485,7 +498,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -575,7 +588,7 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index bb96e862..51205834 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -17,7 +17,7 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -27,7 +27,11 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; let _collection_config_cookie = core_voter_test @@ -67,7 +71,7 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { assert_eq!(voter_weight_record.voter_weight, 10); assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); - + assert_eq!( voter_weight_record.weight_action, Some(VoterWeightAction::CreateProposal.into()) @@ -86,7 +90,7 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -96,12 +100,20 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; let asset_cookie2 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; let _collection_config_cookie = core_voter_test @@ -159,7 +171,7 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -169,7 +181,11 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -215,7 +231,7 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -227,7 +243,11 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie2, + Some(collection_cookie.collection), + ) .await?; core_voter_test @@ -273,9 +293,9 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; - let collection_cookie2 = core_voter_test.core.with_collection(None).await?; + let collection_cookie2 = core_voter_test.core.with_collection().await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -285,12 +305,20 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let _random_asset_cookie = core_voter_test .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie2, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .with_asset( + &collection_cookie2, + &voter_cookie, + Some(collection_cookie2.collection), + ) .await?; core_voter_test @@ -336,13 +364,17 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection(None).await?; + let collection_cookie = core_voter_test.core.with_collection().await?; let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .with_asset( + &collection_cookie, + &voter_cookie, + Some(collection_cookie.collection), + ) .await?; let max_voter_weight_record_cookie = core_voter_test @@ -379,4 +411,4 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE assert_nft_voter_err(err, NftVoterError::DuplicatedNftDetected); Ok(()) -} \ No newline at end of file +} From 40a52f282d2475b53f596deea7ba5f5a77a21d99 Mon Sep 17 00:00:00 2001 From: Tony Boyle Date: Sat, 10 Aug 2024 17:57:00 +0100 Subject: [PATCH 18/18] added max_voter_weight_record tests --- .../src/instructions/configure_collection.rs | 2 + programs/core-voter/src/instructions/mod.rs | 3 + .../udpate_max_voter_weight_record.rs | 42 ++++ .../update_voter_weight_record.rs | 2 + programs/core-voter/src/lib.rs | 9 +- programs/core-voter/tests/cast_nft_vote.rs | 82 +++----- .../core-voter/tests/configure_collection.rs | 109 +++++----- .../tests/program_test/core_test.rs | 31 ++- .../tests/program_test/core_voter_test.rs | 111 ++++++++++- .../core-voter/tests/relinquish_nft_vote.rs | 73 +++---- .../tests/update_max_voter_weight_record.rs | 188 ++++++++++++++++++ .../tests/update_voter_weight_record.rs | 90 +++------ 12 files changed, 492 insertions(+), 250 deletions(-) create mode 100644 programs/core-voter/src/instructions/udpate_max_voter_weight_record.rs create mode 100644 programs/core-voter/tests/update_max_voter_weight_record.rs diff --git a/programs/core-voter/src/instructions/configure_collection.rs b/programs/core-voter/src/instructions/configure_collection.rs index 8c2e3ef6..633f8f03 100644 --- a/programs/core-voter/src/instructions/configure_collection.rs +++ b/programs/core-voter/src/instructions/configure_collection.rs @@ -74,6 +74,8 @@ pub fn configure_collection( let size = collection.current_size; + msg!("Collection size: {}", size); + require!(size > 0, NftVoterError::InvalidCollectionSize); let collection_config = CollectionConfig { diff --git a/programs/core-voter/src/instructions/mod.rs b/programs/core-voter/src/instructions/mod.rs index 518677c5..a2f73d14 100644 --- a/programs/core-voter/src/instructions/mod.rs +++ b/programs/core-voter/src/instructions/mod.rs @@ -18,3 +18,6 @@ mod relinquish_nft_vote; pub use cast_nft_vote::*; mod cast_nft_vote; + +pub use udpate_max_voter_weight_record::*; +mod udpate_max_voter_weight_record; diff --git a/programs/core-voter/src/instructions/udpate_max_voter_weight_record.rs b/programs/core-voter/src/instructions/udpate_max_voter_weight_record.rs new file mode 100644 index 00000000..2195bbc2 --- /dev/null +++ b/programs/core-voter/src/instructions/udpate_max_voter_weight_record.rs @@ -0,0 +1,42 @@ +use crate::error::NftVoterError; +use crate::state::*; +use anchor_lang::prelude::*; +use max_voter_weight_record::MaxVoterWeightRecord; + +// Takes all collections added to `register`, iterates over them and calculates +// the max voter weight +#[derive(Accounts)] +pub struct UpdateMaxVoterWeightRecord<'info> { + /// The NFT voting Registrar + pub registrar: Account<'info, Registrar>, + + #[account( + mut, + constraint = max_voter_weight_record.realm == registrar.realm + @ NftVoterError::InvalidVoterWeightRecordRealm, + + constraint = max_voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ NftVoterError::InvalidVoterWeightRecordMint, + )] + pub max_voter_weight_record: Account<'info, MaxVoterWeightRecord>, +} + +pub fn update_max_voter_weight_record(ctx: Context) -> Result<()> { + let registrar = &ctx.accounts.registrar; + + // Calculate the max voter weight by iterating over all collections and summing + // the max weight of each collection. + ctx.accounts.max_voter_weight_record.max_voter_weight = registrar + .collection_configs + .iter() + .try_fold(0u64, |sum, cc| sum.checked_add(cc.get_max_weight())) + .unwrap(); + + // Record is only valid as of the current slot + let clock = Clock::get()?.slot; + msg!("Clock: {:?}", clock); + + ctx.accounts.max_voter_weight_record.max_voter_weight_expiry = Some(Clock::get()?.slot); + + Ok(()) +} diff --git a/programs/core-voter/src/instructions/update_voter_weight_record.rs b/programs/core-voter/src/instructions/update_voter_weight_record.rs index 36158063..e422a811 100644 --- a/programs/core-voter/src/instructions/update_voter_weight_record.rs +++ b/programs/core-voter/src/instructions/update_voter_weight_record.rs @@ -74,3 +74,5 @@ pub fn update_voter_weight_record( Ok(()) } + +// takes all collections and adjusts collection weight diff --git a/programs/core-voter/src/lib.rs b/programs/core-voter/src/lib.rs index b937994f..a57fe414 100644 --- a/programs/core-voter/src/lib.rs +++ b/programs/core-voter/src/lib.rs @@ -41,14 +41,15 @@ pub mod core_voter { log_version(); instructions::update_voter_weight_record(ctx, voter_weight_action) } + pub fn update_max_voter_weight_record(ctx: Context) -> Result<()> { + log_version(); + instructions::update_max_voter_weight_record(ctx) + } pub fn relinquish_nft_vote(ctx: Context) -> Result<()> { log_version(); instructions::relinquish_nft_vote(ctx) } - pub fn configure_collection( - ctx: Context, - weight: u64, - ) -> Result<()> { + pub fn configure_collection(ctx: Context, weight: u64) -> Result<()> { log_version(); instructions::configure_collection(ctx, weight) } diff --git a/programs/core-voter/tests/cast_nft_vote.rs b/programs/core-voter/tests/cast_nft_vote.rs index 45dcd84f..e84ce01c 100644 --- a/programs/core-voter/tests/cast_nft_vote.rs +++ b/programs/core-voter/tests/cast_nft_vote.rs @@ -21,7 +21,7 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -30,8 +30,7 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -41,7 +40,6 @@ async fn test_cast_asset_vote() -> Result<(), TransportError> { &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -111,7 +109,7 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -120,13 +118,11 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; let asset_cookie2 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -136,7 +132,6 @@ async fn test_cast_asset_vote_with_multiple_nfts() -> Result<(), TransportError> &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -212,7 +207,7 @@ async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -221,8 +216,7 @@ async fn test_cast_asset_vote_with_nft_already_voted_error() -> Result<(), Trans let voter_cookie: program_test::program_test_bench::WalletCookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie,) .await?; core_voter_test @@ -294,7 +288,7 @@ async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -303,8 +297,7 @@ async fn test_cast_asset_vote_with_invalid_voter_error() -> Result<(), Transport let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -364,7 +357,7 @@ async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), Transport let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -375,8 +368,7 @@ async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), Transport let voter_cookie2 = core_voter_test.bench.with_wallet().await; let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie2, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie2) .await?; core_voter_test @@ -386,7 +378,6 @@ async fn test_cast_asset_vote_with_invalid_owner_error() -> Result<(), Transport &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -437,9 +428,9 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -448,13 +439,11 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran let voter_cookie: program_test::program_test_bench::WalletCookie = core_voter_test.bench.with_wallet().await; let _random_asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .core.create_asset(&collection_cookie2, &voter_cookie) .await?; core_voter_test @@ -464,7 +453,6 @@ async fn test_cast_asset_vote_with_invalid_collection_error() -> Result<(), Tran &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -515,7 +503,7 @@ async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -524,8 +512,7 @@ async fn test_cast_asset_vote_with_same_nft_error() -> Result<(), TransportError let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -583,7 +570,7 @@ async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -597,7 +584,7 @@ async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { core_voter_test.bench.advance_clock().await; let asset_cookie = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .create_asset(&collection_cookie, &voter_cookie) .await?; asset_cookies.push(asset_cookie) @@ -610,7 +597,6 @@ async fn test_cast_asset_vote_with_max_5_nfts() -> Result<(), TransportError> { &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -686,7 +672,7 @@ async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), Transp let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -695,13 +681,11 @@ async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), Transp let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; let asset_cookie2 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -711,7 +695,6 @@ async fn test_cast_asset_vote_using_multiple_instructions() -> Result<(), Transp &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -793,7 +776,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -802,8 +785,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -813,7 +795,6 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_nft_already_voted &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -880,7 +861,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwic let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -889,8 +870,7 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwic let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -900,7 +880,6 @@ async fn test_cast_asset_vote_using_multiple_instructions_with_attempted_sandwic &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -986,7 +965,7 @@ async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -995,8 +974,7 @@ async fn test_cast_asset_vote_using_delegate() -> Result<(), TransportError> { let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .core.create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -1068,7 +1046,7 @@ async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error() -> R let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -1078,7 +1056,7 @@ async fn test_cast_asset_vote_with_invalid_voter_weight_token_owner_error() -> R let asset_cookie1 = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test diff --git a/programs/core-voter/tests/configure_collection.rs b/programs/core-voter/tests/configure_collection.rs index 89bf96ae..13d3b0a8 100644 --- a/programs/core-voter/tests/configure_collection.rs +++ b/programs/core-voter/tests/configure_collection.rs @@ -20,13 +20,13 @@ async fn test_configure_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; - + let collection_cookie = core_voter_test.core.create_collection(None).await?; + let voter_cookie = core_voter_test.bench.with_wallet().await; let _asset_cookie = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .create_asset(&collection_cookie, &voter_cookie) .await?; let max_voter_weight_record_cookie = core_voter_test @@ -39,8 +39,7 @@ async fn test_configure_collection() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 1 }), - + Some(ConfigureCollectionArgs { weight: 1 }), ) .await?; @@ -79,22 +78,22 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie1 = core_voter_test.core.with_collection().await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie1 = core_voter_test.core.create_collection(None).await?; + let collection_cookie2 = core_voter_test.core.create_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; for _ in 0..5 { let _asset_cookie = core_voter_test .core - .with_asset(&collection_cookie1, &voter_cookie, Some(collection_cookie1.collection)) + .create_asset(&collection_cookie1, &voter_cookie) .await?; } for _ in 0..10 { let _asset_cookie = core_voter_test .core - .with_asset(&collection_cookie2, &voter_cookie, Some(collection_cookie2.collection)) + .create_asset(&collection_cookie2, &voter_cookie) .await?; } @@ -108,7 +107,7 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie1, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 5 }), + Some(ConfigureCollectionArgs { weight: 1 }), ) .await?; @@ -117,10 +116,7 @@ async fn test_configure_multiple_collections() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie2, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 2, - size: 10, - }), + Some(ConfigureCollectionArgs { weight: 2 }), ) .await?; @@ -154,25 +150,19 @@ async fn test_configure_max_collections() -> Result<(), TransportError> { .with_max_voter_weight_record(®istrar_cookie) .await?; - // Act - let voter_cookie = core_voter_test.bench.with_wallet().await; + + let _voter_cookie = core_voter_test.bench.with_wallet().await; for _ in 0..registrar_cookie.max_collections { - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(3)).await?; - for _ in 0..3 { - let _asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - } core_voter_test .with_collection( ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 3 }), + Some(ConfigureCollectionArgs { weight: 1 }), ) .await?; } @@ -206,16 +196,10 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(10)).await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; + let _voter_cookie = core_voter_test.bench.with_wallet().await; - for _ in 0..10 { - let _asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; - } let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -237,10 +221,7 @@ async fn test_configure_existing_collection() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 2, - size: 10, - }), + Some(ConfigureCollectionArgs { weight: 2 }), ) .await?; @@ -272,13 +253,13 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; let _asset_cookie = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .create_asset(&collection_cookie, &voter_cookie) .await?; let max_voter_weight_record_cookie = core_voter_test @@ -310,7 +291,8 @@ async fn test_configure_collection_with_invalid_realm_error() -> Result<(), Tran } #[tokio::test] -async fn test_configure_collection_with_realm_authority_must_sign_error() -> Result<(), TransportError> { +async fn test_configure_collection_with_realm_authority_must_sign_error( +) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -318,13 +300,13 @@ async fn test_configure_collection_with_realm_authority_must_sign_error() -> Res let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; let _asset_cookie = core_voter_test .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) + .create_asset(&collection_cookie, &voter_cookie) .await?; let max_voter_weight_record_cookie = core_voter_test @@ -353,7 +335,8 @@ async fn test_configure_collection_with_realm_authority_must_sign_error() -> Res } #[tokio::test] -async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> { +async fn test_configure_collection_with_invalid_realm_authority_error() -> Result<(), TransportError> +{ // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; @@ -361,14 +344,14 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(1)).await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; + // let voter_cookie = core_voter_test.bench.with_wallet().await; - let _asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; + // let _asset_cookie = core_voter_test + // .core + // .create_asset(&collection_cookie, &voter_cookie) + // .await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -398,21 +381,22 @@ async fn test_configure_collection_with_invalid_realm_authority_error() -> Resul } #[tokio::test] -async fn test_configure_collection_with_invalid_max_voter_weight_realm_error() -> Result<(), TransportError> { +async fn test_configure_collection_with_invalid_max_voter_weight_realm_error( +) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; let realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(1)).await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; + // let voter_cookie = core_voter_test.bench.with_wallet().await; - let _asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; + // let _asset_cookie = core_voter_test + // .core + // .create_asset(&collection_cookie, &voter_cookie) + // .await?; let realm_cookie2 = core_voter_test.governance.with_realm().await?; let registrar_cookie2 = core_voter_test.with_registrar(&realm_cookie2).await?; @@ -441,21 +425,22 @@ async fn test_configure_collection_with_invalid_max_voter_weight_realm_error() - } #[tokio::test] -async fn test_configure_collection_with_invalid_max_voter_weight_mint_error() -> Result<(), TransportError> { +async fn test_configure_collection_with_invalid_max_voter_weight_mint_error( +) -> Result<(), TransportError> { // Arrange let mut core_voter_test = CoreVoterTest::start_new().await; let mut realm_cookie = core_voter_test.governance.with_realm().await?; let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(1)).await?; - let voter_cookie = core_voter_test.bench.with_wallet().await; + // let voter_cookie = core_voter_test.bench.with_wallet().await; - let _asset_cookie = core_voter_test - .core - .with_asset(&collection_cookie, &voter_cookie, Some(collection_cookie.collection)) - .await?; + // let _asset_cookie = core_voter_test + // .core + // .create_asset(&collection_cookie, &voter_cookie) + // .await?; // Create Registrar for council mint realm_cookie.account.community_mint = realm_cookie.account.config.council_mint.unwrap(); diff --git a/programs/core-voter/tests/program_test/core_test.rs b/programs/core-voter/tests/program_test/core_test.rs index eaf37445..860cf755 100644 --- a/programs/core-voter/tests/program_test/core_test.rs +++ b/programs/core-voter/tests/program_test/core_test.rs @@ -39,7 +39,10 @@ impl CoreTest { } #[allow(dead_code)] - pub async fn with_collection(&self) -> Result { + pub async fn create_collection( + &self, + collection_size: Option, + ) -> Result { let update_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); @@ -73,6 +76,18 @@ impl CoreTest { .process_transaction(&[create_coll_ix], Some(&[&coll_keypair])) .await?; + println!("Minting {} assets to collection", collection_size.unwrap()); + if collection_size.is_some() { + self.mint_assets_to_collection( + &CollectionCookie { + collection: coll_keypair.pubkey(), + authority: coll_authority.insecure_clone(), + }, + collection_size.unwrap(), + ) + .await; + } + Ok(CollectionCookie { collection: coll_keypair.pubkey(), authority: coll_authority, @@ -80,11 +95,11 @@ impl CoreTest { } #[allow(dead_code)] - pub async fn with_asset( + pub async fn create_asset( &self, collection_cookie: &CollectionCookie, asset_owner_cookie: &WalletCookie, - collection: Option, + // collection: Option, ) -> Result { let collection_authority = self.bench.context.borrow().payer.pubkey(); let payer = self.bench.context.borrow().payer.pubkey(); @@ -107,7 +122,7 @@ impl CoreTest { // instruction accounts let create_accounts = mpl_core::instructions::CreateV2 { asset: asset_keypair.pubkey(), - collection, + collection: Some(collection_cookie.collection), authority: Some(collection_authority), payer, owner: Some(asset_owner_cookie.address), @@ -127,4 +142,12 @@ impl CoreTest { asset: asset_keypair.pubkey(), }) } + + pub async fn mint_assets_to_collection(&self, collection_cookie: &CollectionCookie, size: u64) { + let asset_owner = self.bench.with_wallet().await; + + for _ in 0..size { + let _ = self.create_asset(&collection_cookie, &asset_owner).await; + } + } } diff --git a/programs/core-voter/tests/program_test/core_voter_test.rs b/programs/core-voter/tests/program_test/core_voter_test.rs index 7f24b331..3a218595 100644 --- a/programs/core-voter/tests/program_test/core_voter_test.rs +++ b/programs/core-voter/tests/program_test/core_voter_test.rs @@ -2,16 +2,20 @@ use std::sync::Arc; use anchor_lang::prelude::{AccountMeta, Pubkey}; +use anchor_lang::system_program; use gpl_core_voter::state::max_voter_weight_record::{ get_max_voter_weight_record_address, MaxVoterWeightRecord, }; use gpl_core_voter::state::*; +use mpl_core::accounts::BaseCollectionV1; +use solana_sdk::transport::TransportError; use spl_governance::instruction::cast_vote; use spl_governance::state::vote_record::{self, Vote, VoteChoice}; use gpl_core_voter::state::{ - get_nft_vote_record_address, get_registrar_address, CollectionConfig, AssetVoteRecord, Registrar, + get_nft_vote_record_address, get_registrar_address, AssetVoteRecord, CollectionConfig, + Registrar, }; use solana_program_test::{BanksClientError, ProgramTest}; @@ -22,11 +26,13 @@ use solana_sdk::signer::Signer; use crate::program_test::governance_test::GovernanceTest; use crate::program_test::program_test_bench::ProgramTestBench; +use crate::program_test::core_test::{AssetCookie, CollectionCookie, CoreTest}; use crate::program_test::governance_test::{ProposalCookie, RealmCookie, TokenOwnerRecordCookie}; use crate::program_test::program_test_bench::WalletCookie; -use crate::program_test::core_test::{CollectionCookie, AssetCookie, CoreTest}; use crate::program_test::tools::NopOverride; +use super::core_test; + #[derive(Debug, PartialEq)] pub struct RegistrarCookie { pub address: Pubkey, @@ -36,6 +42,7 @@ pub struct RegistrarCookie { pub max_collections: u8, } + pub struct VoterWeightRecordCookie { pub address: Pubkey, pub account: VoterWeightRecord, @@ -52,12 +59,11 @@ pub struct CollectionConfigCookie { pub struct ConfigureCollectionArgs { pub weight: u64, - pub size: u32, } impl Default for ConfigureCollectionArgs { fn default() -> Self { - Self { weight: 1, size: 3 } + Self { weight: 1 } } } @@ -117,6 +123,54 @@ impl CoreVoterTest { } } + #[allow(dead_code)] + pub async fn with_asset( + &self, + collection_cookie: &CollectionCookie, + asset_owner_cookie: &WalletCookie, + ) -> Result { + let collection_authority = self.bench.context.borrow().payer.pubkey(); + let payer = self.bench.context.borrow().payer.pubkey(); + + // Create Asset + let asset_keypair = Keypair::new(); + + let name = "TestAsset".to_string(); + let uri = "URI".to_string(); + + // instruction args + let args = mpl_core::instructions::CreateV2InstructionArgs { + data_state: mpl_core::types::DataState::AccountState, + name, + uri, + plugins: None, + external_plugin_adapters: None, + }; + + // instruction accounts + let create_accounts = mpl_core::instructions::CreateV2 { + asset: asset_keypair.pubkey(), + collection: Some(collection_cookie.collection), + authority: Some(collection_authority), + payer, + owner: Some(asset_owner_cookie.address), + update_authority: None, + system_program: system_program::ID, + log_wrapper: None, + }; + + // creates the instruction + let create_ix = create_accounts.instruction(args); + + self.bench + .process_transaction(&[create_ix], Some(&[&asset_keypair])) + .await?; + + Ok(AssetCookie { + asset: asset_keypair.pubkey(), + }) + } + #[allow(dead_code)] pub async fn with_registrar( &mut self, @@ -353,6 +407,32 @@ impl CoreVoterTest { self.bench.process_transaction(&instructions, None).await } + #[allow(dead_code)] + pub async fn update_max_voter_weight_record( + &self, + registrar_cookie: &RegistrarCookie, + max_voter_weight_record_cookie: &mut MaxVoterWeightRecordCookie, + ) -> Result<(), BanksClientError> { + let data = anchor_lang::InstructionData::data( + &gpl_core_voter::instruction::UpdateMaxVoterWeightRecord {} + ); + + let accounts = gpl_core_voter::accounts::UpdateMaxVoterWeightRecord { + registrar: registrar_cookie.address, + max_voter_weight_record: max_voter_weight_record_cookie.address, + }; + + let account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); + + let instructions = vec![Instruction { + program_id: gpl_core_voter::id(), + accounts: account_metas, + data, + }]; + + self.bench.process_transaction(&instructions, None).await + } + #[allow(dead_code)] pub async fn relinquish_nft_vote( &mut self, @@ -461,9 +541,13 @@ impl CoreVoterTest { .process_transaction(&[configure_collection_ix], Some(signers)) .await?; + let collection_account = self + .get_collection_account(&collection_cookie.collection) + .await; + let collection_config = CollectionConfig { collection: collection_cookie.collection, - size: args.size, + size: collection_account.current_size, weight: args.weight, reserved: [0; 8], }; @@ -505,10 +589,8 @@ impl CoreVoterTest { for asset_cookie in asset_cookies { account_metas.push(AccountMeta::new_readonly(asset_cookie.asset, false)); - let nft_vote_record_key = get_nft_vote_record_address( - &proposal_cookie.address, - &asset_cookie.asset, - ); + let nft_vote_record_key = + get_nft_vote_record_address(&proposal_cookie.address, &asset_cookie.asset); account_metas.push(AccountMeta::new(nft_vote_record_key, false)); let account = AssetVoteRecord { @@ -563,7 +645,6 @@ impl CoreVoterTest { .await?; Ok(asset_vote_record_cookies) - } #[allow(dead_code)] @@ -572,7 +653,10 @@ impl CoreVoterTest { } #[allow(dead_code)] - pub async fn get_asset_vote_record_account(&mut self, nft_vote_record: &Pubkey) -> AssetVoteRecord { + pub async fn get_asset_vote_record_account( + &mut self, + nft_vote_record: &Pubkey, + ) -> AssetVoteRecord { self.bench .get_borsh_account::(nft_vote_record) .await @@ -592,4 +676,9 @@ impl CoreVoterTest { pub async fn get_voter_weight_record(&self, voter_weight_record: &Pubkey) -> VoterWeightRecord { self.bench.get_anchor_account(*voter_weight_record).await } + + #[allow(dead_code)] + pub async fn get_collection_account(&self, voter_weight_record: &Pubkey) -> BaseCollectionV1 { + self.bench.get_anchor_account(*voter_weight_record).await + } } diff --git a/programs/core-voter/tests/relinquish_nft_vote.rs b/programs/core-voter/tests/relinquish_nft_vote.rs index 6ec47a67..d1e2be90 100644 --- a/programs/core-voter/tests/relinquish_nft_vote.rs +++ b/programs/core-voter/tests/relinquish_nft_vote.rs @@ -17,7 +17,7 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -26,11 +26,9 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), + &voter_cookie ) .await?; @@ -39,7 +37,7 @@ async fn test_relinquish_nft_vote() -> Result<(), TransportError> { ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + Some(ConfigureCollectionArgs { weight: 1}), // Set Size == 1 to complete voting with just one vote ) .await?; @@ -113,7 +111,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -122,11 +120,9 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state() -> Result<(), T let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, &voter_cookie, - Some(collection_cookie.collection), ) .await?; @@ -219,7 +215,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(Some(5)).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -227,25 +223,11 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e let voter_cookie = core_voter_test.bench.with_wallet().await; - // Create 5 assets into collection. - for _ in 0..5 { - let _asset_cookie = core_voter_test - .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) - .await?; - } - // Create and store 6th asset. This will be used for the vote. let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), + &voter_cookie ) .await?; @@ -254,7 +236,7 @@ async fn test_relinquish_nft_vote_for_proposal_in_voting_state_and_vote_record_e ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - None, + None ) .await?; @@ -317,7 +299,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -326,11 +308,9 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, &voter_cookie, - Some(collection_cookie.collection), ) .await?; @@ -339,7 +319,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_error() -> Result<(), Trans ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + Some(ConfigureCollectionArgs { weight: 1 }), // Set Size == 1 to complete voting with just one vote ) .await?; @@ -405,7 +385,7 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -414,11 +394,9 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), + &voter_cookie ) .await?; @@ -429,7 +407,6 @@ async fn test_relinquish_nft_vote_with_unexpired_vote_weight_record() -> Result< &max_voter_weight_record_cookie, Some(ConfigureCollectionArgs { weight: 10, - size: 20, }), ) .await?; @@ -498,7 +475,7 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -507,11 +484,9 @@ async fn test_relinquish_nft_vote_with_invalid_voter_weight_token_owner_error( let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), + &voter_cookie ) .await?; @@ -588,7 +563,7 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -597,11 +572,9 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie1 = core_voter_test - .core - .with_asset( + .core.create_asset( &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), + &voter_cookie ) .await?; @@ -610,7 +583,7 @@ async fn test_relinquish_nft_vote_using_delegate() -> Result<(), TransportError> ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { weight: 1, size: 1 }), // Set Size == 1 to complete voting with just one vote + Some(ConfigureCollectionArgs { weight: 1 }), // Set Size == 1 to complete voting with just one vote ) .await?; diff --git a/programs/core-voter/tests/update_max_voter_weight_record.rs b/programs/core-voter/tests/update_max_voter_weight_record.rs new file mode 100644 index 00000000..7e095984 --- /dev/null +++ b/programs/core-voter/tests/update_max_voter_weight_record.rs @@ -0,0 +1,188 @@ +use crate::program_test::core_voter_test::ConfigureCollectionArgs; +use program_test::core_voter_test::CoreVoterTest; +use solana_program_test::*; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_update_collection_config_invalidates_max_voter_weight_record_expirey( +) -> Result<(), TransportError> { + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let _voter_cookie = core_voter_test.bench.with_wallet().await; + + let mut max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let collection_1_size = 7; + let collection_1_weight = 5; + + let collection_cookie_1 = core_voter_test + .core + .create_collection(Some(collection_1_size)) + .await?; + + // Register collection_1 to registrar + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie_1, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: collection_1_weight, + }), + ) + .await?; + + // Generate an updated new max voter weight record + core_voter_test + .update_max_voter_weight_record(®istrar_cookie, &mut max_voter_weight_record_cookie) + .await?; + + let collection_2_size = 10; + let collection_2_weight = 2; + + // Generate a new collection and update the registrar with the additional collection + // while invalidating max voter weight. + let collection_cookie_2 = core_voter_test + .core + .create_collection(Some(collection_2_size)) + .await?; + + // Register collection_2 to registrar + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie_2, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: collection_2_weight, + }), + ) + .await?; + + // Fetch registrar account and assert that collection was added to the registrars collection_configs + let registrar = core_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + let max_voter_weight_record = core_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + core_voter_test.bench.advance_clock().await; + let _clock = core_voter_test.bench.get_clock().await; + + // Assert + let max_voter_weight_total = + (collection_1_weight * collection_1_size) + (collection_2_weight * collection_2_size); + + assert!(registrar.collection_configs.len() == 2); + assert!(max_voter_weight_record.max_voter_weight_expiry.is_none()); + assert!(max_voter_weight_record.max_voter_weight == max_voter_weight_total as u64); + + Ok(()) +} + +#[tokio::test] +async fn test_update_max_voter_weight_record_provides_valid_expirey() -> Result<(), TransportError> +{ + // Arrange + let mut core_voter_test = CoreVoterTest::start_new().await; + + let realm_cookie = core_voter_test.governance.with_realm().await?; + + let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; + + let mut max_voter_weight_record_cookie = core_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voter_cookie = core_voter_test.bench.with_wallet().await; + + // Set collection sizes and weights for collection_1 + let collection_1_size = 11; + let collection_1_weight = 4; + + let collection_cookie_1 = core_voter_test + .core + .create_collection(Some(collection_1_size)) + .await?; + + // Register collection_1 to registrar + let _collection_config_cookie = core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie_1, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: collection_1_weight, + }), + ) + .await?; + + // Generate an updated new max voter weight record + core_voter_test + .update_max_voter_weight_record(®istrar_cookie, &mut max_voter_weight_record_cookie) + .await?; + + // Advance clock so that second `update_max_voter_weight_record`` can be made without a duplicate + // transaction submission which causes transaction to "pass" but not actually update the account. + + core_voter_test.bench.advance_clock().await; + let _clock = core_voter_test.bench.get_clock().await; + + // Generate a new collection and update the registrar with the additional collection + // which also invalidates max_voter_weight_expirey. + + let collection_2_size = 9; + let collection_2_weight = 3; + let collection_cookie_2 = core_voter_test + .core + .create_collection(Some(collection_2_size)) + .await?; + + // Register collection_2 to registrar + core_voter_test + .with_collection( + ®istrar_cookie, + &collection_cookie_2, + &max_voter_weight_record_cookie, + Some(ConfigureCollectionArgs { + weight: collection_2_weight, + }), + ) + .await?; + + // Revalidate max voter weight record by calling the update + let _update_max_voter_weight_record_2 = core_voter_test + .update_max_voter_weight_record(®istrar_cookie, &mut max_voter_weight_record_cookie) + .await?; + + // Fetch registrar account and assert that collection was added to the registrars collection_configs + let registrar = core_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + // Fetch max voter weight record and assert that max voter weight expiry is set + let max_voter_weight_record = core_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // Assert + let max_voter_weight_total = + (collection_1_weight * collection_1_size) + (collection_2_weight * collection_2_size); + + assert!(registrar.collection_configs.len() == 2); + assert!(max_voter_weight_record.max_voter_weight == max_voter_weight_total as u64); + assert!(max_voter_weight_record.max_voter_weight_expiry.is_some()); + + Ok(()) +} diff --git a/programs/core-voter/tests/update_voter_weight_record.rs b/programs/core-voter/tests/update_voter_weight_record.rs index 51205834..85b721da 100644 --- a/programs/core-voter/tests/update_voter_weight_record.rs +++ b/programs/core-voter/tests/update_voter_weight_record.rs @@ -4,6 +4,7 @@ use gpl_core_voter::state::*; use program_test::core_voter_test::CoreVoterTest; use program_test::tools::*; use solana_program_test::*; +use solana_sdk::msg; use solana_sdk::transport::TransportError; mod program_test; @@ -17,7 +18,7 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -27,22 +28,17 @@ async fn test_update_voter_weight_record() -> Result<(), TransportError> { let asset_cookie1 = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie) .await?; + msg!("Register the collection to the registrar"); + // Register the collection to the registrar let _collection_config_cookie = core_voter_test .with_collection( ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + Some(ConfigureCollectionArgs { weight: 10 }), ) .await?; @@ -90,7 +86,7 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -100,20 +96,12 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr let asset_cookie1 = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie) .await?; let asset_cookie2 = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie) .await?; let _collection_config_cookie = core_voter_test @@ -121,10 +109,7 @@ async fn test_update_voter_weight_with_multiple_nfts() -> Result<(), TransportEr ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + Some(ConfigureCollectionArgs { weight: 10 }), ) .await?; @@ -171,7 +156,7 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -181,11 +166,7 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( let asset_cookie1 = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie) .await?; core_voter_test @@ -193,10 +174,7 @@ async fn test_update_voter_weight_with_cast_vote_not_allowed_error() -> Result<( ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + Some(ConfigureCollectionArgs { weight: 10 }), ) .await?; @@ -231,7 +209,7 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -243,11 +221,7 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans let asset_cookie1 = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie2, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie2) .await?; core_voter_test @@ -255,10 +229,7 @@ async fn test_update_voter_weight_with_invalid_owner_error() -> Result<(), Trans ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + Some(ConfigureCollectionArgs { weight: 10 }), ) .await?; @@ -293,9 +264,9 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; - let collection_cookie2 = core_voter_test.core.with_collection().await?; + let collection_cookie2 = core_voter_test.core.create_collection(None).await?; let max_voter_weight_record_cookie = core_voter_test .with_max_voter_weight_record(®istrar_cookie) @@ -305,20 +276,12 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), let _random_asset_cookie = core_voter_test .core - .with_asset( - &collection_cookie2, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie2, &voter_cookie) .await?; let asset_cookie1 = core_voter_test .core - .with_asset( - &collection_cookie2, - &voter_cookie, - Some(collection_cookie2.collection), - ) + .create_asset(&collection_cookie2, &voter_cookie) .await?; core_voter_test @@ -326,10 +289,7 @@ async fn test_update_voter_weight_with_invalid_collection_error() -> Result<(), ®istrar_cookie, &collection_cookie, &max_voter_weight_record_cookie, - Some(ConfigureCollectionArgs { - weight: 10, - size: 20, - }), + Some(ConfigureCollectionArgs { weight: 10 }), ) .await?; @@ -364,17 +324,13 @@ async fn test_update_voter_weight_with_same_nft_error() -> Result<(), TransportE let registrar_cookie = core_voter_test.with_registrar(&realm_cookie).await?; - let collection_cookie = core_voter_test.core.with_collection().await?; + let collection_cookie = core_voter_test.core.create_collection(None).await?; let voter_cookie = core_voter_test.bench.with_wallet().await; let asset_cookie = core_voter_test .core - .with_asset( - &collection_cookie, - &voter_cookie, - Some(collection_cookie.collection), - ) + .create_asset(&collection_cookie, &voter_cookie) .await?; let max_voter_weight_record_cookie = core_voter_test

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°IHPy30iH@)KNAzdGT>rL0Jkaqua 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