386 lines
12 KiB
Rust
386 lines
12 KiB
Rust
use std::sync::Arc;
|
|
|
|
use solana_program::instruction::Instruction;
|
|
use solana_sdk::pubkey::Pubkey;
|
|
use solana_sdk::signature::{Keypair, Signer};
|
|
use spl_governance::state::{proposal, vote_record};
|
|
|
|
use crate::*;
|
|
|
|
#[derive(Clone)]
|
|
pub struct GovernanceCookie {
|
|
pub solana: Arc<solana::SolanaCookie>,
|
|
pub program_id: Pubkey,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct GovernanceRealmCookie {
|
|
pub governance: GovernanceCookie,
|
|
pub authority: Pubkey,
|
|
pub realm: Pubkey,
|
|
pub realm_config: Pubkey,
|
|
pub community_token_mint: MintCookie,
|
|
pub community_token_account: Pubkey,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct TokenOwnerRecordCookie {
|
|
pub address: Pubkey,
|
|
}
|
|
|
|
pub struct AccountGovernanceCookie {
|
|
pub address: Pubkey,
|
|
pub governed_account: Pubkey,
|
|
}
|
|
|
|
pub struct MintGovernanceCookie {
|
|
pub address: Pubkey,
|
|
pub governed_mint: Pubkey,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ProposalCookie {
|
|
pub address: Pubkey,
|
|
pub owner_token_owner_record: Pubkey,
|
|
}
|
|
|
|
impl GovernanceCookie {
|
|
pub async fn create_realm(
|
|
&self,
|
|
name: &str,
|
|
realm_authority: Pubkey,
|
|
community_token_mint: &MintCookie,
|
|
payer: &Keypair,
|
|
voter_weight_addin: &Pubkey,
|
|
) -> GovernanceRealmCookie {
|
|
let realm = Pubkey::find_program_address(
|
|
&[b"governance".as_ref(), name.as_ref()],
|
|
&self.program_id,
|
|
)
|
|
.0;
|
|
let community_token_account = Pubkey::find_program_address(
|
|
&[
|
|
b"governance".as_ref(),
|
|
&realm.to_bytes(),
|
|
&community_token_mint.pubkey.unwrap().to_bytes(),
|
|
],
|
|
&self.program_id,
|
|
)
|
|
.0;
|
|
let realm_config = Pubkey::find_program_address(
|
|
&[b"realm-config".as_ref(), &realm.to_bytes()],
|
|
&self.program_id,
|
|
)
|
|
.0;
|
|
|
|
let instructions = vec![spl_governance::instruction::create_realm(
|
|
&self.program_id,
|
|
&realm_authority,
|
|
&community_token_mint.pubkey.unwrap(),
|
|
&payer.pubkey(),
|
|
None,
|
|
Some(*voter_weight_addin),
|
|
None,
|
|
name.to_string(),
|
|
0,
|
|
spl_governance::state::enums::MintMaxVoteWeightSource::SupplyFraction(10000000000),
|
|
)];
|
|
|
|
let signer = Keypair::from_base58_string(&payer.to_base58_string());
|
|
|
|
self.solana
|
|
.process_transaction(&instructions, Some(&[&signer]))
|
|
.await
|
|
.unwrap();
|
|
|
|
GovernanceRealmCookie {
|
|
governance: self.clone(),
|
|
authority: realm_authority,
|
|
realm,
|
|
realm_config,
|
|
community_token_mint: community_token_mint.clone(),
|
|
community_token_account,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl GovernanceRealmCookie {
|
|
pub async fn create_token_owner_record(
|
|
&self,
|
|
owner: Pubkey,
|
|
payer: &Keypair,
|
|
) -> TokenOwnerRecordCookie {
|
|
let record = Pubkey::find_program_address(
|
|
&[
|
|
b"governance".as_ref(),
|
|
&self.realm.to_bytes(),
|
|
&self.community_token_mint.pubkey.unwrap().to_bytes(),
|
|
&owner.to_bytes(),
|
|
],
|
|
&self.governance.program_id,
|
|
)
|
|
.0;
|
|
|
|
let instructions = vec![spl_governance::instruction::create_token_owner_record(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&owner,
|
|
&self.community_token_mint.pubkey.unwrap(),
|
|
&payer.pubkey(),
|
|
)];
|
|
|
|
let signer = Keypair::from_base58_string(&payer.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer]))
|
|
.await
|
|
.unwrap();
|
|
|
|
TokenOwnerRecordCookie { address: record }
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub async fn create_account_governance(
|
|
&self,
|
|
governed_account: Pubkey,
|
|
voter: &VoterCookie,
|
|
authority: &Keypair,
|
|
payer: &Keypair,
|
|
vwr_instruction: Instruction,
|
|
) -> AccountGovernanceCookie {
|
|
let account_governance = spl_governance::state::governance::get_governance_address(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&governed_account,
|
|
);
|
|
|
|
let instructions = vec![
|
|
vwr_instruction,
|
|
spl_governance::instruction::create_governance(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
Some(&governed_account),
|
|
&voter.token_owner_record,
|
|
&payer.pubkey(),
|
|
&authority.pubkey(),
|
|
Some(voter.voter_weight_record),
|
|
spl_governance::state::governance::GovernanceConfig {
|
|
vote_threshold_percentage:
|
|
spl_governance::state::enums::VoteThresholdPercentage::YesVote(50),
|
|
min_community_weight_to_create_proposal: 1000,
|
|
min_transaction_hold_up_time: 0,
|
|
max_voting_time: 10,
|
|
vote_tipping: spl_governance::state::enums::VoteTipping::Disabled,
|
|
proposal_cool_off_time: 0,
|
|
min_council_weight_to_create_proposal: 1,
|
|
},
|
|
),
|
|
];
|
|
|
|
let signer1 = Keypair::from_base58_string(&payer.to_base58_string());
|
|
let signer2 = Keypair::from_base58_string(&authority.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer1, &signer2]))
|
|
.await
|
|
.unwrap();
|
|
|
|
AccountGovernanceCookie {
|
|
address: account_governance,
|
|
governed_account,
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub async fn create_mint_governance(
|
|
&self,
|
|
governed_mint: Pubkey,
|
|
governed_mint_authority: &Keypair,
|
|
voter: &VoterCookie,
|
|
authority: &Keypair,
|
|
payer: &Keypair,
|
|
vwr_instruction: Instruction,
|
|
) -> MintGovernanceCookie {
|
|
let mint_governance = spl_governance::state::governance::get_mint_governance_address(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&governed_mint,
|
|
);
|
|
|
|
let instructions = vec![
|
|
vwr_instruction,
|
|
spl_governance::instruction::create_mint_governance(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&governed_mint,
|
|
&governed_mint_authority.pubkey(),
|
|
&voter.token_owner_record,
|
|
&payer.pubkey(),
|
|
&authority.pubkey(),
|
|
Some(voter.voter_weight_record),
|
|
spl_governance::state::governance::GovernanceConfig {
|
|
vote_threshold_percentage:
|
|
spl_governance::state::enums::VoteThresholdPercentage::YesVote(50),
|
|
min_community_weight_to_create_proposal: 1000,
|
|
min_transaction_hold_up_time: 0,
|
|
max_voting_time: 10,
|
|
vote_tipping: spl_governance::state::enums::VoteTipping::Disabled,
|
|
proposal_cool_off_time: 0,
|
|
min_council_weight_to_create_proposal: 1,
|
|
},
|
|
true,
|
|
),
|
|
];
|
|
|
|
let signer1 = Keypair::from_base58_string(&payer.to_base58_string());
|
|
let signer2 = Keypair::from_base58_string(&authority.to_base58_string());
|
|
let signer3 = Keypair::from_base58_string(&governed_mint_authority.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer1, &signer2, &signer3]))
|
|
.await
|
|
.unwrap();
|
|
|
|
MintGovernanceCookie {
|
|
address: mint_governance,
|
|
governed_mint,
|
|
}
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub async fn create_proposal(
|
|
&self,
|
|
governance: Pubkey,
|
|
authority: &Keypair,
|
|
voter: &VoterCookie,
|
|
payer: &Keypair,
|
|
vwr_instruction: Instruction,
|
|
) -> std::result::Result<ProposalCookie, BanksClientError> {
|
|
let proposal = spl_governance::state::proposal::get_proposal_address(
|
|
&self.governance.program_id,
|
|
&governance,
|
|
&self.community_token_mint.pubkey.unwrap(),
|
|
&0u32.to_le_bytes(),
|
|
);
|
|
|
|
let instructions = vec![
|
|
vwr_instruction,
|
|
spl_governance::instruction::create_proposal(
|
|
&self.governance.program_id,
|
|
&governance,
|
|
&voter.token_owner_record,
|
|
&authority.pubkey(),
|
|
&payer.pubkey(),
|
|
Some(voter.voter_weight_record),
|
|
&self.realm,
|
|
"test proposal".into(),
|
|
"description".into(),
|
|
&self.community_token_mint.pubkey.unwrap(),
|
|
proposal::VoteType::SingleChoice,
|
|
vec!["yes".into()],
|
|
true,
|
|
0,
|
|
),
|
|
spl_governance::instruction::add_signatory(
|
|
&self.governance.program_id,
|
|
&proposal,
|
|
&voter.token_owner_record,
|
|
&authority.pubkey(),
|
|
&payer.pubkey(),
|
|
&authority.pubkey(),
|
|
),
|
|
spl_governance::instruction::sign_off_proposal(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&governance,
|
|
&proposal,
|
|
&authority.pubkey(),
|
|
None,
|
|
),
|
|
];
|
|
|
|
let signer1 = Keypair::from_base58_string(&payer.to_base58_string());
|
|
let signer2 = Keypair::from_base58_string(&authority.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer1, &signer2]))
|
|
.await?;
|
|
|
|
Ok(ProposalCookie {
|
|
address: proposal,
|
|
owner_token_owner_record: voter.token_owner_record,
|
|
})
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub async fn cast_vote(
|
|
&self,
|
|
governance: Pubkey,
|
|
proposal: &ProposalCookie,
|
|
voter: &VoterCookie,
|
|
authority: &Keypair,
|
|
payer: &Keypair,
|
|
vwr_instruction: Instruction,
|
|
) -> std::result::Result<(), BanksClientError> {
|
|
let instructions = vec![
|
|
vwr_instruction,
|
|
spl_governance::instruction::cast_vote(
|
|
&self.governance.program_id,
|
|
&self.realm,
|
|
&governance,
|
|
&proposal.address,
|
|
&proposal.owner_token_owner_record,
|
|
&voter.token_owner_record,
|
|
&authority.pubkey(),
|
|
&self.community_token_mint.pubkey.unwrap(),
|
|
&payer.pubkey(),
|
|
Some(voter.voter_weight_record),
|
|
None,
|
|
vote_record::Vote::Approve(vec![vote_record::VoteChoice {
|
|
rank: 0,
|
|
weight_percentage: 100,
|
|
}]),
|
|
),
|
|
];
|
|
|
|
let signer1 = Keypair::from_base58_string(&payer.to_base58_string());
|
|
let signer2 = Keypair::from_base58_string(&authority.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer1, &signer2]))
|
|
.await
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub async fn relinquish_vote(
|
|
&self,
|
|
governance: Pubkey,
|
|
proposal: &ProposalCookie,
|
|
token_owner_record: Pubkey,
|
|
authority: &Keypair,
|
|
beneficiary: Pubkey,
|
|
) -> std::result::Result<(), BanksClientError> {
|
|
let instructions = vec![spl_governance::instruction::relinquish_vote(
|
|
&self.governance.program_id,
|
|
&governance,
|
|
&proposal.address,
|
|
&token_owner_record,
|
|
&self.community_token_mint.pubkey.unwrap(),
|
|
Some(authority.pubkey()),
|
|
Some(beneficiary),
|
|
)];
|
|
|
|
let signer = Keypair::from_base58_string(&authority.to_base58_string());
|
|
|
|
self.governance
|
|
.solana
|
|
.process_transaction(&instructions, Some(&[&signer]))
|
|
.await
|
|
}
|
|
}
|