// This file is autogenerated with https://github.com/acheroncrypto/native-to-anchor

use anchor_lang::prelude::*;

declare_id!("11111111111111111111111111111111");

#[program]
pub mod spl_governance {
    use super::*;

    pub fn create_realm(
        ctx: Context<CreateRealm>,
        name: String,
        config_args: RealmConfigArgs,
    ) -> Result<()> {
        Ok(())
    }

    pub fn deposit_governing_tokens(
        ctx: Context<DepositGoverningTokens>,
        amount: u64,
    ) -> Result<()> {
        Ok(())
    }

    pub fn withdraw_governing_tokens(ctx: Context<WithdrawGoverningTokens>) -> Result<()> {
        Ok(())
    }

    pub fn set_governance_delegate(
        ctx: Context<SetGovernanceDelegate>,
        new_governance_delegate: Option<Pubkey>,
    ) -> Result<()> {
        Ok(())
    }

    pub fn create_governance(
        ctx: Context<CreateGovernance>,
        config: GovernanceConfig,
    ) -> Result<()> {
        Ok(())
    }

    pub fn create_program_governance(
        ctx: Context<CreateProgramGovernance>,
        config: GovernanceConfig,
        transfer_upgrade_authority: bool,
    ) -> Result<()> {
        Ok(())
    }

    pub fn create_proposal(
        ctx: Context<CreateProposal>,
        name: String,
        description_link: String,
        vote_type: VoteType,
        options: Vec<String>,
        use_deny_option: bool,
    ) -> Result<()> {
        Ok(())
    }

    pub fn add_signatory(ctx: Context<AddSignatory>, signatory: Pubkey) -> Result<()> {
        Ok(())
    }

    pub fn remove_signatory(ctx: Context<RemoveSignatory>, signatory: Pubkey) -> Result<()> {
        Ok(())
    }

    pub fn insert_transaction(
        ctx: Context<InsertTransaction>,
        option_index: u8,
        index: u16,
        hold_up_time: u32,
        instructions: Vec<InstructionData>,
    ) -> Result<()> {
        Ok(())
    }

    pub fn remove_transaction(ctx: Context<RemoveTransaction>) -> Result<()> {
        Ok(())
    }

    pub fn cancel_proposal(ctx: Context<CancelProposal>) -> Result<()> {
        Ok(())
    }

    pub fn sign_off_proposal(ctx: Context<SignOffProposal>) -> Result<()> {
        Ok(())
    }

    pub fn cast_vote(ctx: Context<CastVote>, vote: Vote) -> Result<()> {
        Ok(())
    }

    pub fn finalize_vote(ctx: Context<FinalizeVote>) -> Result<()> {
        Ok(())
    }

    pub fn relinquish_vote(ctx: Context<RelinquishVote>) -> Result<()> {
        Ok(())
    }

    pub fn execute_transaction(ctx: Context<ExecuteTransaction>) -> Result<()> {
        Ok(())
    }

    pub fn create_mint_governance(
        ctx: Context<CreateMintGovernance>,
        config: GovernanceConfig,
        transfer_mint_authorities: bool,
    ) -> Result<()> {
        Ok(())
    }

    pub fn create_token_governance(
        ctx: Context<CreateTokenGovernance>,
        config: GovernanceConfig,
        transfer_account_authorities: bool,
    ) -> Result<()> {
        Ok(())
    }

    pub fn set_governance_config(
        ctx: Context<SetGovernanceConfig>,
        config: GovernanceConfig,
    ) -> Result<()> {
        Ok(())
    }

    pub fn flag_transaction_error(ctx: Context<FlagTransactionError>) -> Result<()> {
        Ok(())
    }

    pub fn set_realm_authority(
        ctx: Context<SetRealmAuthority>,
        action: SetRealmAuthorityAction,
    ) -> Result<()> {
        Ok(())
    }

    pub fn set_realm_config(
        ctx: Context<SetRealmConfig>,
        config_args: RealmConfigArgs,
    ) -> Result<()> {
        Ok(())
    }

    pub fn create_token_owner_record(ctx: Context<CreateTokenOwnerRecord>) -> Result<()> {
        Ok(())
    }

    pub fn update_program_metadata(ctx: Context<UpdateProgramMetadata>) -> Result<()> {
        Ok(())
    }

    pub fn create_native_treasury(ctx: Context<CreateNativeTreasury>) -> Result<()> {
        Ok(())
    }
}

#[derive(Accounts)]
pub struct CreateRealm<'info> {
    #[account(mut)]
    realm_address: AccountInfo<'info>,
    realm_authority: AccountInfo<'info>,
    community_token_mint: AccountInfo<'info>,
    #[account(mut)]
    community_token_holding_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
    token_program: Program<'info, Token>,
    rent: Sysvar<'info, Rent>,
    // optional_council_token_mint: AccountInfo<'info>,
    // #[account(mut)]
    // optional_council_token_holding_address: AccountInfo<'info>,
    // optional_community_voter_weight_addin: Signer<'info>,
    // optional_max_community_voter_weight_addin: Signer<'info>,
    // #[account(mut)]
    // optional_realm_config_address: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct DepositGoverningTokens<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    governing_token_holding_address: AccountInfo<'info>,
    #[account(mut)]
    governing_token_source: AccountInfo<'info>,
    governing_token_owner: Signer<'info>,
    governing_token_transfer_authority: Signer<'info>,
    #[account(mut)]
    token_owner_record_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
    token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct WithdrawGoverningTokens<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    governing_token_holding_address: AccountInfo<'info>,
    #[account(mut)]
    governing_token_destination: AccountInfo<'info>,
    governing_token_owner: Signer<'info>,
    #[account(mut)]
    token_owner_record_address: AccountInfo<'info>,
    token_program: Program<'info, Token>,
}

#[derive(Accounts)]
pub struct SetGovernanceDelegate<'info> {
    governance_authority: Signer<'info>,
    #[account(mut)]
    vote_record_address: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct CreateGovernance<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    governance_address: AccountInfo<'info>,
    governed_account_address: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
    create_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateProgramGovernance<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    program_governance_address: AccountInfo<'info>,
    governed_program: AccountInfo<'info>,
    #[account(mut)]
    governed_program_data_address: AccountInfo<'info>,
    governed_program_upgrade_authority: Signer<'info>,
    token_owner_record: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    bpf_loader_upgradeable: AccountInfo<'info>,
    system_program: Program<'info, System>,
    create_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateProposal<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    proposal_address: AccountInfo<'info>,
    #[account(mut)]
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal_owner_record: AccountInfo<'info>,
    governing_token_mint: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct AddSignatory<'info> {
    #[account(mut)]
    proposal: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    signatory_record_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct RemoveSignatory<'info> {
    #[account(mut)]
    proposal: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    signatory_record_address: AccountInfo<'info>,
    #[account(mut)]
    beneficiary: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct InsertTransaction<'info> {
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    proposal_transaction_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
    rent: Sysvar<'info, Rent>,
}

#[derive(Accounts)]
pub struct RemoveTransaction<'info> {
    #[account(mut)]
    proposal: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    proposal_transaction: AccountInfo<'info>,
    #[account(mut)]
    beneficiary: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct CancelProposal<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    #[account(mut)]
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    #[account(mut)]
    proposal_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct SignOffProposal<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    #[account(mut)]
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    signatory: Signer<'info>,
    // optional_proposal_owner_record: AccountInfo<'info>,
    // #[account(mut)]
    // optional_signatory_record_address: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct CastVote<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    #[account(mut)]
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    #[account(mut)]
    proposal_owner_record: AccountInfo<'info>,
    #[account(mut)]
    voter_token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    vote_record_address: AccountInfo<'info>,
    vote_governing_token_mint: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct FinalizeVote<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    #[account(mut)]
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    #[account(mut)]
    proposal_owner_record: AccountInfo<'info>,
    governing_token_mint: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct RelinquishVote<'info> {
    realm: AccountInfo<'info>,
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    #[account(mut)]
    token_owner_record: AccountInfo<'info>,
    #[account(mut)]
    vote_record_address: AccountInfo<'info>,
    vote_governing_token_mint: AccountInfo<'info>,
    // optional_governance_authority: Signer<'info>,
    // #[account(mut)]
    // optional_beneficiary: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct ExecuteTransaction<'info> {
    governance: AccountInfo<'info>,
    #[account(mut)]
    proposal: AccountInfo<'info>,
    #[account(mut)]
    proposal_transaction: AccountInfo<'info>,
    instruction_program: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct CreateMintGovernance<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    mint_governance_address: AccountInfo<'info>,
    #[account(mut)]
    governed_mint: AccountInfo<'info>,
    governed_mint_authority: Signer<'info>,
    token_owner_record: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    token_program: Program<'info, Token>,
    system_program: Program<'info, System>,
    create_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateTokenGovernance<'info> {
    realm: AccountInfo<'info>,
    #[account(mut)]
    token_governance_address: AccountInfo<'info>,
    #[account(mut)]
    governed_token: AccountInfo<'info>,
    governed_token_owner: Signer<'info>,
    token_owner_record: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    token_program: Program<'info, Token>,
    system_program: Program<'info, System>,
    create_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct SetGovernanceConfig<'info> {
    #[account(mut)]
    governance: Signer<'info>,
}

#[derive(Accounts)]
pub struct FlagTransactionError<'info> {
    #[account(mut)]
    proposal: AccountInfo<'info>,
    token_owner_record: AccountInfo<'info>,
    governance_authority: Signer<'info>,
    #[account(mut)]
    proposal_transaction: AccountInfo<'info>,
}

#[derive(Accounts)]
pub struct SetRealmAuthority<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    realm_authority: Signer<'info>,
    // optional_new_realm_authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct SetRealmConfig<'info> {
    #[account(mut)]
    realm: AccountInfo<'info>,
    realm_authority: Signer<'info>,
    // optional_council_token_mint: AccountInfo<'info>,
    // #[account(mut)]
    // optional_council_token_holding_address: AccountInfo<'info>,
    // optional_system_program: Program<'info, System>,
    // #[account(mut)]
    // optional_realm_config_address: AccountInfo<'info>,
    // optional_community_voter_weight_addin: Signer<'info>,
    // optional_max_community_voter_weight_addin: Signer<'info>,
    // #[account(mut)]
    // optional_payer: Signer<'info>,
}

#[derive(Accounts)]
pub struct CreateTokenOwnerRecord<'info> {
    realm: AccountInfo<'info>,
    governing_token_owner: AccountInfo<'info>,
    #[account(mut)]
    token_owner_record_address: AccountInfo<'info>,
    governing_token_mint: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct UpdateProgramMetadata<'info> {
    #[account(mut)]
    program_metadata_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct CreateNativeTreasury<'info> {
    governance: AccountInfo<'info>,
    #[account(mut)]
    native_treasury_address: AccountInfo<'info>,
    #[account(mut)]
    payer: Signer<'info>,
    system_program: Program<'info, System>,
}

#[account]
pub struct RealmV2 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Community mint
    pub community_mint: Pubkey,

    /// Configuration of the Realm
    pub config: RealmConfig,

    /// Reserved space for future versions
    pub reserved: [u8; 6],

    /// The number of proposals in voting state in the Realm
    pub voting_proposal_count: u16,

    /// Realm authority. The authority must sign transactions which update the realm config
    /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals
    pub authority: Option<Pubkey>,

    /// Governance Realm name
    pub name: String,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 128],
}

#[account]
pub struct ProposalV2 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Governance account the Proposal belongs to
    pub governance: Pubkey,

    /// Indicates which Governing Token is used to vote on the Proposal
    /// Whether the general Community token owners or the Council tokens owners vote on this Proposal
    pub governing_token_mint: Pubkey,

    /// Current proposal state
    pub state: ProposalState,

    // TODO: add state_at timestamp to have single field to filter recent proposals in the UI
    /// The TokenOwnerRecord representing the user who created and owns this Proposal
    pub token_owner_record: Pubkey,

    /// The number of signatories assigned to the Proposal
    pub signatories_count: u8,

    /// The number of signatories who already signed
    pub signatories_signed_off_count: u8,

    /// Vote type
    pub vote_type: VoteType,

    /// Proposal options
    pub options: Vec<ProposalOption>,

    /// The total weight of the Proposal rejection votes
    /// If the proposal has no deny option then the weight is None
    /// Only proposals with the deny option can have executable instructions attached to them
    /// Without the deny option a proposal is only non executable survey
    pub deny_vote_weight: Option<u64>,

    /// Reserved space for future versions
    /// This field is a leftover from unused veto_vote_weight: Option<u64>
    pub reserved1: u8,

    /// The total weight of  votes
    /// Note: Abstain is not supported in the current version
    pub abstain_vote_weight: Option<u64>,

    /// Optional start time if the Proposal should not enter voting state immediately after being signed off
    /// Note: start_at is not supported in the current version
    pub start_voting_at: Option<i64>,

    /// When the Proposal was created and entered Draft state
    pub draft_at: i64,

    /// When Signatories started signing off the Proposal
    pub signing_off_at: Option<i64>,

    /// When the Proposal began voting as UnixTimestamp
    pub voting_at: Option<i64>,

    /// When the Proposal began voting as Slot
    /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights
    pub voting_at_slot: Option<u64>,

    /// When the Proposal ended voting and entered either Succeeded or Defeated
    pub voting_completed_at: Option<i64>,

    /// When the Proposal entered Executing state
    pub executing_at: Option<i64>,

    /// When the Proposal entered final state Completed or Cancelled and was closed
    pub closed_at: Option<i64>,

    /// Instruction execution flag for ordered and transactional instructions
    /// Note: This field is not used in the current version
    pub execution_flags: InstructionExecutionFlags,

    /// The max vote weight for the Governing Token mint at the time Proposal was decided
    /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed
    /// after vote was completed.
    pub max_vote_weight: Option<u64>,

    /// Max voting time for the proposal if different from parent Governance  (only higher value possible)
    /// Note: This field is not used in the current version
    pub max_voting_time: Option<u32>,

    /// The vote threshold at the time Proposal was decided
    /// It's used to show correct vote results for historical proposals in cases when the threshold
    /// was changed for governance config after vote was completed.
    /// TODO: Use this field to override the threshold from parent Governance (only higher value possible)
    pub vote_threshold: Option<VoteThreshold>,

    /// Reserved space for future versions
    pub reserved: [u8; 64],

    /// Proposal name
    pub name: String,

    /// Link to proposal's description
    pub description_link: String,

    /// The total weight of Veto votes
    pub veto_vote_weight: u64,
}

#[account]
pub struct ProgramMetadata {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// The slot when the metadata was captured
    pub updated_at: u64,

    /// The version of the program
    /// Max 11 characters XXX.YYY.ZZZ
    pub version: String,

    /// Reserved
    pub reserved: [u8; 64],
}

#[account]
pub struct SignatoryRecordV2 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Proposal the signatory is assigned for
    pub proposal: Pubkey,

    /// The account of the signatory who can sign off the proposal
    pub signatory: Pubkey,

    /// Indicates whether the signatory signed off the proposal
    pub signed_off: bool,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 8],
}

#[account]
pub struct RealmV1 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Community mint
    pub community_mint: Pubkey,

    /// Configuration of the Realm
    pub config: RealmConfig,

    /// Reserved space for future versions
    pub reserved: [u8; 6],

    /// The number of proposals in voting state in the Realm
    /// Note: This is field introduced in V2 but it took space from reserved
    /// and we have preserve it for V1 serialization roundtrip
    pub voting_proposal_count: u16,

    /// Realm authority. The authority must sign transactions which update the realm config
    /// The authority should be transferred to Realm Governance to make the Realm self governed through proposals
    pub authority: Option<Pubkey>,

    /// Governance Realm name
    pub name: String,
}

#[account]
pub struct TokenOwnerRecordV1 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// The Realm the TokenOwnerRecord belongs to
    pub realm: Pubkey,

    /// Governing Token Mint the TokenOwnerRecord holds deposit for
    pub governing_token_mint: Pubkey,

    /// The owner (either single or multisig) of the deposited governing SPL Tokens
    /// This is who can authorize a withdrawal of the tokens
    pub governing_token_owner: Pubkey,

    /// The amount of governing tokens deposited into the Realm
    /// This amount is the voter weight used when voting on proposals
    pub governing_token_deposit_amount: u64,

    /// The number of votes cast by TokenOwner but not relinquished yet
    /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state
    pub unrelinquished_votes_count: u32,

    /// The total number of votes cast by the TokenOwner
    /// If TokenOwner withdraws vote while voting is still in progress total_votes_count is decreased  and the vote doesn't count towards the total
    pub total_votes_count: u32,

    /// The number of outstanding proposals the TokenOwner currently owns
    /// The count is increased when TokenOwner creates a proposal
    /// and decreased  once it's either voted on (Succeeded or Defeated) or Cancelled
    /// By default it's restricted to 1 outstanding Proposal per token owner
    pub outstanding_proposal_count: u8,

    /// Reserved space for future versions
    pub reserved: [u8; 7],

    /// A single account that is allowed to operate governance with the deposited governing tokens
    /// It can be delegated to by the governing_token_owner or current governance_delegate
    pub governance_delegate: Option<Pubkey>,
}

#[account]
pub struct GovernanceV1 {
    /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance
    pub account_type: GovernanceAccountType,

    /// Governance Realm
    pub realm: Pubkey,

    /// Account governed by this Governance and/or PDA identity seed
    /// It can be Program account, Mint account, Token account or any other account
    ///
    /// Note: The account doesn't have to exist. In that case the field is only a PDA seed
    ///
    /// Note: Setting governed_account doesn't give any authority over the governed account
    /// The relevant authorities for specific account types must still be transferred to the Governance PDA
    /// Ex: mint_authority/freeze_authority for a Mint account
    /// or upgrade_authority for a Program account should be transferred to the Governance PDA
    pub governed_account: Pubkey,

    /// Running count of proposals
    pub proposals_count: u32,

    /// Governance config
    pub config: GovernanceConfig,

    /// Reserved space for future versions
    pub reserved: [u8; 6],

    /// The number of proposals in voting state in the Governance
    /// Note: This is field introduced in V2 but it took space from reserved
    /// and we have preserve it for V1 serialization roundtrip
    pub voting_proposal_count: u16,
}

#[account]
pub struct ProposalV1 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Governance account the Proposal belongs to
    pub governance: Pubkey,

    /// Indicates which Governing Token is used to vote on the Proposal
    /// Whether the general Community token owners or the Council tokens owners vote on this Proposal
    pub governing_token_mint: Pubkey,

    /// Current proposal state
    pub state: ProposalState,

    /// The TokenOwnerRecord representing the user who created and owns this Proposal
    pub token_owner_record: Pubkey,

    /// The number of signatories assigned to the Proposal
    pub signatories_count: u8,

    /// The number of signatories who already signed
    pub signatories_signed_off_count: u8,

    /// The number of Yes votes
    pub yes_votes_count: u64,

    /// The number of No votes
    pub no_votes_count: u64,

    /// The number of the instructions already executed
    pub instructions_executed_count: u16,

    /// The number of instructions included in the proposal
    pub instructions_count: u16,

    /// The index of the next instruction to be added
    pub instructions_next_index: u16,

    /// When the Proposal was created and entered Draft state
    pub draft_at: i64,

    /// When Signatories started signing off the Proposal
    pub signing_off_at: Option<i64>,

    /// When the Proposal began voting as UnixTimestamp
    pub voting_at: Option<i64>,

    /// When the Proposal began voting as Slot
    /// Note: The slot is not currently used but the exact slot is going to be required to support snapshot based vote weights
    pub voting_at_slot: Option<u64>,

    /// When the Proposal ended voting and entered either Succeeded or Defeated
    pub voting_completed_at: Option<i64>,

    /// When the Proposal entered Executing state
    pub executing_at: Option<i64>,

    /// When the Proposal entered final state Completed or Cancelled and was closed
    pub closed_at: Option<i64>,

    /// Instruction execution flag for ordered and transactional instructions
    /// Note: This field is not used in the current version
    pub execution_flags: InstructionExecutionFlags,

    /// The max vote weight for the Governing Token mint at the time Proposal was decided
    /// It's used to show correct vote results for historical proposals in cases when the mint supply or max weight source changed
    /// after vote was completed.
    pub max_vote_weight: Option<u64>,

    /// The vote threshold percentage at the time Proposal was decided
    /// It's used to show correct vote results for historical proposals in cases when the threshold
    /// was changed for governance config after vote was completed.
    pub vote_threshold: Option<VoteThreshold>,

    /// Proposal name
    pub name: String,

    /// Link to proposal's description
    pub description_link: String,
}

#[account]
pub struct SignatoryRecordV1 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Proposal the signatory is assigned for
    pub proposal: Pubkey,

    /// The account of the signatory who can sign off the proposal
    pub signatory: Pubkey,

    /// Indicates whether the signatory signed off the proposal
    pub signed_off: bool,
}

#[account]
pub struct VoteRecordV1 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Proposal account
    pub proposal: Pubkey,

    /// The user who casted this vote
    /// This is the Governing Token Owner who deposited governing tokens into the Realm
    pub governing_token_owner: Pubkey,

    /// Indicates whether the vote was relinquished by voter
    pub is_relinquished: bool,

    /// Voter's vote: Yes/No and amount
    pub vote_weight: VoteWeightV1,
}

#[account]
pub struct GovernanceV2 {
    /// Account type. It can be Uninitialized, Governance, ProgramGovernance, TokenGovernance or MintGovernance
    pub account_type: GovernanceAccountType,

    /// Governance Realm
    pub realm: Pubkey,

    /// Account governed by this Governance and/or PDA identity seed
    /// It can be Program account, Mint account, Token account or any other account
    ///
    /// Note: The account doesn't have to exist. In that case the field is only a PDA seed
    ///
    /// Note: Setting governed_account doesn't give any authority over the governed account
    /// The relevant authorities for specific account types must still be transferred to the Governance PDA
    /// Ex: mint_authority/freeze_authority for a Mint account
    /// or upgrade_authority for a Program account should be transferred to the Governance PDA
    pub governed_account: Pubkey,

    /// Running count of proposals
    pub proposals_count: u32,

    /// Governance config
    pub config: GovernanceConfig,

    /// Reserved space for future versions
    pub reserved: [u8; 6],

    /// The number of proposals in voting state in the Governance
    pub voting_proposal_count: u16,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 128],
}

#[account]
pub struct VoteRecordV2 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// Proposal account
    pub proposal: Pubkey,

    /// The user who casted this vote
    /// This is the Governing Token Owner who deposited governing tokens into the Realm
    pub governing_token_owner: Pubkey,

    /// Indicates whether the vote was relinquished by voter
    pub is_relinquished: bool,

    /// The weight of the user casting the vote
    pub voter_weight: u64,

    /// Voter's vote
    pub vote: Vote,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 8],
}

#[account]
pub struct TokenOwnerRecordV2 {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// The Realm the TokenOwnerRecord belongs to
    pub realm: Pubkey,

    /// Governing Token Mint the TokenOwnerRecord holds deposit for
    pub governing_token_mint: Pubkey,

    /// The owner (either single or multisig) of the deposited governing SPL Tokens
    /// This is who can authorize a withdrawal of the tokens
    pub governing_token_owner: Pubkey,

    /// The amount of governing tokens deposited into the Realm
    /// This amount is the voter weight used when voting on proposals
    pub governing_token_deposit_amount: u64,

    /// The number of votes cast by TokenOwner but not relinquished yet
    /// Every time a vote is cast this number is increased and it's always decreased when relinquishing a vote regardless of the vote state
    pub unrelinquished_votes_count: u32,

    /// The total number of votes cast by the TokenOwner
    /// If TokenOwner withdraws vote while voting is still in progress total_votes_count is decreased  and the vote doesn't count towards the total
    pub total_votes_count: u32,

    /// The number of outstanding proposals the TokenOwner currently owns
    /// The count is increased when TokenOwner creates a proposal
    /// and decreased  once it's either voted on (Succeeded or Defeated) or Cancelled
    /// By default it's restricted to 1 outstanding Proposal per token owner
    pub outstanding_proposal_count: u8,

    /// Reserved space for future versions
    pub reserved: [u8; 7],

    /// A single account that is allowed to operate governance with the deposited governing tokens
    /// It can be delegated to by the governing_token_owner or current governance_delegate
    pub governance_delegate: Option<Pubkey>,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 128],
}

#[account]
pub struct RealmConfigAccount {
    /// Governance account type
    pub account_type: GovernanceAccountType,

    /// The realm the config belong to
    pub realm: Pubkey,

    /// Addin providing voter weights for community token
    pub community_voter_weight_addin: Option<Pubkey>,

    /// Addin providing max vote weight for community token
    /// Note: This field is not implemented in the current version
    pub max_community_voter_weight_addin: Option<Pubkey>,

    /// Addin providing voter weights for council token
    /// Note: This field is not implemented in the current version
    pub council_voter_weight_addin: Option<Pubkey>,

    /// Addin providing max vote weight for council token
    /// Note: This field is not implemented in the current version
    pub council_max_vote_weight_addin: Option<Pubkey>,

    /// Reserved
    pub reserved: [u8; 128],
}

#[account]
pub struct ProposalTransactionV2 {
    /// Governance Account type
    pub account_type: GovernanceAccountType,

    /// The Proposal the instruction belongs to
    pub proposal: Pubkey,

    /// The option index the instruction belongs to
    pub option_index: u8,

    /// Unique transaction index within it's parent Proposal
    pub transaction_index: u16,

    /// Minimum waiting time in seconds for the  instruction to be executed once proposal is voted on
    pub hold_up_time: u32,

    /// Instructions to execute
    /// The instructions will be signed by Governance PDA the Proposal belongs to
    // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA
    // All instructions will be executed within a single transaction
    pub instructions: Vec<InstructionData>,

    /// Executed at flag
    pub executed_at: Option<i64>,

    /// Instruction execution status
    pub execution_status: TransactionExecutionStatus,

    /// Reserved space for versions v2 and onwards
    /// Note: This space won't be available to v1 accounts until runtime supports resizing
    pub reserved_v2: [u8; 8],
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct NativeTreasury {}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum MintMaxVoteWeightSource {
    /// Fraction (10^10 precision) of the governing mint supply is used as max vote weight
    /// The default is 100% (10^10) to use all available mint supply for voting
    SupplyFraction(u64),

    /// Absolute value, irrelevant of the actual mint supply, is used as max vote weight
    /// Note: this option is not implemented in the current version
    Absolute(u64),
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct RealmConfigArgs {
    /// Indicates whether council_mint should be used
    /// If yes then council_mint account must also be passed to the instruction
    pub use_council_mint: bool,

    /// Min number of community tokens required to create a governance
    pub min_community_weight_to_create_governance: u64,

    /// The source used for community mint max vote weight source
    pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource,

    /// Indicates whether an external addin program should be used to provide community voters weights
    /// If yes then the voters weight program account must be passed to the instruction
    pub use_community_voter_weight_addin: bool,

    /// Indicates whether an external addin program should be used to provide max voters weight for the community mint
    /// If yes then the max voter weight program account must be passed to the instruction
    pub use_max_community_voter_weight_addin: bool,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct RealmConfig {
    /// Indicates whether an external addin program should be used to provide voters weights for the community mint
    pub use_community_voter_weight_addin: bool,

    /// Indicates whether an external addin program should be used to provide max voter weight for the community mint
    pub use_max_community_voter_weight_addin: bool,

    /// Reserved space for future versions
    pub reserved: [u8; 6],

    /// Min number of voter's community weight required to create a governance
    pub min_community_weight_to_create_governance: u64,

    /// The source used for community mint max vote weight source
    pub community_mint_max_vote_weight_source: MintMaxVoteWeightSource,

    /// Optional council mint
    pub council_mint: Option<Pubkey>,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum GovernanceAccountType {
    /// Default uninitialized account state
    Uninitialized,

    /// Top level aggregation for governances with Community Token (and optional Council Token)
    RealmV1,

    /// Token Owner Record for given governing token owner within a Realm
    TokenOwnerRecordV1,

    /// Governance account
    GovernanceV1,

    /// Program Governance account
    ProgramGovernanceV1,

    /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts
    ProposalV1,

    /// Proposal Signatory account
    SignatoryRecordV1,

    /// Vote record account for a given Proposal.  Proposal can have 0..n voting records
    VoteRecordV1,

    /// ProposalInstruction account which holds an instruction to execute for Proposal
    ProposalInstructionV1,

    /// Mint Governance account
    MintGovernanceV1,

    /// Token Governance account
    TokenGovernanceV1,

    /// Realm config account (introduced in V2)
    RealmConfig,

    /// Vote record account for a given Proposal.  Proposal can have 0..n voting records
    /// V2 adds support for multi option votes
    VoteRecordV2,

    /// ProposalTransaction account which holds instructions to execute for Proposal within a single Transaction
    /// V2 replaces ProposalInstruction and adds index for proposal option and multiple instructions
    ProposalTransactionV2,

    /// Proposal account for Governance account. A single Governance account can have multiple Proposal accounts
    /// V2 adds support for multiple vote options
    ProposalV2,

    /// Program metadata account (introduced in V2)
    /// It stores information about the particular SPL-Governance program instance
    ProgramMetadata,

    /// Top level aggregation for governances with Community Token (and optional Council Token)
    /// V2 adds the following fields:
    /// 1) use_community_voter_weight_addin and use_max_community_voter_weight_addin to RealmConfig
    /// 2) voting_proposal_count
    /// 3) extra reserved space reserved_v2
    RealmV2,

    /// Token Owner Record for given governing token owner within a Realm
    /// V2 adds extra reserved space reserved_v2
    TokenOwnerRecordV2,

    /// Governance account
    /// V2 adds extra reserved space reserved_v2
    GovernanceV2,

    /// Program Governance account
    /// V2 adds extra reserved space reserved_v2
    ProgramGovernanceV2,

    /// Mint Governance account
    /// V2 adds extra reserved space reserved_v2
    MintGovernanceV2,

    /// Token Governance account
    /// V2 adds extra reserved space reserved_v2
    TokenGovernanceV2,

    /// Proposal Signatory account
    /// V2 adds extra reserved space reserved_v2
    SignatoryRecordV2,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum OptionVoteResult {
    /// Vote on the option is not resolved yet
    None,

    /// Vote on the option is completed and the option passed
    Succeeded,

    /// Vote on the option is completed and the option was defeated
    Defeated,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct ProposalOption {
    /// Option label
    pub label: String,

    /// Vote weight for the option
    pub vote_weight: u64,

    /// Vote result for the option
    pub vote_result: OptionVoteResult,

    /// The number of the transactions already executed
    pub transactions_executed_count: u16,

    /// The number of transactions included in the option
    pub transactions_count: u16,

    /// The index of the next transaction to be added
    pub transactions_next_index: u16,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum ProposalState {
    /// Draft - Proposal enters Draft state when it's created
    Draft,

    /// SigningOff - The Proposal is being signed off by Signatories
    /// Proposal enters the state when first Signatory Sings and leaves it when last Signatory signs
    SigningOff,

    /// Taking votes
    Voting,

    /// Voting ended with success
    Succeeded,

    /// Voting on Proposal succeeded and now instructions are being executed
    /// Proposal enter this state when first instruction is executed and leaves when the last instruction is executed
    Executing,

    /// Completed
    Completed,

    /// Cancelled
    Cancelled,

    /// Defeated
    Defeated,

    /// Same as Executing but indicates some instructions failed to execute
    /// Proposal can't be transitioned from ExecutingWithErrors to Completed state
    ExecutingWithErrors,

    /// The Proposal was vetoed
    Vetoed,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum VoteType {
    /// Single choice vote with mutually exclusive choices
    /// In the SingeChoice mode there can ever be a single winner
    /// If multiple options score the same highest vote then the Proposal is not resolved and considered as Failed
    /// Note: Yes/No vote is a single choice (Yes) vote with the deny option (No)
    SingleChoice,

    /// Multiple options can be selected with up to max_voter_options per voter
    /// and with up to max_winning_options of successful options
    /// Ex. voters are given 5 options, can choose up to 3 (max_voter_options)
    /// and only 1 (max_winning_options) option can win and be executed
    MultiChoice {
        /// The max number of options a voter can choose
        /// By default it equals to the number of available options
        /// Note: In the current version the limit is not supported and not enforced yet
        #[allow(dead_code)]
        max_voter_options: u8,

        /// The max number of wining options
        /// For executable proposals it limits how many options can be executed for a Proposal
        /// By default it equals to the number of available options
        /// Note: In the current version the limit is not supported and not enforced yet
        #[allow(dead_code)]
        max_winning_options: u8,
    },
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum InstructionExecutionFlags {
    /// No execution flags are specified
    /// Instructions can be executed individually, in any order, as soon as they hold_up time expires
    None,

    /// Instructions are executed in a specific order
    /// Note: Ordered execution is not supported in the current version
    /// The implementation requires another account type to track deleted instructions
    Ordered,

    /// Multiple instructions can be executed as a single transaction
    /// Note: Transactions are not supported in the current version
    /// The implementation requires another account type to group instructions within a transaction
    UseTransaction,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum VoteThreshold {
    /// Voting threshold of Yes votes in % required to tip the vote (Approval Quorum)
    /// It's the percentage of tokens out of the entire pool of governance tokens eligible to vote
    /// Note: If the threshold is below or equal to 50% then an even split of votes ex: 50:50 or 40:40 is always resolved as Defeated
    /// In other words a '+1 vote' tie breaker is always required to have a successful vote
    YesVotePercentage(u8),

    /// The minimum number of votes in % out of the entire pool of governance tokens eligible to vote
    /// which must be cast for the vote to be valid
    /// Once the quorum is achieved a simple majority (50%+1) of Yes votes is required for the vote to succeed
    /// Note: Quorum is not implemented in the current version
    QuorumPercentage(u8),

    /// Disabled vote threshold indicates the given voting population (community or council) is not allowed to vote
    /// on proposals for the given Governance
    Disabled,
    //
    // Absolute vote threshold expressed in the voting mint units
    // It can be implemented once Solana runtime supports accounts resizing to accommodate u64 size extension
    // Alternatively we could use the reserved space if it becomes a priority
    // Absolute(u64)
    //
    // Vote threshold which is always accepted
    // It can be used in a setup where the only security gate is proposal creation
    // and once created it's automatically approved
    // Any
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum VoteTipping {
    /// Tip when there is no way for another option to win and the vote threshold
    /// has been reached. This ignores voters withdrawing their votes.
    ///
    /// Currently only supported for the "yes" option in single choice votes.
    Strict,

    /// Tip when an option reaches the vote threshold and has more vote weight
    /// than any other options.
    ///
    /// Currently only supported for the "yes" option in single choice votes.
    Early,

    /// Never tip the vote early.
    Disabled,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct GovernanceConfig {
    /// The type of the vote threshold used for community vote
    /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported
    pub community_vote_threshold: VoteThreshold,

    /// Minimum community weight a governance token owner must possess to be able to create a proposal
    pub min_community_weight_to_create_proposal: u64,

    /// Minimum waiting time in seconds for a transaction to be executed after proposal is voted on
    pub min_transaction_hold_up_time: u32,

    /// Time limit in seconds for proposal to be open for voting
    pub max_voting_time: u32,

    /// Conditions under which a vote will complete early
    pub vote_tipping: VoteTipping,

    /// The type of the vote threshold used for council vote
    /// Note: In the current version only YesVotePercentage and Disabled thresholds are supported
    pub council_vote_threshold: VoteThreshold,

    /// The threshold for Council Veto votes
    pub council_veto_vote_threshold: VoteThreshold,

    /// Minimum council weight a governance token owner must possess to be able to create a proposal
    pub min_council_weight_to_create_proposal: u64,
    //
    // The threshold for Community Veto votes
    // Note: Community Veto vote is not supported in the current version
    // In order to use this threshold the space from GovernanceV2.reserved must be taken to expand GovernanceConfig size
    // pub community_veto_vote_threshold: VoteThreshold,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct AccountMetaData {
    /// An account's public key
    pub pubkey: Pubkey,
    /// True if an Instruction requires a Transaction signature matching `pubkey`.
    pub is_signer: bool,
    /// True if the `pubkey` can be loaded as a read-write account.
    pub is_writable: bool,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct InstructionData {
    /// Pubkey of the instruction processor that executes this instruction
    pub program_id: Pubkey,
    /// Metadata for what accounts should be passed to the instruction processor
    pub accounts: Vec<AccountMetaData>,
    /// Opaque data passed to the instruction processor
    pub data: Vec<u8>,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum TransactionExecutionStatus {
    /// Transaction was not executed yet
    None,

    /// Transaction was executed successfully
    Success,

    /// Transaction execution failed
    Error,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct ProposalInstructionV1 {
    /// Governance Account type
    pub account_type: GovernanceAccountType,

    /// The Proposal the instruction belongs to
    pub proposal: Pubkey,

    /// Unique instruction index within it's parent Proposal
    pub instruction_index: u16,

    /// Minimum waiting time in seconds for the instruction to be executed once proposal is voted on
    pub hold_up_time: u32,

    /// Instruction to execute
    /// The instruction will be signed by Governance PDA the Proposal belongs to
    // For example for ProgramGovernance the instruction to upgrade program will be signed by ProgramGovernance PDA
    pub instruction: InstructionData,

    /// Executed at flag
    pub executed_at: Option<i64>,

    /// Instruction execution status
    pub execution_status: TransactionExecutionStatus,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum VoteWeightV1 {
    /// Yes vote
    Yes(u64),

    /// No vote
    No(u64),
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct VoteChoice {
    /// The rank given to the choice by voter
    /// Note: The filed is not used in the current version
    pub rank: u8,

    /// The voter's weight percentage given by the voter to the choice
    pub weight_percentage: u8,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum Vote {
    /// Vote approving choices
    Approve(Vec<VoteChoice>),

    /// Vote rejecting proposal
    Deny,

    /// Declare indifference to proposal
    /// Note: Not supported in the current version
    Abstain,

    /// Veto proposal
    Veto,
}

#[derive(AnchorSerialize, AnchorDeserialize)]
pub enum SetRealmAuthorityAction {
    /// Sets realm authority without any checks
    /// Uncheck option allows to set the realm authority to non governance accounts
    SetUnchecked,

    /// Sets realm authority and checks the new new authority is one of the realm's governances
    // Note: This is not a security feature because governance creation is only gated with min_community_weight_to_create_governance
    //       The check is done to prevent scenarios where the authority could be accidentally set to a wrong or none existing account
    SetChecked,

    /// Removes realm authority
    Remove,
}

#[error_code]
pub enum GovernanceError {
    /// Invalid instruction passed to program
    #[msg("Invalid instruction passed to program")]
    InvalidInstruction = 500, // Start Governance custom errors from 500 to avoid conflicts with programs invoked via CPI

    /// Realm with the given name and governing mints already exists
    #[msg("Realm with the given name and governing mints already exists")]
    RealmAlreadyExists,

    /// Invalid Realm
    #[msg("Invalid realm")]
    InvalidRealm,

    /// Invalid Governing Token Mint
    #[msg("Invalid Governing Token Mint")]
    InvalidGoverningTokenMint, // 503

    /// Governing Token Owner must sign transaction
    #[msg("Governing Token Owner must sign transaction")]
    GoverningTokenOwnerMustSign,

    /// Governing Token Owner or Delegate  must sign transaction
    #[msg("Governing Token Owner or Delegate  must sign transaction")]
    GoverningTokenOwnerOrDelegateMustSign, // 505

    /// All votes must be relinquished to withdraw governing tokens
    #[msg("All votes must be relinquished to withdraw governing tokens")]
    AllVotesMustBeRelinquishedToWithdrawGoverningTokens,

    /// Invalid Token Owner Record account address
    #[msg("Invalid Token Owner Record account address")]
    InvalidTokenOwnerRecordAccountAddress,

    /// Invalid GoverningMint for TokenOwnerRecord
    #[msg("Invalid GoverningMint for TokenOwnerRecord")]
    InvalidGoverningMintForTokenOwnerRecord, // 508

    /// Invalid Realm for TokenOwnerRecord
    #[msg("Invalid Realm for TokenOwnerRecord")]
    InvalidRealmForTokenOwnerRecord, // 509

    /// Invalid Proposal for ProposalTransaction,
    #[msg("Invalid Proposal for ProposalTransaction,")]
    InvalidProposalForProposalTransaction, // 510

    /// Invalid Signatory account address
    #[msg("Invalid Signatory account address")]
    InvalidSignatoryAddress, // 511

    /// Signatory already signed off
    #[msg("Signatory already signed off")]
    SignatoryAlreadySignedOff, // 512

    /// Signatory must sign
    #[msg("Signatory must sign")]
    SignatoryMustSign, // 513

    /// Invalid Proposal Owner
    #[msg("Invalid Proposal Owner")]
    InvalidProposalOwnerAccount, // 514

    /// Invalid Proposal for VoterRecord
    #[msg("Invalid Proposal for VoterRecord")]
    InvalidProposalForVoterRecord, // 515

    /// Invalid GoverningTokenOwner  for VoteRecord
    #[msg("Invalid GoverningTokenOwner for VoteRecord")]
    InvalidGoverningTokenOwnerForVoteRecord, // 516

    /// Invalid Governance config: Vote threshold percentage out of range"
    #[msg("Invalid Governance config: Vote threshold percentage out of range")]
    InvalidVoteThresholdPercentage, // 517

    /// Proposal for the given Governance, Governing Token Mint and index already exists
    #[msg("Proposal for the given Governance, Governing Token Mint and index already exists")]
    ProposalAlreadyExists, // 518

    /// Token Owner already voted on the Proposal
    #[msg("Token Owner already voted on the Proposal")]
    VoteAlreadyExists, // 519

    /// Owner doesn't have enough governing tokens to create Proposal
    #[msg("Owner doesn't have enough governing tokens to create Proposal")]
    NotEnoughTokensToCreateProposal, // 520

    /// Invalid State: Can't edit Signatories
    #[msg("Invalid State: Can't edit Signatories")]
    InvalidStateCannotEditSignatories, // 521

    /// Invalid Proposal state
    #[msg("Invalid Proposal state")]
    InvalidProposalState, // 522

    /// Invalid State: Can't edit transactions
    #[msg("Invalid State: Can't edit transactions")]
    InvalidStateCannotEditTransactions, // 523

    /// Invalid State: Can't execute transaction
    #[msg("Invalid State: Can't execute transaction")]
    InvalidStateCannotExecuteTransaction, // 524

    /// Can't execute transaction within its hold up time
    #[msg("Can't execute transaction within its hold up time")]
    CannotExecuteTransactionWithinHoldUpTime, // 525

    /// Transaction already executed
    #[msg("Transaction already executed")]
    TransactionAlreadyExecuted, // 526

    /// Invalid Transaction index
    #[msg("Invalid Transaction index")]
    InvalidTransactionIndex, // 527

    /// Transaction hold up time is below the min specified by Governance
    #[msg("Transaction hold up time is below the min specified by Governance")]
    TransactionHoldUpTimeBelowRequiredMin, // 528

    /// Transaction at the given index for the Proposal already exists
    #[msg("Transaction at the given index for the Proposal already exists")]
    TransactionAlreadyExists, // 529

    /// Invalid State: Can't sign off
    #[msg("Invalid State: Can't sign off")]
    InvalidStateCannotSignOff, // 530

    /// Invalid State: Can't vote
    #[msg("Invalid State: Can't vote")]
    InvalidStateCannotVote,

    /// Invalid State: Can't finalize vote
    #[msg("Invalid State: Can't finalize vote")]
    InvalidStateCannotFinalize,

    /// Invalid State: Can't cancel Proposal
    #[msg("Invalid State: Can't cancel Proposal")]
    InvalidStateCannotCancelProposal,

    /// Vote already relinquished
    #[msg("Vote already relinquished")]
    VoteAlreadyRelinquished,

    /// Can't finalize vote. Voting still in progress
    #[msg("Can't finalize vote. Voting still in progress")]
    CannotFinalizeVotingInProgress,

    /// Proposal voting time expired
    #[msg("Proposal voting time expired")]
    ProposalVotingTimeExpired,

    /// Invalid Signatory Mint
    #[msg("Invalid Signatory Mint")]
    InvalidSignatoryMint,

    /// Proposal does not belong to the given Governance
    #[msg("Proposal does not belong to the given Governance")]
    InvalidGovernanceForProposal, // 538

    /// Proposal does not belong to given Governing Mint"
    #[msg("Proposal does not belong to given Governing Mint")]
    InvalidGoverningMintForProposal, // 539

    /// Current mint authority must sign transaction
    #[msg("Current mint authority must sign transaction")]
    MintAuthorityMustSign, // 540

    /// Invalid mint authority
    #[msg("Invalid mint authority")]
    InvalidMintAuthority, // 542

    /// Mint has no authority
    #[msg("Mint has no authority")]
    MintHasNoAuthority, // 542

    /// ---- SPL Token Tools Errors ----

    /// Invalid Token account owner
    #[msg("Invalid Token account owner")]
    SplTokenAccountWithInvalidOwner, // 543

    /// Invalid Mint account owner
    #[msg("Invalid Mint account owner")]
    SplTokenMintWithInvalidOwner, // 544

    /// Token Account is not initialized
    #[msg("Token Account is not initialized")]
    SplTokenAccountNotInitialized, // 545

    /// Token Account doesn't exist
    #[msg("Token Account doesn't exist")]
    SplTokenAccountDoesNotExist, // 546

    /// Token account data is invalid
    #[msg("Token account data is invalid")]
    SplTokenInvalidTokenAccountData, // 547

    /// Token mint account data is invalid
    #[msg("Token mint account data is invalid")]
    SplTokenInvalidMintAccountData, // 548

    /// Token Mint is not initialized
    #[msg("Token Mint account is not initialized")]
    SplTokenMintNotInitialized, // 549

    /// Token Mint account doesn't exist
    #[msg("Token Mint account doesn't exist")]
    SplTokenMintDoesNotExist, // 550

    /// ---- Bpf Upgradable Loader Tools Errors ----

    /// Invalid ProgramData account Address
    #[msg("Invalid ProgramData account address")]
    InvalidProgramDataAccountAddress, // 551

    /// Invalid ProgramData account data
    #[msg("Invalid ProgramData account Data")]
    InvalidProgramDataAccountData, // 552

    /// Provided upgrade authority doesn't match current program upgrade authority
    #[msg("Provided upgrade authority doesn't match current program upgrade authority")]
    InvalidUpgradeAuthority, // 553

    /// Current program upgrade authority must sign transaction
    #[msg("Current program upgrade authority must sign transaction")]
    UpgradeAuthorityMustSign, // 554

    /// Given program is not upgradable
    #[msg("Given program is not upgradable")]
    ProgramNotUpgradable, // 555

    /// Invalid token owner
    #[msg("Invalid token owner")]
    InvalidTokenOwner, // 556

    /// Current token owner must sign transaction
    #[msg("Current token owner must sign transaction")]
    TokenOwnerMustSign, // 557

    /// Given VoteThresholdType is not supported
    #[msg("Given VoteThresholdType is not supported")]
    VoteThresholdTypeNotSupported, // 558

    /// Given VoteWeightSource is not supported
    #[msg("Given VoteWeightSource is not supported")]
    VoteWeightSourceNotSupported, // 559

    /// GoverningTokenMint not allowed to vote
    #[msg("GoverningTokenMint not allowed to vote")]
    GoverningTokenMintNotAllowedToVote, // 560

    /// Governance PDA must sign
    #[msg("Governance PDA must sign")]
    GovernancePdaMustSign,

    /// Transaction already flagged with error
    #[msg("Transaction already flagged with error")]
    TransactionAlreadyFlaggedWithError,

    /// Invalid Realm for Governance
    #[msg("Invalid Realm for Governance")]
    InvalidRealmForGovernance,

    /// Invalid Authority for Realm
    #[msg("Invalid Authority for Realm")]
    InvalidAuthorityForRealm,

    /// Realm has no authority
    #[msg("Realm has no authority")]
    RealmHasNoAuthority,

    /// Realm authority must sign
    #[msg("Realm authority must sign")]
    RealmAuthorityMustSign, // 566

    /// Invalid governing token holding account
    #[msg("Invalid governing token holding account")]
    InvalidGoverningTokenHoldingAccount,

    /// Realm council mint change is not supported
    #[msg("Realm council mint change is not supported")]
    RealmCouncilMintChangeIsNotSupported,

    /// Not supported mint max vote weight sourcef
    #[msg("Not supported mint max vote weight source")]
    MintMaxVoteWeightSourceNotSupported,

    /// Invalid max vote weight supply fraction
    #[msg("Invalid max vote weight supply fraction")]
    InvalidMaxVoteWeightSupplyFraction,

    /// Owner doesn't have enough governing tokens to create Governance
    #[msg("Owner doesn't have enough governing tokens to create Governance")]
    NotEnoughTokensToCreateGovernance,

    /// Too many outstanding proposals
    #[msg("Too many outstanding proposals")]
    TooManyOutstandingProposals,

    /// All proposals must be finalized to withdraw governing tokens
    #[msg("All proposals must be finalized to withdraw governing tokens")]
    AllProposalsMustBeFinalisedToWithdrawGoverningTokens,

    /// Invalid VoterWeightRecord for Realm
    #[msg("Invalid VoterWeightRecord for Realm")]
    InvalidVoterWeightRecordForRealm,

    /// Invalid VoterWeightRecord for GoverningTokenMint
    #[msg("Invalid VoterWeightRecord for GoverningTokenMint")]
    InvalidVoterWeightRecordForGoverningTokenMint,

    /// Invalid VoterWeightRecord for TokenOwner
    #[msg("Invalid VoterWeightRecord for TokenOwner")]
    InvalidVoterWeightRecordForTokenOwner,

    /// VoterWeightRecord expired
    #[msg("VoterWeightRecord expired")]
    VoterWeightRecordExpired,

    /// Invalid RealmConfig for Realm
    #[msg("Invalid RealmConfig for Realm")]
    InvalidRealmConfigForRealm,

    /// TokenOwnerRecord already exists
    #[msg("TokenOwnerRecord already exists")]
    TokenOwnerRecordAlreadyExists,

    /// Governing token deposits not allowed
    #[msg("Governing token deposits not allowed")]
    GoverningTokenDepositsNotAllowed,

    /// Invalid vote choice weight percentage
    #[msg("Invalid vote choice weight percentage")]
    InvalidVoteChoiceWeightPercentage,

    /// Vote type not supported
    #[msg("Vote type not supported")]
    VoteTypeNotSupported,

    /// InvalidProposalOptions
    #[msg("Invalid proposal options")]
    InvalidProposalOptions,

    /// Proposal is not not executable
    #[msg("Proposal is not not executable")]
    ProposalIsNotExecutable,

    /// Invalid vote
    #[msg("Invalid vote")]
    InvalidVote,

    /// Cannot execute defeated option
    #[msg("Cannot execute defeated option")]
    CannotExecuteDefeatedOption,

    /// VoterWeightRecord invalid action
    #[msg("VoterWeightRecord invalid action")]
    VoterWeightRecordInvalidAction,

    /// VoterWeightRecord invalid action target
    #[msg("VoterWeightRecord invalid action target")]
    VoterWeightRecordInvalidActionTarget,

    /// Invalid MaxVoterWeightRecord for Realm
    #[msg("Invalid MaxVoterWeightRecord for Realm")]
    InvalidMaxVoterWeightRecordForRealm,

    /// Invalid MaxVoterWeightRecord for GoverningTokenMint
    #[msg("Invalid MaxVoterWeightRecord for GoverningTokenMint")]
    InvalidMaxVoterWeightRecordForGoverningTokenMint,

    /// MaxVoterWeightRecord expired
    #[msg("MaxVoterWeightRecord expired")]
    MaxVoterWeightRecordExpired,

    /// Not supported VoteType
    #[msg("Not supported VoteType")]
    NotSupportedVoteType,

    /// RealmConfig change not allowed
    #[msg("RealmConfig change not allowed")]
    RealmConfigChangeNotAllowed,

    /// GovernanceConfig change not allowed
    #[msg("GovernanceConfig change not allowed")]
    GovernanceConfigChangeNotAllowed,

    /// At least one VoteThreshold is required
    #[msg("At least one VoteThreshold is required")]
    AtLeastOneVoteThresholdRequired,

    /// Reserved buffer must be empty
    #[msg("Reserved buffer must be empty")]
    ReservedBufferMustBeEmpty,

    /// Cannot Relinquish in Finalizing state
    #[msg("Cannot Relinquish in Finalizing state")]
    CannotRelinquishInFinalizingState,
}
