diff --git a/.changeset/solana-v3.md b/.changeset/solana-v3.md new file mode 100644 index 0000000..a9c6137 --- /dev/null +++ b/.changeset/solana-v3.md @@ -0,0 +1,10 @@ +--- +'@codama/renderers-rust': minor +--- + +- Add camelCase `rename_all` and `DisplayFromStr` for u64/i64/u128/i128 to serde feature +- Fix `featureFlags` not emitting `cfg_attr` for traits absent from defaults +- Enforce required accounts and args at compile time via constructor params +- Validate account discriminators, owners, and Anchor `try_deserialize` +- Auto-derive PDA accounts in instruction builders +- Add PDA generation with mod/page templates diff --git a/.changeset/tired-rules-rule.md b/.changeset/tired-rules-rule.md new file mode 100644 index 0000000..6574b56 --- /dev/null +++ b/.changeset/tired-rules-rule.md @@ -0,0 +1,5 @@ +--- +'@codama/renderers-rust': patch +--- + +Add support for PDA generation diff --git a/Cargo.lock b/Cargo.lock index da4d9bb..f5d9259 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -258,6 +258,15 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.100" @@ -690,6 +699,18 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + [[package]] name = "codama-renderers-rust-e2e-anchor" version = "0.0.0" @@ -720,6 +741,30 @@ dependencies = [ "solana-program-error 3.0.0", ] +[[package]] +name = "codama-renderers-rust-e2e-governance" +version = "0.0.0" +dependencies = [ + "anchor-lang", + "borsh 1.5.7", + "kaigan", + "num-derive", + "num-traits", + "serde", + "serde-big-array", + "serde_with", + "solana-account 3.0.0", + "solana-account-info 3.1.0", + "solana-address 2.2.0", + "solana-client", + "solana-cpi 3.1.0", + "solana-decode-error", + "solana-instruction 3.2.0", + "solana-program-error 3.0.0", + "spl-collections", + "thiserror 1.0.69", +] + [[package]] name = "codama-renderers-rust-e2e-memo" version = "0.0.0" @@ -1063,6 +1108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", + "serde_core", ] [[package]] @@ -1119,6 +1165,12 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "ed25519" version = "2.2.3" @@ -1516,6 +1568,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "histogram" version = "0.6.9" @@ -1642,6 +1700,30 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "2.0.0" @@ -1755,6 +1837,17 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.11.4" @@ -1763,6 +1856,8 @@ checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.16.0", + "serde", + "serde_core", ] [[package]] @@ -1877,6 +1972,15 @@ dependencies = [ "serde_json", ] +[[package]] +name = "kaigan" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f25ded719a2354f6b1a51d0c0741c25bc7afe038617664eb37f6418439eb084" +dependencies = [ + "borsh 0.10.4", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2581,6 +2685,26 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "regex" version = "1.11.3" @@ -2835,6 +2959,30 @@ dependencies = [ "windows-sys 0.61.1", ] +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -2969,9 +3117,18 @@ version = "3.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.11.4", + "schemars 0.9.0", + "schemars 1.2.1", "serde", "serde_derive", + "serde_json", "serde_with_macros", + "time", ] [[package]] @@ -3282,7 +3439,7 @@ dependencies = [ "dashmap", "futures", "futures-util", - "indexmap", + "indexmap 2.11.4", "indicatif", "log", "quinn", @@ -3393,7 +3550,7 @@ dependencies = [ "bincode", "crossbeam-channel", "futures-util", - "indexmap", + "indexmap 2.11.4", "log", "rand 0.8.5", "rayon", @@ -4743,7 +4900,7 @@ dependencies = [ "futures-util", "governor", "histogram", - "indexmap", + "indexmap 2.11.4", "itertools", "libc", "log", @@ -4931,7 +5088,7 @@ dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap", + "indexmap 2.11.4", "indicatif", "log", "rayon", @@ -5473,7 +5630,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap", + "indexmap 2.11.4", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -5487,7 +5644,7 @@ version = "0.23.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3effe7c0e86fdff4f69cdd2ccc1b96f933e24811c5441d44904e8683e27184b" dependencies = [ - "indexmap", + "indexmap 2.11.4", "toml_datetime 0.7.2", "toml_parser", "winnow", @@ -5922,12 +6079,65 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "windows-core" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-link" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index f412555..d78a267 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,12 @@ resolver = "2" [workspace.dependencies] anchor-lang = "~0.31" borsh = "^1.0" +kaigan = "^0.3" num-derive = "^0.4" num-traits = "^0.2" +serde = "^1.0" +serde-big-array = "^0.5" +serde_with = "^3.0" solana-account = "~3.0" solana-account-info = "~3.1" solana-address = "~2.2" diff --git a/e2e/anchor/src/generated/accounts/guard_v1.rs b/e2e/anchor/src/generated/accounts/guard_v1.rs index 6575b57..b5dd561 100644 --- a/e2e/anchor/src/generated/accounts/guard_v1.rs +++ b/e2e/anchor/src/generated/accounts/guard_v1.rs @@ -32,6 +32,12 @@ pub const GUARD_V1_DISCRIMINATOR: [u8; 8] = [185, 149, 156, 78, 245, 108, 172, 6 impl GuardV1 { #[inline(always)] pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..GUARD_V1_DISCRIMINATOR.len()) != Some(&GUARD_V1_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } let mut data = data; Self::deserialize(&mut data) } @@ -41,8 +47,14 @@ impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for GuardV1 { type Error = std::io::Error; fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { - let mut data: &[u8] = &(*account_info.data).borrow(); - Self::deserialize(&mut data) + if account_info.owner != &crate::WEN_TRANSFER_GUARD_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) } } @@ -69,6 +81,11 @@ pub fn fetch_all_guard_v1( let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( "Account not found: {address}" )))?; + if account.owner != crate::WEN_TRANSFER_GUARD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } let data = GuardV1::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::DecodedAccount { address, @@ -100,6 +117,11 @@ pub fn fetch_all_maybe_guard_v1( for i in 0..addresses.len() { let address = addresses[i]; if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::WEN_TRANSFER_GUARD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } let data = GuardV1::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::MaybeAccount::Exists( crate::shared::DecodedAccount { @@ -117,6 +139,15 @@ pub fn fetch_all_maybe_guard_v1( #[cfg(feature = "anchor")] impl anchor_lang::AccountDeserialize for GuardV1 { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < GUARD_V1_DISCRIMINATOR.len() + || buf[..GUARD_V1_DISCRIMINATOR.len()] != GUARD_V1_DISCRIMINATOR[..] + { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into()); + } + Self::try_deserialize_unchecked(buf) + } + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { Ok(Self::deserialize(buf)?) } @@ -137,5 +168,5 @@ impl anchor_lang::IdlBuild for GuardV1 {} #[cfg(feature = "anchor-idl-build")] impl anchor_lang::Discriminator for GuardV1 { - const DISCRIMINATOR: &[u8] = &[0; 8]; + const DISCRIMINATOR: &[u8] = &GUARD_V1_DISCRIMINATOR; } diff --git a/e2e/anchor/src/generated/instructions/create_guard.rs b/e2e/anchor/src/generated/instructions/create_guard.rs index fd28a57..15c45e7 100644 --- a/e2e/anchor/src/generated/instructions/create_guard.rs +++ b/e2e/anchor/src/generated/instructions/create_guard.rs @@ -124,62 +124,73 @@ impl CreateGuardInstructionArgs { /// /// ### Accounts: /// -/// 0. `[writable]` guard +/// 0. `[writable, optional]` guard (default to PDA derived from 'guard') /// 1. `[writable, signer]` mint -/// 2. `[writable]` mint_token_account +/// 2. `[writable, optional]` mint_token_account (default to PDA derived from 'mintTokenAccount') /// 3. `[signer]` guard_authority /// 4. `[writable, signer]` payer /// 5. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) /// 6. `[optional]` token_program (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) /// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct CreateGuardBuilder { guard: Option, - mint: Option, + mint: solana_address::Address, mint_token_account: Option, - guard_authority: Option, - payer: Option, + guard_authority: solana_address::Address, + payer: solana_address::Address, associated_token_program: Option, token_program: Option, system_program: Option, - name: Option, - symbol: Option, - uri: Option, + name: String, + symbol: String, + uri: String, cpi_rule: Option, transfer_amount_rule: Option, - additional_fields_rule: Option>, + additional_fields_rule: Vec, __remaining_accounts: Vec, } impl CreateGuardBuilder { - pub fn new() -> Self { - Self::default() + pub fn new( + mint: solana_address::Address, + guard_authority: solana_address::Address, + payer: solana_address::Address, + name: String, + symbol: String, + uri: String, + additional_fields_rule: Vec, + ) -> Self { + Self { + guard: None, + mint, + mint_token_account: None, + guard_authority, + payer, + associated_token_program: None, + token_program: None, + system_program: None, + name, + symbol, + uri, + cpi_rule: None, + transfer_amount_rule: None, + additional_fields_rule, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'guard']` #[inline(always)] pub fn guard(&mut self, guard: solana_address::Address) -> &mut Self { self.guard = Some(guard); self } - #[inline(always)] - pub fn mint(&mut self, mint: solana_address::Address) -> &mut Self { - self.mint = Some(mint); - self - } + /// `[optional account, default to PDA derived from 'mintTokenAccount']` #[inline(always)] pub fn mint_token_account(&mut self, mint_token_account: solana_address::Address) -> &mut Self { self.mint_token_account = Some(mint_token_account); self } - #[inline(always)] - pub fn guard_authority(&mut self, guard_authority: solana_address::Address) -> &mut Self { - self.guard_authority = Some(guard_authority); - self - } - #[inline(always)] - pub fn payer(&mut self, payer: solana_address::Address) -> &mut Self { - self.payer = Some(payer); - self - } /// `[optional account, default to 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` #[inline(always)] pub fn associated_token_program( @@ -201,21 +212,6 @@ impl CreateGuardBuilder { self.system_program = Some(system_program); self } - #[inline(always)] - pub fn name(&mut self, name: String) -> &mut Self { - self.name = Some(name); - self - } - #[inline(always)] - pub fn symbol(&mut self, symbol: String) -> &mut Self { - self.symbol = Some(symbol); - self - } - #[inline(always)] - pub fn uri(&mut self, uri: String) -> &mut Self { - self.uri = Some(uri); - self - } /// `[optional argument]` #[inline(always)] pub fn cpi_rule(&mut self, cpi_rule: CpiRule) -> &mut Self { @@ -228,14 +224,6 @@ impl CreateGuardBuilder { self.transfer_amount_rule = Some(transfer_amount_rule); self } - #[inline(always)] - pub fn additional_fields_rule( - &mut self, - additional_fields_rule: Vec, - ) -> &mut Self { - self.additional_fields_rule = Some(additional_fields_rule); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -253,34 +241,55 @@ impl CreateGuardBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let guard = self + .guard + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.mint).0); + let mint = self.mint; + let mint_token_account = self.mint_token_account.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.guard_authority.as_ref(), + self.token_program + .unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )) + .as_ref(), + self.mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + let guard_authority = self.guard_authority; + let payer = self.payer; + let associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); let accounts = CreateGuard { - guard: self.guard.expect("guard is not set"), - mint: self.mint.expect("mint is not set"), - mint_token_account: self - .mint_token_account - .expect("mint_token_account is not set"), - guard_authority: self.guard_authority.expect("guard_authority is not set"), - payer: self.payer.expect("payer is not set"), - associated_token_program: self.associated_token_program.unwrap_or( - solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), - ), - token_program: self.token_program.unwrap_or(solana_address::address!( - "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" - )), - system_program: self - .system_program - .unwrap_or(solana_address::address!("11111111111111111111111111111111")), + guard, + mint, + mint_token_account, + guard_authority, + payer, + associated_token_program, + token_program, + system_program, }; let args = CreateGuardInstructionArgs { - name: self.name.clone().expect("name is not set"), - symbol: self.symbol.clone().expect("symbol is not set"), - uri: self.uri.clone().expect("uri is not set"), + name: self.name.clone(), + symbol: self.symbol.clone(), + uri: self.uri.clone(), cpi_rule: self.cpi_rule.clone(), transfer_amount_rule: self.transfer_amount_rule.clone(), - additional_fields_rule: self - .additional_fields_rule - .clone() - .expect("additional_fields_rule is not set"), + additional_fields_rule: self.additional_fields_rule.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -452,97 +461,41 @@ pub struct CreateGuardCpiBuilder<'a, 'b> { } impl<'a, 'b> CreateGuardCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + mint_token_account: &'b solana_account_info::AccountInfo<'a>, + guard_authority: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + name: String, + symbol: String, + uri: String, + additional_fields_rule: Vec, + ) -> Self { let instruction = Box::new(CreateGuardCpiBuilderInstruction { - __program: program, - guard: None, - mint: None, - mint_token_account: None, - guard_authority: None, - payer: None, - associated_token_program: None, - token_program: None, - system_program: None, - name: None, - symbol: None, - uri: None, + __program, + guard, + mint, + mint_token_account, + guard_authority, + payer, + associated_token_program, + token_program, + system_program, + name, + symbol, + uri, cpi_rule: None, transfer_amount_rule: None, - additional_fields_rule: None, + additional_fields_rule, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn guard(&mut self, guard: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.guard = Some(guard); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.mint = Some(mint); - self - } - #[inline(always)] - pub fn mint_token_account( - &mut self, - mint_token_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.mint_token_account = Some(mint_token_account); - self - } - #[inline(always)] - pub fn guard_authority( - &mut self, - guard_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.guard_authority = Some(guard_authority); - self - } - #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); - self - } - #[inline(always)] - pub fn associated_token_program( - &mut self, - associated_token_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.associated_token_program = Some(associated_token_program); - self - } - #[inline(always)] - pub fn token_program( - &mut self, - token_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.token_program = Some(token_program); - self - } - #[inline(always)] - pub fn system_program( - &mut self, - system_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.system_program = Some(system_program); - self - } - #[inline(always)] - pub fn name(&mut self, name: String) -> &mut Self { - self.instruction.name = Some(name); - self - } - #[inline(always)] - pub fn symbol(&mut self, symbol: String) -> &mut Self { - self.instruction.symbol = Some(symbol); - self - } - #[inline(always)] - pub fn uri(&mut self, uri: String) -> &mut Self { - self.instruction.uri = Some(uri); - self - } /// `[optional argument]` #[inline(always)] pub fn cpi_rule(&mut self, cpi_rule: CpiRule) -> &mut Self { @@ -555,14 +508,6 @@ impl<'a, 'b> CreateGuardCpiBuilder<'a, 'b> { self.instruction.transfer_amount_rule = Some(transfer_amount_rule); self } - #[inline(always)] - pub fn additional_fields_rule( - &mut self, - additional_fields_rule: Vec, - ) -> &mut Self { - self.instruction.additional_fields_rule = Some(additional_fields_rule); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -598,50 +543,23 @@ impl<'a, 'b> CreateGuardCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = CreateGuardInstructionArgs { - name: self.instruction.name.clone().expect("name is not set"), - symbol: self.instruction.symbol.clone().expect("symbol is not set"), - uri: self.instruction.uri.clone().expect("uri is not set"), + name: self.instruction.name.clone(), + symbol: self.instruction.symbol.clone(), + uri: self.instruction.uri.clone(), cpi_rule: self.instruction.cpi_rule.clone(), transfer_amount_rule: self.instruction.transfer_amount_rule.clone(), - additional_fields_rule: self - .instruction - .additional_fields_rule - .clone() - .expect("additional_fields_rule is not set"), + additional_fields_rule: self.instruction.additional_fields_rule.clone(), }; let instruction = CreateGuardCpi { __program: self.instruction.__program, - - guard: self.instruction.guard.expect("guard is not set"), - - mint: self.instruction.mint.expect("mint is not set"), - - mint_token_account: self - .instruction - .mint_token_account - .expect("mint_token_account is not set"), - - guard_authority: self - .instruction - .guard_authority - .expect("guard_authority is not set"), - - payer: self.instruction.payer.expect("payer is not set"), - - associated_token_program: self - .instruction - .associated_token_program - .expect("associated_token_program is not set"), - - token_program: self - .instruction - .token_program - .expect("token_program is not set"), - - system_program: self - .instruction - .system_program - .expect("system_program is not set"), + guard: self.instruction.guard, + mint: self.instruction.mint, + mint_token_account: self.instruction.mint_token_account, + guard_authority: self.instruction.guard_authority, + payer: self.instruction.payer, + associated_token_program: self.instruction.associated_token_program, + token_program: self.instruction.token_program, + system_program: self.instruction.system_program, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -654,20 +572,20 @@ impl<'a, 'b> CreateGuardCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct CreateGuardCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - guard: Option<&'b solana_account_info::AccountInfo<'a>>, - mint: Option<&'b solana_account_info::AccountInfo<'a>>, - mint_token_account: Option<&'b solana_account_info::AccountInfo<'a>>, - guard_authority: Option<&'b solana_account_info::AccountInfo<'a>>, - payer: Option<&'b solana_account_info::AccountInfo<'a>>, - associated_token_program: Option<&'b solana_account_info::AccountInfo<'a>>, - token_program: Option<&'b solana_account_info::AccountInfo<'a>>, - system_program: Option<&'b solana_account_info::AccountInfo<'a>>, - name: Option, - symbol: Option, - uri: Option, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + mint_token_account: &'b solana_account_info::AccountInfo<'a>, + guard_authority: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + name: String, + symbol: String, + uri: String, cpi_rule: Option, transfer_amount_rule: Option, - additional_fields_rule: Option>, + additional_fields_rule: Vec, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/anchor/src/generated/instructions/execute.rs b/e2e/anchor/src/generated/instructions/execute.rs index 410cbe4..5ce2c95 100644 --- a/e2e/anchor/src/generated/instructions/execute.rs +++ b/e2e/anchor/src/generated/instructions/execute.rs @@ -121,49 +121,44 @@ impl ExecuteInstructionArgs { /// 1. `[]` mint /// 2. `[]` destination_account /// 3. `[]` owner_delegate -/// 4. `[]` extra_metas_account +/// 4. `[optional]` extra_metas_account (default to PDA derived from 'extraMetasAccount') /// 5. `[]` guard /// 6. `[optional]` instruction_sysvar_account (default to `Sysvar1nstructions1111111111111111111111111`) -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ExecuteBuilder { - source_account: Option, - mint: Option, - destination_account: Option, - owner_delegate: Option, + source_account: solana_address::Address, + mint: solana_address::Address, + destination_account: solana_address::Address, + owner_delegate: solana_address::Address, extra_metas_account: Option, - guard: Option, + guard: solana_address::Address, instruction_sysvar_account: Option, - amount: Option, + amount: u64, __remaining_accounts: Vec, } impl ExecuteBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn source_account(&mut self, source_account: solana_address::Address) -> &mut Self { - self.source_account = Some(source_account); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: solana_address::Address) -> &mut Self { - self.mint = Some(mint); - self - } - #[inline(always)] - pub fn destination_account( - &mut self, + pub fn new( + source_account: solana_address::Address, + mint: solana_address::Address, destination_account: solana_address::Address, - ) -> &mut Self { - self.destination_account = Some(destination_account); - self - } - #[inline(always)] - pub fn owner_delegate(&mut self, owner_delegate: solana_address::Address) -> &mut Self { - self.owner_delegate = Some(owner_delegate); - self + owner_delegate: solana_address::Address, + guard: solana_address::Address, + amount: u64, + ) -> Self { + Self { + source_account, + mint, + destination_account, + owner_delegate, + extra_metas_account: None, + guard, + instruction_sysvar_account: None, + amount, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'extraMetasAccount']` #[inline(always)] pub fn extra_metas_account( &mut self, @@ -172,11 +167,6 @@ impl ExecuteBuilder { self.extra_metas_account = Some(extra_metas_account); self } - #[inline(always)] - pub fn guard(&mut self, guard: solana_address::Address) -> &mut Self { - self.guard = Some(guard); - self - } /// `[optional account, default to 'Sysvar1nstructions1111111111111111111111111']` #[inline(always)] pub fn instruction_sysvar_account( @@ -186,11 +176,6 @@ impl ExecuteBuilder { self.instruction_sysvar_account = Some(instruction_sysvar_account); self } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.amount = Some(amount); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -208,23 +193,30 @@ impl ExecuteBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let source_account = self.source_account; + let mint = self.mint; + let destination_account = self.destination_account; + let owner_delegate = self.owner_delegate; + let extra_metas_account = self + .extra_metas_account + .unwrap_or_else(|| crate::pdas::find_extra_metas_account_pda(&self.mint).0); + let guard = self.guard; + let instruction_sysvar_account = + self.instruction_sysvar_account + .unwrap_or(solana_address::address!( + "Sysvar1nstructions1111111111111111111111111" + )); let accounts = Execute { - source_account: self.source_account.expect("source_account is not set"), - mint: self.mint.expect("mint is not set"), - destination_account: self - .destination_account - .expect("destination_account is not set"), - owner_delegate: self.owner_delegate.expect("owner_delegate is not set"), - extra_metas_account: self - .extra_metas_account - .expect("extra_metas_account is not set"), - guard: self.guard.expect("guard is not set"), - instruction_sysvar_account: self.instruction_sysvar_account.unwrap_or( - solana_address::address!("Sysvar1nstructions1111111111111111111111111"), - ), + source_account, + mint, + destination_account, + owner_delegate, + extra_metas_account, + guard, + instruction_sysvar_account, }; let args = ExecuteInstructionArgs { - amount: self.amount.clone().expect("amount is not set"), + amount: self.amount.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -394,75 +386,30 @@ pub struct ExecuteCpiBuilder<'a, 'b> { } impl<'a, 'b> ExecuteCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { - let instruction = Box::new(ExecuteCpiBuilderInstruction { - __program: program, - source_account: None, - mint: None, - destination_account: None, - owner_delegate: None, - extra_metas_account: None, - guard: None, - instruction_sysvar_account: None, - amount: None, - __remaining_accounts: Vec::new(), - }); - Self { instruction } - } - #[inline(always)] - pub fn source_account( - &mut self, + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, source_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.source_account = Some(source_account); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.mint = Some(mint); - self - } - #[inline(always)] - pub fn destination_account( - &mut self, + mint: &'b solana_account_info::AccountInfo<'a>, destination_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.destination_account = Some(destination_account); - self - } - #[inline(always)] - pub fn owner_delegate( - &mut self, owner_delegate: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.owner_delegate = Some(owner_delegate); - self - } - #[inline(always)] - pub fn extra_metas_account( - &mut self, extra_metas_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.extra_metas_account = Some(extra_metas_account); - self - } - #[inline(always)] - pub fn guard(&mut self, guard: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.guard = Some(guard); - self - } - #[inline(always)] - pub fn instruction_sysvar_account( - &mut self, + guard: &'b solana_account_info::AccountInfo<'a>, instruction_sysvar_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.instruction_sysvar_account = Some(instruction_sysvar_account); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.instruction.amount = Some(amount); - self + amount: u64, + ) -> Self { + let instruction = Box::new(ExecuteCpiBuilderInstruction { + __program, + source_account, + mint, + destination_account, + owner_delegate, + extra_metas_account, + guard, + instruction_sysvar_account, + amount, + __remaining_accounts: Vec::new(), + }); + Self { instruction } } /// Add an additional account to the instruction. #[inline(always)] @@ -499,39 +446,17 @@ impl<'a, 'b> ExecuteCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = ExecuteInstructionArgs { - amount: self.instruction.amount.clone().expect("amount is not set"), + amount: self.instruction.amount.clone(), }; let instruction = ExecuteCpi { __program: self.instruction.__program, - - source_account: self - .instruction - .source_account - .expect("source_account is not set"), - - mint: self.instruction.mint.expect("mint is not set"), - - destination_account: self - .instruction - .destination_account - .expect("destination_account is not set"), - - owner_delegate: self - .instruction - .owner_delegate - .expect("owner_delegate is not set"), - - extra_metas_account: self - .instruction - .extra_metas_account - .expect("extra_metas_account is not set"), - - guard: self.instruction.guard.expect("guard is not set"), - - instruction_sysvar_account: self - .instruction - .instruction_sysvar_account - .expect("instruction_sysvar_account is not set"), + source_account: self.instruction.source_account, + mint: self.instruction.mint, + destination_account: self.instruction.destination_account, + owner_delegate: self.instruction.owner_delegate, + extra_metas_account: self.instruction.extra_metas_account, + guard: self.instruction.guard, + instruction_sysvar_account: self.instruction.instruction_sysvar_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -544,14 +469,14 @@ impl<'a, 'b> ExecuteCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct ExecuteCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - source_account: Option<&'b solana_account_info::AccountInfo<'a>>, - mint: Option<&'b solana_account_info::AccountInfo<'a>>, - destination_account: Option<&'b solana_account_info::AccountInfo<'a>>, - owner_delegate: Option<&'b solana_account_info::AccountInfo<'a>>, - extra_metas_account: Option<&'b solana_account_info::AccountInfo<'a>>, - guard: Option<&'b solana_account_info::AccountInfo<'a>>, - instruction_sysvar_account: Option<&'b solana_account_info::AccountInfo<'a>>, - amount: Option, + source_account: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + destination_account: &'b solana_account_info::AccountInfo<'a>, + owner_delegate: &'b solana_account_info::AccountInfo<'a>, + extra_metas_account: &'b solana_account_info::AccountInfo<'a>, + guard: &'b solana_account_info::AccountInfo<'a>, + instruction_sysvar_account: &'b solana_account_info::AccountInfo<'a>, + amount: u64, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/anchor/src/generated/instructions/initialize.rs b/e2e/anchor/src/generated/instructions/initialize.rs index ce30b3c..9527f44 100644 --- a/e2e/anchor/src/generated/instructions/initialize.rs +++ b/e2e/anchor/src/generated/instructions/initialize.rs @@ -94,27 +94,41 @@ impl Default for InitializeInstructionData { /// /// ### Accounts: /// -/// 0. `[writable]` extra_metas_account +/// 0. `[writable, optional]` extra_metas_account (default to PDA derived from 'extraMetasAccount') /// 1. `[]` guard /// 2. `[]` mint /// 3. `[writable, signer]` transfer_hook_authority /// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) /// 5. `[writable, signer]` payer -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct InitializeBuilder { extra_metas_account: Option, - guard: Option, - mint: Option, - transfer_hook_authority: Option, + guard: solana_address::Address, + mint: solana_address::Address, + transfer_hook_authority: solana_address::Address, system_program: Option, - payer: Option, + payer: solana_address::Address, __remaining_accounts: Vec, } impl InitializeBuilder { - pub fn new() -> Self { - Self::default() + pub fn new( + guard: solana_address::Address, + mint: solana_address::Address, + transfer_hook_authority: solana_address::Address, + payer: solana_address::Address, + ) -> Self { + Self { + extra_metas_account: None, + guard, + mint, + transfer_hook_authority, + system_program: None, + payer, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'extraMetasAccount']` #[inline(always)] pub fn extra_metas_account( &mut self, @@ -123,35 +137,12 @@ impl InitializeBuilder { self.extra_metas_account = Some(extra_metas_account); self } - #[inline(always)] - pub fn guard(&mut self, guard: solana_address::Address) -> &mut Self { - self.guard = Some(guard); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: solana_address::Address) -> &mut Self { - self.mint = Some(mint); - self - } - #[inline(always)] - pub fn transfer_hook_authority( - &mut self, - transfer_hook_authority: solana_address::Address, - ) -> &mut Self { - self.transfer_hook_authority = Some(transfer_hook_authority); - self - } /// `[optional account, default to '11111111111111111111111111111111']` #[inline(always)] pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { self.system_program = Some(system_program); self } - #[inline(always)] - pub fn payer(&mut self, payer: solana_address::Address) -> &mut Self { - self.payer = Some(payer); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -169,19 +160,23 @@ impl InitializeBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let extra_metas_account = self + .extra_metas_account + .unwrap_or_else(|| crate::pdas::find_extra_metas_account_pda(&self.mint).0); + let guard = self.guard; + let mint = self.mint; + let transfer_hook_authority = self.transfer_hook_authority; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let payer = self.payer; let accounts = Initialize { - extra_metas_account: self - .extra_metas_account - .expect("extra_metas_account is not set"), - guard: self.guard.expect("guard is not set"), - mint: self.mint.expect("mint is not set"), - transfer_hook_authority: self - .transfer_hook_authority - .expect("transfer_hook_authority is not set"), - system_program: self - .system_program - .unwrap_or(solana_address::address!("11111111111111111111111111111111")), - payer: self.payer.expect("payer is not set"), + extra_metas_account, + guard, + mint, + transfer_hook_authority, + system_program, + payer, }; accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) @@ -331,58 +326,27 @@ pub struct InitializeCpiBuilder<'a, 'b> { } impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + extra_metas_account: &'b solana_account_info::AccountInfo<'a>, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + transfer_hook_authority: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { let instruction = Box::new(InitializeCpiBuilderInstruction { - __program: program, - extra_metas_account: None, - guard: None, - mint: None, - transfer_hook_authority: None, - system_program: None, - payer: None, + __program, + extra_metas_account, + guard, + mint, + transfer_hook_authority, + system_program, + payer, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn extra_metas_account( - &mut self, - extra_metas_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.extra_metas_account = Some(extra_metas_account); - self - } - #[inline(always)] - pub fn guard(&mut self, guard: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.guard = Some(guard); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.mint = Some(mint); - self - } - #[inline(always)] - pub fn transfer_hook_authority( - &mut self, - transfer_hook_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.transfer_hook_authority = Some(transfer_hook_authority); - self - } - #[inline(always)] - pub fn system_program( - &mut self, - system_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.system_program = Some(system_program); - self - } - #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -419,27 +383,12 @@ impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let instruction = InitializeCpi { __program: self.instruction.__program, - - extra_metas_account: self - .instruction - .extra_metas_account - .expect("extra_metas_account is not set"), - - guard: self.instruction.guard.expect("guard is not set"), - - mint: self.instruction.mint.expect("mint is not set"), - - transfer_hook_authority: self - .instruction - .transfer_hook_authority - .expect("transfer_hook_authority is not set"), - - system_program: self - .instruction - .system_program - .expect("system_program is not set"), - - payer: self.instruction.payer.expect("payer is not set"), + extra_metas_account: self.instruction.extra_metas_account, + guard: self.instruction.guard, + mint: self.instruction.mint, + transfer_hook_authority: self.instruction.transfer_hook_authority, + system_program: self.instruction.system_program, + payer: self.instruction.payer, }; instruction.invoke_signed_with_remaining_accounts( signers_seeds, @@ -451,12 +400,12 @@ impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct InitializeCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - extra_metas_account: Option<&'b solana_account_info::AccountInfo<'a>>, - guard: Option<&'b solana_account_info::AccountInfo<'a>>, - mint: Option<&'b solana_account_info::AccountInfo<'a>>, - transfer_hook_authority: Option<&'b solana_account_info::AccountInfo<'a>>, - system_program: Option<&'b solana_account_info::AccountInfo<'a>>, - payer: Option<&'b solana_account_info::AccountInfo<'a>>, + extra_metas_account: &'b solana_account_info::AccountInfo<'a>, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + transfer_hook_authority: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/anchor/src/generated/instructions/update_guard.rs b/e2e/anchor/src/generated/instructions/update_guard.rs index 9eb70a1..3d1b0fb 100644 --- a/e2e/anchor/src/generated/instructions/update_guard.rs +++ b/e2e/anchor/src/generated/instructions/update_guard.rs @@ -114,50 +114,57 @@ impl UpdateGuardInstructionArgs { /// /// ### Accounts: /// -/// 0. `[writable]` guard +/// 0. `[writable, optional]` guard (default to PDA derived from 'guard') /// 1. `[]` mint -/// 2. `[]` token_account +/// 2. `[optional]` token_account (default to PDA derived from 'tokenAccount') /// 3. `[signer]` guard_authority /// 4. `[optional]` token_program (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) /// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct UpdateGuardBuilder { guard: Option, - mint: Option, + mint: solana_address::Address, token_account: Option, - guard_authority: Option, + guard_authority: solana_address::Address, token_program: Option, system_program: Option, cpi_rule: Option, transfer_amount_rule: Option, - additional_fields_rule: Option>, + additional_fields_rule: Vec, __remaining_accounts: Vec, } impl UpdateGuardBuilder { - pub fn new() -> Self { - Self::default() + pub fn new( + mint: solana_address::Address, + guard_authority: solana_address::Address, + additional_fields_rule: Vec, + ) -> Self { + Self { + guard: None, + mint, + token_account: None, + guard_authority, + token_program: None, + system_program: None, + cpi_rule: None, + transfer_amount_rule: None, + additional_fields_rule, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'guard']` #[inline(always)] pub fn guard(&mut self, guard: solana_address::Address) -> &mut Self { self.guard = Some(guard); self } - #[inline(always)] - pub fn mint(&mut self, mint: solana_address::Address) -> &mut Self { - self.mint = Some(mint); - self - } + /// `[optional account, default to PDA derived from 'tokenAccount']` #[inline(always)] pub fn token_account(&mut self, token_account: solana_address::Address) -> &mut Self { self.token_account = Some(token_account); self } - #[inline(always)] - pub fn guard_authority(&mut self, guard_authority: solana_address::Address) -> &mut Self { - self.guard_authority = Some(guard_authority); - self - } /// `[optional account, default to 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb']` #[inline(always)] pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { @@ -182,14 +189,6 @@ impl UpdateGuardBuilder { self.transfer_amount_rule = Some(transfer_amount_rule); self } - #[inline(always)] - pub fn additional_fields_rule( - &mut self, - additional_fields_rule: Vec, - ) -> &mut Self { - self.additional_fields_rule = Some(additional_fields_rule); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -207,25 +206,44 @@ impl UpdateGuardBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let guard = self + .guard + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.mint).0); + let mint = self.mint; + let token_account = self.token_account.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.guard_authority.as_ref(), + self.token_program + .unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )) + .as_ref(), + self.mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + let guard_authority = self.guard_authority; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); let accounts = UpdateGuard { - guard: self.guard.expect("guard is not set"), - mint: self.mint.expect("mint is not set"), - token_account: self.token_account.expect("token_account is not set"), - guard_authority: self.guard_authority.expect("guard_authority is not set"), - token_program: self.token_program.unwrap_or(solana_address::address!( - "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" - )), - system_program: self - .system_program - .unwrap_or(solana_address::address!("11111111111111111111111111111111")), + guard, + mint, + token_account, + guard_authority, + token_program, + system_program, }; let args = UpdateGuardInstructionArgs { cpi_rule: self.cpi_rule.clone(), transfer_amount_rule: self.transfer_amount_rule.clone(), - additional_fields_rule: self - .additional_fields_rule - .clone() - .expect("additional_fields_rule is not set"), + additional_fields_rule: self.additional_fields_rule.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -381,64 +399,31 @@ pub struct UpdateGuardCpiBuilder<'a, 'b> { } impl<'a, 'b> UpdateGuardCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + token_account: &'b solana_account_info::AccountInfo<'a>, + guard_authority: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + additional_fields_rule: Vec, + ) -> Self { let instruction = Box::new(UpdateGuardCpiBuilderInstruction { - __program: program, - guard: None, - mint: None, - token_account: None, - guard_authority: None, - token_program: None, - system_program: None, + __program, + guard, + mint, + token_account, + guard_authority, + token_program, + system_program, cpi_rule: None, transfer_amount_rule: None, - additional_fields_rule: None, + additional_fields_rule, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn guard(&mut self, guard: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.guard = Some(guard); - self - } - #[inline(always)] - pub fn mint(&mut self, mint: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.mint = Some(mint); - self - } - #[inline(always)] - pub fn token_account( - &mut self, - token_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.token_account = Some(token_account); - self - } - #[inline(always)] - pub fn guard_authority( - &mut self, - guard_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.guard_authority = Some(guard_authority); - self - } - #[inline(always)] - pub fn token_program( - &mut self, - token_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.token_program = Some(token_program); - self - } - #[inline(always)] - pub fn system_program( - &mut self, - system_program: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.system_program = Some(system_program); - self - } /// `[optional argument]` #[inline(always)] pub fn cpi_rule(&mut self, cpi_rule: CpiRule) -> &mut Self { @@ -451,14 +436,6 @@ impl<'a, 'b> UpdateGuardCpiBuilder<'a, 'b> { self.instruction.transfer_amount_rule = Some(transfer_amount_rule); self } - #[inline(always)] - pub fn additional_fields_rule( - &mut self, - additional_fields_rule: Vec, - ) -> &mut Self { - self.instruction.additional_fields_rule = Some(additional_fields_rule); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -496,38 +473,16 @@ impl<'a, 'b> UpdateGuardCpiBuilder<'a, 'b> { let args = UpdateGuardInstructionArgs { cpi_rule: self.instruction.cpi_rule.clone(), transfer_amount_rule: self.instruction.transfer_amount_rule.clone(), - additional_fields_rule: self - .instruction - .additional_fields_rule - .clone() - .expect("additional_fields_rule is not set"), + additional_fields_rule: self.instruction.additional_fields_rule.clone(), }; let instruction = UpdateGuardCpi { __program: self.instruction.__program, - - guard: self.instruction.guard.expect("guard is not set"), - - mint: self.instruction.mint.expect("mint is not set"), - - token_account: self - .instruction - .token_account - .expect("token_account is not set"), - - guard_authority: self - .instruction - .guard_authority - .expect("guard_authority is not set"), - - token_program: self - .instruction - .token_program - .expect("token_program is not set"), - - system_program: self - .instruction - .system_program - .expect("system_program is not set"), + guard: self.instruction.guard, + mint: self.instruction.mint, + token_account: self.instruction.token_account, + guard_authority: self.instruction.guard_authority, + token_program: self.instruction.token_program, + system_program: self.instruction.system_program, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -540,15 +495,15 @@ impl<'a, 'b> UpdateGuardCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct UpdateGuardCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - guard: Option<&'b solana_account_info::AccountInfo<'a>>, - mint: Option<&'b solana_account_info::AccountInfo<'a>>, - token_account: Option<&'b solana_account_info::AccountInfo<'a>>, - guard_authority: Option<&'b solana_account_info::AccountInfo<'a>>, - token_program: Option<&'b solana_account_info::AccountInfo<'a>>, - system_program: Option<&'b solana_account_info::AccountInfo<'a>>, + guard: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + token_account: &'b solana_account_info::AccountInfo<'a>, + guard_authority: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, cpi_rule: Option, transfer_amount_rule: Option, - additional_fields_rule: Option>, + additional_fields_rule: Vec, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/anchor/src/generated/mod.rs b/e2e/anchor/src/generated/mod.rs index e0d740a..d37d822 100644 --- a/e2e/anchor/src/generated/mod.rs +++ b/e2e/anchor/src/generated/mod.rs @@ -8,6 +8,7 @@ pub mod accounts; pub mod errors; pub mod instructions; +pub mod pdas; pub mod programs; pub mod shared; pub mod types; diff --git a/e2e/anchor/src/generated/pdas/extra_metas_account.rs b/e2e/anchor/src/generated/pdas/extra_metas_account.rs new file mode 100644 index 0000000..408a008 --- /dev/null +++ b/e2e/anchor/src/generated/pdas/extra_metas_account.rs @@ -0,0 +1,29 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::WEN_TRANSFER_GUARD_ID; + +pub const EXTRA_METAS_ACCOUNT_SEED: &'static [u8] = &[ + 101, 120, 116, 114, 97, 45, 97, 99, 99, 111, 117, 110, 116, 45, 109, 101, 116, 97, 115, +]; +pub fn create_extra_metas_account_pda( + mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[EXTRA_METAS_ACCOUNT_SEED, mint.as_ref(), &[bump]], + &WEN_TRANSFER_GUARD_ID, + ) +} +pub fn find_extra_metas_account_pda(mint: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[EXTRA_METAS_ACCOUNT_SEED, mint.as_ref()], + &WEN_TRANSFER_GUARD_ID, + ) +} diff --git a/e2e/anchor/src/generated/pdas/guard.rs b/e2e/anchor/src/generated/pdas/guard.rs new file mode 100644 index 0000000..a8c7888 --- /dev/null +++ b/e2e/anchor/src/generated/pdas/guard.rs @@ -0,0 +1,31 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::WEN_TRANSFER_GUARD_ID; + +pub const GUARD_SEED_0: &'static [u8] = &[ + 119, 101, 110, 95, 116, 111, 107, 101, 110, 95, 116, 114, 97, 110, 115, 102, 101, 114, 95, 103, + 117, 97, 114, 100, +]; +pub const GUARD_SEED_1: &'static [u8] = &[103, 117, 97, 114, 100, 95, 118, 49]; +pub fn create_guard_pda( + mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[GUARD_SEED_0, GUARD_SEED_1, mint.as_ref(), &[bump]], + &WEN_TRANSFER_GUARD_ID, + ) +} +pub fn find_guard_pda(mint: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[GUARD_SEED_0, GUARD_SEED_1, mint.as_ref()], + &WEN_TRANSFER_GUARD_ID, + ) +} diff --git a/e2e/anchor/src/generated/pdas/mod.rs b/e2e/anchor/src/generated/pdas/mod.rs new file mode 100644 index 0000000..25ee0c4 --- /dev/null +++ b/e2e/anchor/src/generated/pdas/mod.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod extra_metas_account; +pub mod guard; + +pub use self::extra_metas_account::*; +pub use self::guard::*; diff --git a/e2e/dummy/idl.json b/e2e/dummy/idl.json index b81b84d..110235e 100644 --- a/e2e/dummy/idl.json +++ b/e2e/dummy/idl.json @@ -2,7 +2,44 @@ "kind": "rootNode", "program": { "kind": "programNode", - "pdas": [], + "pdas": [ + { + "kind": "pdaNode", + "name": "derivedAccount", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "value": { "kind": "stringValueNode", "string": "derived" } + }, + { + "kind": "variablePdaSeedNode", + "name": "mint", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + }, + { + "kind": "variablePdaSeedNode", + "name": "tokenProgram", + "type": { "kind": "publicKeyTypeNode" }, + "docs": [] + } + ], + "docs": [] + }, + { + "kind": "pdaNode", + "name": "globalConfig", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { "kind": "stringTypeNode", "encoding": "utf8" }, + "value": { "kind": "stringValueNode", "string": "global_config" } + } + ], + "docs": ["A PDA with only constant seeds — address is deterministic."] + } + ], "accounts": [], "instructions": [ { @@ -133,6 +170,116 @@ } ], "arguments": [] + }, + { + "kind": "instructionNode", + "name": "instruction8", + "optionalAccountStrategy": "programId", + "docs": ["Testing pdaLinkNode auto-derivation with upstream defaulted seed account"], + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "mint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + }, + { + "kind": "instructionAccountNode", + "name": "derivedAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "derivedAccount" + }, + "seeds": [ + { + "kind": "pdaSeedValueNode", + "name": "mint", + "value": { "kind": "accountValueNode", "name": "mint" } + }, + { + "kind": "pdaSeedValueNode", + "name": "tokenProgram", + "value": { "kind": "accountValueNode", "name": "tokenProgram" } + } + ] + } + } + ], + "arguments": [], + "remainingAccounts": [] + }, + { + "kind": "instructionNode", + "name": "instruction9", + "optionalAccountStrategy": "programId", + "docs": ["Testing precomputed PDA constant for zero-variable-seed linked PDA"], + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "globalConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "globalConfig" + }, + "seeds": [] + } + } + ], + "arguments": [] + }, + { + "kind": "instructionNode", + "name": "instruction10", + "optionalAccountStrategy": "programId", + "docs": ["Testing programIdValueNode account default"], + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "owner", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "selfProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "programIdValueNode" + } + } + ], + "arguments": [] } ], "definedTypes": [], diff --git a/e2e/dummy/src/generated/instructions/instruction1.rs b/e2e/dummy/src/generated/instructions/instruction1.rs index cae4c09..f635f68 100644 --- a/e2e/dummy/src/generated/instructions/instruction1.rs +++ b/e2e/dummy/src/generated/instructions/instruction1.rs @@ -161,9 +161,9 @@ pub struct Instruction1CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction1CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { let instruction = Box::new(Instruction1CpiBuilderInstruction { - __program: program, + __program, __remaining_accounts: Vec::new(), }); Self { instruction } diff --git a/e2e/dummy/src/generated/instructions/instruction10.rs b/e2e/dummy/src/generated/instructions/instruction10.rs new file mode 100644 index 0000000..cb64872 --- /dev/null +++ b/e2e/dummy/src/generated/instructions/instruction10.rs @@ -0,0 +1,299 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +#[derive(Debug)] +pub struct Instruction10 { + pub owner: solana_address::Address, + + pub self_program: solana_address::Address, +} + +impl Instruction10 { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.self_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = Instruction10InstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Instruction10InstructionData {} + +impl Instruction10InstructionData { + pub fn new() -> Self { + Self {} + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for Instruction10InstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Instruction10`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` self_program +#[derive(Clone, Debug)] +pub struct Instruction10Builder { + owner: solana_address::Address, + self_program: Option, + __remaining_accounts: Vec, +} + +impl Instruction10Builder { + pub fn new(owner: solana_address::Address) -> Self { + Self { + owner, + self_program: None, + __remaining_accounts: Vec::new(), + } + } + #[inline(always)] + pub fn self_program(&mut self, self_program: solana_address::Address) -> &mut Self { + self.self_program = Some(self_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let owner = self.owner; + let self_program = self.self_program.unwrap_or(crate::DUMMY_ID); + let accounts = Instruction10 { + owner, + self_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `instruction10` CPI accounts. +pub struct Instruction10CpiAccounts<'a, 'b> { + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub self_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `instruction10` CPI instruction. +pub struct Instruction10Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub self_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> Instruction10Cpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: Instruction10CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + self_program: accounts.self_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.self_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = Instruction10InstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(3 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.self_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Instruction10` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` self_program +#[derive(Clone, Debug)] +pub struct Instruction10CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> Instruction10CpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(Instruction10CpiBuilderInstruction { + __program, + owner, + self_program: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn self_program( + &mut self, + self_program: &'b solana_account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.self_program = Some(self_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = Instruction10Cpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + self_program: self + .instruction + .self_program + .unwrap_or(self.instruction.__program), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct Instruction10CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + self_program: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/dummy/src/generated/instructions/instruction2.rs b/e2e/dummy/src/generated/instructions/instruction2.rs index d946ef0..2ff4c32 100644 --- a/e2e/dummy/src/generated/instructions/instruction2.rs +++ b/e2e/dummy/src/generated/instructions/instruction2.rs @@ -161,9 +161,9 @@ pub struct Instruction2CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction2CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { let instruction = Box::new(Instruction2CpiBuilderInstruction { - __program: program, + __program, __remaining_accounts: Vec::new(), }); Self { instruction } diff --git a/e2e/dummy/src/generated/instructions/instruction3.rs b/e2e/dummy/src/generated/instructions/instruction3.rs index 876b035..631f78e 100644 --- a/e2e/dummy/src/generated/instructions/instruction3.rs +++ b/e2e/dummy/src/generated/instructions/instruction3.rs @@ -165,9 +165,9 @@ pub struct Instruction3CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction3CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { let instruction = Box::new(Instruction3CpiBuilderInstruction { - __program: program, + __program, __remaining_accounts: Vec::new(), }); Self { instruction } diff --git a/e2e/dummy/src/generated/instructions/instruction4.rs b/e2e/dummy/src/generated/instructions/instruction4.rs index 860b06e..817fc74 100644 --- a/e2e/dummy/src/generated/instructions/instruction4.rs +++ b/e2e/dummy/src/generated/instructions/instruction4.rs @@ -74,20 +74,18 @@ impl Instruction4InstructionArgs { /// /// ### Accounts: /// -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Instruction4Builder { - my_argument: Option, + my_argument: u64, __remaining_accounts: Vec, } impl Instruction4Builder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn my_argument(&mut self, my_argument: u64) -> &mut Self { - self.my_argument = Some(my_argument); - self + pub fn new(my_argument: u64) -> Self { + Self { + my_argument, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -108,7 +106,7 @@ impl Instruction4Builder { pub fn instruction(&self) -> solana_instruction::Instruction { let accounts = Instruction4 {}; let args = Instruction4InstructionArgs { - my_argument: self.my_argument.clone().expect("my_argument is not set"), + my_argument: self.my_argument.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -197,19 +195,14 @@ pub struct Instruction4CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction4CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>, my_argument: u64) -> Self { let instruction = Box::new(Instruction4CpiBuilderInstruction { - __program: program, - my_argument: None, + __program, + my_argument, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn my_argument(&mut self, my_argument: u64) -> &mut Self { - self.instruction.my_argument = Some(my_argument); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -245,11 +238,7 @@ impl<'a, 'b> Instruction4CpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = Instruction4InstructionArgs { - my_argument: self - .instruction - .my_argument - .clone() - .expect("my_argument is not set"), + my_argument: self.instruction.my_argument.clone(), }; let instruction = Instruction4Cpi { __program: self.instruction.__program, @@ -265,7 +254,7 @@ impl<'a, 'b> Instruction4CpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct Instruction4CpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - my_argument: Option, + my_argument: u64, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/dummy/src/generated/instructions/instruction5.rs b/e2e/dummy/src/generated/instructions/instruction5.rs index da1301e..2b335d6 100644 --- a/e2e/dummy/src/generated/instructions/instruction5.rs +++ b/e2e/dummy/src/generated/instructions/instruction5.rs @@ -198,9 +198,9 @@ pub struct Instruction5CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction5CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { let instruction = Box::new(Instruction5CpiBuilderInstruction { - __program: program, + __program, my_argument: None, __remaining_accounts: Vec::new(), }); diff --git a/e2e/dummy/src/generated/instructions/instruction6.rs b/e2e/dummy/src/generated/instructions/instruction6.rs index a6762bf..8d64e61 100644 --- a/e2e/dummy/src/generated/instructions/instruction6.rs +++ b/e2e/dummy/src/generated/instructions/instruction6.rs @@ -61,20 +61,18 @@ impl Default for Instruction6InstructionData { /// ### Accounts: /// /// 0. `[writable]` my_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Instruction6Builder { - my_account: Option, + my_account: solana_address::Address, __remaining_accounts: Vec, } impl Instruction6Builder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn my_account(&mut self, my_account: solana_address::Address) -> &mut Self { - self.my_account = Some(my_account); - self + pub fn new(my_account: solana_address::Address) -> Self { + Self { + my_account, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -93,9 +91,8 @@ impl Instruction6Builder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = Instruction6 { - my_account: self.my_account.expect("my_account is not set"), - }; + let my_account = self.my_account; + let accounts = Instruction6 { my_account }; accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) } @@ -192,22 +189,17 @@ pub struct Instruction6CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction6CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + my_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { let instruction = Box::new(Instruction6CpiBuilderInstruction { - __program: program, - my_account: None, + __program, + my_account, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn my_account( - &mut self, - my_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.my_account = Some(my_account); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -244,8 +236,7 @@ impl<'a, 'b> Instruction6CpiBuilder<'a, 'b> { pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let instruction = Instruction6Cpi { __program: self.instruction.__program, - - my_account: self.instruction.my_account.expect("my_account is not set"), + my_account: self.instruction.my_account, }; instruction.invoke_signed_with_remaining_accounts( signers_seeds, @@ -257,7 +248,7 @@ impl<'a, 'b> Instruction6CpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct Instruction6CpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - my_account: Option<&'b solana_account_info::AccountInfo<'a>>, + my_account: &'b solana_account_info::AccountInfo<'a>, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/dummy/src/generated/instructions/instruction7.rs b/e2e/dummy/src/generated/instructions/instruction7.rs index fff4818..2cdcb36 100644 --- a/e2e/dummy/src/generated/instructions/instruction7.rs +++ b/e2e/dummy/src/generated/instructions/instruction7.rs @@ -101,9 +101,8 @@ impl Instruction7Builder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = Instruction7 { - my_account: self.my_account, - }; + let my_account = self.my_account; + let accounts = Instruction7 { my_account }; accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) } @@ -206,9 +205,9 @@ pub struct Instruction7CpiBuilder<'a, 'b> { } impl<'a, 'b> Instruction7CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { let instruction = Box::new(Instruction7CpiBuilderInstruction { - __program: program, + __program, my_account: None, __remaining_accounts: Vec::new(), }); @@ -259,7 +258,6 @@ impl<'a, 'b> Instruction7CpiBuilder<'a, 'b> { pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let instruction = Instruction7Cpi { __program: self.instruction.__program, - my_account: self.instruction.my_account, }; instruction.invoke_signed_with_remaining_accounts( diff --git a/e2e/dummy/src/generated/instructions/instruction8.rs b/e2e/dummy/src/generated/instructions/instruction8.rs new file mode 100644 index 0000000..fc926c5 --- /dev/null +++ b/e2e/dummy/src/generated/instructions/instruction8.rs @@ -0,0 +1,332 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +#[derive(Debug)] +pub struct Instruction8 { + pub mint: solana_address::Address, + + pub token_program: solana_address::Address, + + pub derived_account: solana_address::Address, +} + +impl Instruction8 { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.mint, false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.derived_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = Instruction8InstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Instruction8InstructionData {} + +impl Instruction8InstructionData { + pub fn new() -> Self { + Self {} + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for Instruction8InstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Instruction8`. +/// +/// ### Accounts: +/// +/// 0. `[]` mint +/// 1. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 2. `[writable, optional]` derived_account (default to PDA derived from 'derivedAccount') +#[derive(Clone, Debug)] +pub struct Instruction8Builder { + mint: solana_address::Address, + token_program: Option, + derived_account: Option, + __remaining_accounts: Vec, +} + +impl Instruction8Builder { + pub fn new(mint: solana_address::Address) -> Self { + Self { + mint, + token_program: None, + derived_account: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// `[optional account, default to PDA derived from 'derivedAccount']` + #[inline(always)] + pub fn derived_account(&mut self, derived_account: solana_address::Address) -> &mut Self { + self.derived_account = Some(derived_account); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let mint = self.mint; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let derived_account = self.derived_account.unwrap_or_else(|| { + crate::pdas::find_derived_account_pda( + &self.mint, + &self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )), + ) + .0 + }); + let accounts = Instruction8 { + mint, + token_program, + derived_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `instruction8` CPI accounts. +pub struct Instruction8CpiAccounts<'a, 'b> { + pub mint: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub derived_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `instruction8` CPI instruction. +pub struct Instruction8Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub mint: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub derived_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> Instruction8Cpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: Instruction8CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + mint: accounts.mint, + token_program: accounts.token_program, + derived_account: accounts.derived_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.derived_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = Instruction8InstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.mint.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.derived_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Instruction8` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` mint +/// 1. `[]` token_program +/// 2. `[writable]` derived_account +#[derive(Clone, Debug)] +pub struct Instruction8CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> Instruction8CpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + derived_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(Instruction8CpiBuilderInstruction { + __program, + mint, + token_program, + derived_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = Instruction8Cpi { + __program: self.instruction.__program, + mint: self.instruction.mint, + token_program: self.instruction.token_program, + derived_account: self.instruction.derived_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct Instruction8CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + mint: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + derived_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/dummy/src/generated/instructions/instruction9.rs b/e2e/dummy/src/generated/instructions/instruction9.rs new file mode 100644 index 0000000..597ee5e --- /dev/null +++ b/e2e/dummy/src/generated/instructions/instruction9.rs @@ -0,0 +1,262 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +#[derive(Debug)] +pub struct Instruction9 { + pub global_config: solana_address::Address, +} + +impl Instruction9 { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(1 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = Instruction9InstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Instruction9InstructionData {} + +impl Instruction9InstructionData { + pub fn new() -> Self { + Self {} + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for Instruction9InstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Instruction9`. +/// +/// ### Accounts: +/// +/// 0. `[optional]` global_config (default to PDA derived from 'globalConfig') +#[derive(Clone, Debug, Default)] +pub struct Instruction9Builder { + global_config: Option, + __remaining_accounts: Vec, +} + +impl Instruction9Builder { + pub fn new() -> Self { + Self::default() + } + /// `[optional account, default to PDA derived from 'globalConfig']` + #[inline(always)] + pub fn global_config(&mut self, global_config: solana_address::Address) -> &mut Self { + self.global_config = Some(global_config); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let global_config = self + .global_config + .unwrap_or(crate::pdas::GLOBAL_CONFIG_ADDRESS); + let accounts = Instruction9 { global_config }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `instruction9` CPI accounts. +pub struct Instruction9CpiAccounts<'a, 'b> { + pub global_config: &'b solana_account_info::AccountInfo<'a>, +} + +/// `instruction9` CPI instruction. +pub struct Instruction9Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub global_config: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> Instruction9Cpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: Instruction9CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + global_config: accounts.global_config, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(1 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = Instruction9InstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::DUMMY_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(2 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_config.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Instruction9` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` global_config +#[derive(Clone, Debug)] +pub struct Instruction9CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> Instruction9CpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(Instruction9CpiBuilderInstruction { + __program, + global_config, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = Instruction9Cpi { + __program: self.instruction.__program, + global_config: self.instruction.global_config, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct Instruction9CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/dummy/src/generated/instructions/mod.rs b/e2e/dummy/src/generated/instructions/mod.rs index a0205b0..2fe4073 100644 --- a/e2e/dummy/src/generated/instructions/mod.rs +++ b/e2e/dummy/src/generated/instructions/mod.rs @@ -6,17 +6,23 @@ //! pub(crate) mod r#instruction1; +pub(crate) mod r#instruction10; pub(crate) mod r#instruction2; pub(crate) mod r#instruction3; pub(crate) mod r#instruction4; pub(crate) mod r#instruction5; pub(crate) mod r#instruction6; pub(crate) mod r#instruction7; +pub(crate) mod r#instruction8; +pub(crate) mod r#instruction9; pub use self::r#instruction1::*; +pub use self::r#instruction10::*; pub use self::r#instruction2::*; pub use self::r#instruction3::*; pub use self::r#instruction4::*; pub use self::r#instruction5::*; pub use self::r#instruction6::*; pub use self::r#instruction7::*; +pub use self::r#instruction8::*; +pub use self::r#instruction9::*; diff --git a/e2e/dummy/src/generated/mod.rs b/e2e/dummy/src/generated/mod.rs index 9c64a4b..374b603 100644 --- a/e2e/dummy/src/generated/mod.rs +++ b/e2e/dummy/src/generated/mod.rs @@ -7,6 +7,7 @@ pub mod errors; pub mod instructions; +pub mod pdas; pub mod programs; pub(crate) use programs::*; diff --git a/e2e/dummy/src/generated/pdas/derived_account.rs b/e2e/dummy/src/generated/pdas/derived_account.rs new file mode 100644 index 0000000..1061621 --- /dev/null +++ b/e2e/dummy/src/generated/pdas/derived_account.rs @@ -0,0 +1,36 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::DUMMY_ID; + +pub const DERIVED_ACCOUNT_SEED: &'static [u8] = b"derived"; +pub fn create_derived_account_pda( + mint: Address, + token_program: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + DERIVED_ACCOUNT_SEED, + mint.as_ref(), + token_program.as_ref(), + &[bump], + ], + &DUMMY_ID, + ) +} +pub fn find_derived_account_pda( + mint: &Address, + token_program: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[DERIVED_ACCOUNT_SEED, mint.as_ref(), token_program.as_ref()], + &DUMMY_ID, + ) +} diff --git a/e2e/dummy/src/generated/pdas/global_config.rs b/e2e/dummy/src/generated/pdas/global_config.rs new file mode 100644 index 0000000..bcca593 --- /dev/null +++ b/e2e/dummy/src/generated/pdas/global_config.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::DUMMY_ID; + +pub const GLOBAL_CONFIG_SEED: &'static [u8] = b"global_config"; + +pub const GLOBAL_CONFIG_ADDRESS: solana_address::Address = + solana_address::address!("9gM2qHs9cK8n6DoWe2HsoVjhJzsW9jt4je7r6NNtgRsG"); +/// A PDA with only constant seeds — address is deterministic. +pub fn create_global_config_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address(&[GLOBAL_CONFIG_SEED, &[bump]], &DUMMY_ID) +} +/// A PDA with only constant seeds — address is deterministic. +pub fn find_global_config_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address(&[GLOBAL_CONFIG_SEED], &DUMMY_ID) +} diff --git a/e2e/dummy/src/generated/pdas/mod.rs b/e2e/dummy/src/generated/pdas/mod.rs new file mode 100644 index 0000000..9729cc3 --- /dev/null +++ b/e2e/dummy/src/generated/pdas/mod.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod derived_account; +pub mod global_config; + +pub use self::derived_account::*; +pub use self::global_config::*; diff --git a/e2e/governance/Cargo.toml b/e2e/governance/Cargo.toml new file mode 100644 index 0000000..989aedd --- /dev/null +++ b/e2e/governance/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "codama-renderers-rust-e2e-governance" +version = "0.0.0" +edition = "2021" + +[features] +anchor = ["dep:anchor-lang"] +anchor-idl-build = ["anchor", "anchor-lang?/idl-build"] +fetch = ["dep:solana-client"] +serde = ["dep:serde", "dep:serde_with", "dep:serde-big-array"] +test-sbf = [] + +[dependencies] +anchor-lang = { workspace = true, optional = true } +borsh = { workspace = true } +kaigan = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } +serde = { workspace = true, features = ["derive"], optional = true } +serde-big-array = { workspace = true, optional = true } +serde_with = { workspace = true, optional = true } +solana-account = { workspace = true } +solana-account-info = { workspace = true } +solana-client = { workspace = true, optional = true } +solana-cpi = { workspace = true } +solana-decode-error = { workspace = true } +solana-instruction = { workspace = true } +solana-program-error = { workspace = true } +solana-address = { workspace = true, features = ["borsh", "copy", "curve25519", "decode"] } +spl-collections = { workspace = true } +thiserror = { workspace = true } diff --git a/e2e/governance/idl.json b/e2e/governance/idl.json new file mode 100644 index 0000000..ca7f9df --- /dev/null +++ b/e2e/governance/idl.json @@ -0,0 +1,8758 @@ +{ + "kind": "rootNode", + "standard": "codama", + "version": "1.3.7", + "program": { + "kind": "programNode", + "name": "splGovernance", + "publicKey": "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", + "version": "3.1.1", + "origin": "shank", + "docs": [], + "accounts": [ + { + "kind": "accountNode", + "name": "governanceV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governedAccount", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved1", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "reserved119" + } + }, + { + "kind": "structFieldTypeNode", + "name": "requiredSignatoriesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "activeProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "governance" + } + }, + { + "kind": "accountNode", + "name": "realmV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "realmConfig" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 6 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "authority", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "realm" + } + }, + { + "kind": "accountNode", + "name": "tokenOwnerRecordV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenDepositAmount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "unrelinquishedVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "outstandingProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "version", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 6 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "governanceDelegate", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "tokenOwnerRecord" + } + }, + { + "kind": "accountNode", + "name": "governanceV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governedAccount", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposalsCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "governance" + } + }, + { + "kind": "accountNode", + "name": "proposalV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "state", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "proposalState" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tokenOwnerRecord", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatoriesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatoriesSignedOffCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "yesVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "noVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instructionsExecutedCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instructionsCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instructionsNextIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "draftAt", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signingOffAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingAtSlot", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "slot" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingCompletedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executingAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "closedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executionFlags", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "instructionExecutionFlags" + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVoteWeight", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteThreshold", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "descriptionLink", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "proposal" + } + }, + { + "kind": "accountNode", + "name": "signatoryRecordV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signedOff", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "signatoryRecord" + } + }, + { + "kind": "accountNode", + "name": "proposalInstructionV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instructionIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "holdUpTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instruction", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "instructionData" + } + }, + { + "kind": "structFieldTypeNode", + "name": "executedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executionStatus", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "transactionExecutionStatus" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "proposalTransaction" + } + }, + { + "kind": "accountNode", + "name": "voteRecordV1", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "isRelinquished", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteWeight", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteWeightV1" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "voteRecord" + } + }, + { + "kind": "accountNode", + "name": "programMetadata", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "updatedAt", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "slot" + } + }, + { + "kind": "structFieldTypeNode", + "name": "version", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 64 + } + } + } + ] + } + }, + { + "kind": "accountNode", + "name": "proposalV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "state", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "proposalState" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tokenOwnerRecord", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatoriesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatoriesSignedOffCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "options", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "definedTypeLinkNode", + "name": "proposalOption" + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "denyVoteWeight", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved1", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "abstainVoteWeight", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "startVotingAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "draftAt", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signingOffAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingAtSlot", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "slot" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingCompletedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executingAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "closedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executionFlags", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "instructionExecutionFlags" + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVoteWeight", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVotingTime", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteThreshold", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 64 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "descriptionLink", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "vetoVoteWeight", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "proposal" + } + }, + { + "kind": "accountNode", + "name": "proposalDeposit", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "depositPayer", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 64 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "proposalDeposit" + } + }, + { + "kind": "accountNode", + "name": "proposalTransactionV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "optionIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "transactionIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "holdUpTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "instructions", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "definedTypeLinkNode", + "name": "instructionData" + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executedAt", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "definedTypeLinkNode", + "name": "unixTimestamp" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "executionStatus", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "transactionExecutionStatus" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 8 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "proposalTransaction" + } + }, + { + "kind": "accountNode", + "name": "realmV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "realmConfig" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 6 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "legacy1", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "authority", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 128 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "realm" + } + }, + { + "kind": "accountNode", + "name": "realmConfigAccount", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityTokenConfig", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenConfig" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilTokenConfig", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenConfig" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "reserved110" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "realmConfig" + } + }, + { + "kind": "accountNode", + "name": "requiredSignatory", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "accountVersion", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "requiredSignatory" + } + }, + { + "kind": "accountNode", + "name": "signatoryRecordV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "signedOff", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 8 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "signatoryRecord" + } + }, + { + "kind": "accountNode", + "name": "tokenOwnerRecordV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenDepositAmount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "unrelinquishedVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "outstandingProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "version", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 6 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "governanceDelegate", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 128 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "tokenOwnerRecord" + } + }, + { + "kind": "accountNode", + "name": "legacyTokenOwnerRecord", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenDepositAmount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "unrelinquishedVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "totalVotesCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "outstandingProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 7 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "governanceDelegate", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 128 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "tokenOwnerRecord" + } + }, + { + "kind": "accountNode", + "name": "voteRecordV2", + "docs": [], + "data": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "accountType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceAccountType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "isRelinquished", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "voterWeight", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "vote", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "vote" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reservedV2", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 8 + } + } + } + ] + }, + "pda": { + "kind": "pdaLinkNode", + "name": "voteRecord" + } + } + ], + "instructions": [ + { + "kind": "instructionNode", + "name": "createRealm", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governance Realm account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "realmAuthority", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "The authority of the Realm" + ] + }, + { + "kind": "instructionAccountNode", + "name": "communityTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "The mint address of the token to be used as the community mint" + ] + }, + { + "kind": "instructionAccountNode", + "name": "communityTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "The account to hold the community tokens.", + " PDA seeds=['governance', realm, community_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [ + "the payer of this transaction" + ], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "System Program" + ], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "SPL Token Program" + ], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + }, + { + "kind": "instructionAccountNode", + "name": "rent", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "SysVar Rent" + ], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRent111111111111111111111111111111111" + } + }, + { + "kind": "instructionAccountNode", + "name": "councilTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "The mint address of the token to be used as the council mint" + ] + }, + { + "kind": "instructionAccountNode", + "name": "councilTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "The account to hold the council tokens.", + " PDA seeds: ['governance',realm,council_mint]", + " " + ] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm Config account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "communityVoterWeightAddin", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Community Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxCommunityVoterWeightAddin", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Community Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "councilVoterWeightAddin", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Council Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxCouncilVoterWeightAddin", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Council Voter Weight Addin Program Id" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 0 + } + }, + { + "kind": "instructionArgumentNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "instructionArgumentNode", + "name": "configArgs", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "realmConfigParams" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "depositGoverningTokens", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenSourceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "It can either be spl-token TokenAccount or MintAccount. Tokens will be transferred or minted to the holding account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenSourceAccountAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "It should be owner for TokenAccount and mint_authority for MintAccount" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint, governing_token_owner]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + }, + { + "kind": "instructionAccountNode", + "name": "realmConfigAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['realm-config', realm]" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 1 + } + }, + { + "kind": "instructionArgumentNode", + "name": "amount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "withdrawGoverningTokens", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenDestinationAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "All tokens will be transferred to this account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance',realm, governing_token_mint, governing_token_owner]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + }, + { + "kind": "instructionAccountNode", + "name": "realmConfigAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['realm-config', realm]" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 2 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "setGovernanceDelegate", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "currentDelegateOrOwner", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Current governance delegate or governing token owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 3 + } + }, + { + "kind": "instructionArgumentNode", + "name": "newGovernanceDelegate", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createGovernance", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm account the created governance belongs to" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['account-governance', realm, governed_account]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governedAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Account governed by this Governance (governing_account). ", + " Note: the account doesn't have to exist and can be used only as a unique identified for the Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Used only if not signed by RealmAuthority" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfigAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 4 + } + }, + { + "kind": "instructionArgumentNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createProgramGovernance", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm account the created Governance belongs to" + ] + }, + { + "kind": "instructionAccountNode", + "name": "programGovernanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Program Governance account. seeds: ['program-governance', realm, governed_program]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governedProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Program governed by this Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "programData", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Program Data account of the Program governed by this Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "currentUpgradeAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Current Upgrade Authority account of the Program governed by this Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "bpfUpgradeableLoaderProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "bpf_upgradeable_loader_program program" + ] + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 5 + } + }, + { + "kind": "instructionArgumentNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + }, + { + "kind": "instructionArgumentNode", + "name": "transferUpgradeAuthority", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createProposal", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm account the created Proposal belongs to" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Token Mint the Proposal is created for" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. PDA seeds: ['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalDepositAccount", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Proposal deposit is required when there are more active ", + " proposals than the configured deposit exempt amount. ", + " PDA seeds: ['proposal-deposit', proposal, deposit payer]" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 6 + } + }, + { + "kind": "instructionArgumentNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "instructionArgumentNode", + "name": "descriptionLink", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "instructionArgumentNode", + "name": "voteType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteType" + } + }, + { + "kind": "instructionArgumentNode", + "name": "options", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + }, + { + "kind": "instructionArgumentNode", + "name": "useDenyOption", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "instructionArgumentNode", + "name": "proposalSeed", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "addSignatory", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Proposal Account associated with the governance" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "signatoryRecordAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Signatory Record Account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 7 + } + }, + { + "kind": "instructionArgumentNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "legacy1", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 8 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "insertTransaction", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalTransactionAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "rent", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "SysvarRent111111111111111111111111111111111" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 9 + } + }, + { + "kind": "instructionArgumentNode", + "name": "optionIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "instructionArgumentNode", + "name": "index", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "instructionArgumentNode", + "name": "holdUpTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "instructionArgumentNode", + "name": "instructions", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "definedTypeLinkNode", + "name": "instructionData" + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "removeTransaction", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalTransactionAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "beneficiaryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Beneficiary Account which would receive lamports from the disposed ProposalTransaction account" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 10 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "cancelProposal", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance authority (Token Owner or Governance Delegate)" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 11 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "signOffProposal", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "signatoryAccount", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Signatory account signing off the Proposal.", + " Or Proposal owner if the owner hasn't appointed any signatories" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal.", + " Or `[writable]` SignatoryRecord account, required when non owner signs off the Proposal" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 12 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "castVote", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalTokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterTokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalVoteRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "The Governing Token Mint which is used to cast the vote (vote_governing_token_mint).", + " The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes.", + " For Veto vote the voting token mint is the mint of the opposite voting population.", + " Council mint to veto Community proposals and Community mint to veto Council proposals", + " Note: In the current version only Council veto is supported" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "realmConfigAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. PDA seeds: ['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxVoterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 13 + } + }, + { + "kind": "instructionArgumentNode", + "name": "vote", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "vote" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "finalizeVote", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. PDA seeds: ['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxVoterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 14 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "relinquishVote", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalVoteRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "The Governing Token Mint which was used to cast the vote (vote_governing_token_mint)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": true, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "beneficiaryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed.", + " It's required only when Proposal is still being voted on" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 15 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "executeTransaction", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalTransactionAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 16 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createMintGovernance", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm account the created Governance belongs to" + ] + }, + { + "kind": "instructionAccountNode", + "name": "mintGovernanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Mint Governance account. seeds=['mint-governance', realm, governed_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governedMint", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Mint governed by this Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "mintAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Current Mint authority (MintTokens and optionally FreezeAccount)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 17 + } + }, + { + "kind": "instructionArgumentNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + }, + { + "kind": "instructionArgumentNode", + "name": "transferMintAuthorities", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createTokenGovernance", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Realm account the created Governance belongs to" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenGovernanceAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Token Governance account. seeds=['token-governance', realm, governed_token]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Token account governed by this Governance account" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenAccountAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Current token account authority (AccountOwner and optionally CloseAccount" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "voterWeightRecord", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Voter Weight Record" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 18 + } + }, + { + "kind": "instructionArgumentNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + }, + { + "kind": "instructionArgumentNode", + "name": "transferAccountAuthorities", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "setGovernanceConfig", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [ + "The governance account the config is for" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 19 + } + }, + { + "kind": "instructionArgumentNode", + "name": "config", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governanceConfig" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "flagTransactionError", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governanceAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Governance Authority (Token Owner or Governance Delegate)" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalTransactionAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "ProposalTransaction account to flag" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 20 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "setRealmAuthority", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "newRealmAuthority", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Must be one of the realm governances when set" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 21 + } + }, + { + "kind": "instructionArgumentNode", + "name": "action", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "setRealmAuthorityAction" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "setRealmConfig", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "realmAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "councilTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Council Token Mint - optional. ", + " Note: In the current version it's only possible to remove council mint (set it to None)", + " After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. ", + " If that's required then it must be done before executing this instruction" + ] + }, + { + "kind": "instructionAccountNode", + "name": "councilTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional unless council is used. seeds=['governance', realm, council_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + }, + { + "kind": "instructionAccountNode", + "name": "realmConfig", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "RealmConfig account. seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "communityVoterWeightAddinProgramId", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Community Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxCommunityVoterWeightAddinProgramId", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Community Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "councilVoterWeightAddinProgramId", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Council Voter Weight Adding Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "maxCouncilVoterWeightAddinProgramId", + "isWritable": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "Optional Max Council Voter Weight Addin Program Id" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "Optional Payer. Required if RealmConfig doesn't exist and needs to be created" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 22 + } + }, + { + "kind": "instructionArgumentNode", + "name": "configArgs", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "realmConfigParams" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createTokenOwnerRecord", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenOwnerAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint, governing_token_owner]" + ], + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "tokenOwnerRecord" + }, + "seeds": [ + { + "kind": "pdaSeedValueNode", + "name": "realm", + "value": { + "kind": "accountValueNode", + "name": "realmAccount" + } + }, + { + "kind": "pdaSeedValueNode", + "name": "governingTokenMint", + "value": { + "kind": "accountValueNode", + "name": "governingTokenMint" + } + }, + { + "kind": "pdaSeedValueNode", + "name": "governingTokenOwner", + "value": { + "kind": "accountValueNode", + "name": "governingTokenOwnerAccount" + } + } + ] + } + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 23 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "updateProgramMetadata", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "programMetadataAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['metadata']" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 24 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "createNativeTreasury", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "Governance account the treasury account is for" + ] + }, + { + "kind": "instructionAccountNode", + "name": "nativeTreasuryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['native-treasury', governance]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 25 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "revokeGoverningTokens", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "realmAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenHoldingAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['governance', realm, governing_token_mint, governing_token_owner]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMint", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "governingTokenMintAuthorityOrTokenOwner", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "GoverningTokenMint mint_authority" + ] + }, + { + "kind": "instructionAccountNode", + "name": "realmConfigAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "seeds=['realm-config', realm]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "tokenProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "identifier": "splToken" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 26 + } + }, + { + "kind": "instructionArgumentNode", + "name": "amount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "refundProposalDeposit", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "proposalDepositAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "PDA Seeds: ['proposal-deposit', proposal, deposit payer]" + ] + }, + { + "kind": "instructionAccountNode", + "name": "proposalDepositPayer", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Proposal Deposit Payer (beneficiary) account" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 27 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "completeProposal", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "proposalAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "tokenOwnerRecord", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [ + "TokenOwnerRecord account of the Proposal owner" + ] + }, + { + "kind": "instructionAccountNode", + "name": "completeProposalAuthority", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [ + "Token Owner or Delegate" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 28 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "addRequiredSignatory", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [ + "The Governance account the config is for" + ] + }, + { + "kind": "instructionAccountNode", + "name": "requiredSignatoryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "payer", + "isWritable": false, + "isSigner": true, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "payerValueNode" + } + }, + { + "kind": "instructionAccountNode", + "name": "systemProgram", + "isWritable": false, + "isSigner": false, + "isOptional": false, + "docs": [], + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111", + "identifier": "systemProgram" + } + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 29 + } + }, + { + "kind": "instructionArgumentNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + }, + { + "kind": "instructionNode", + "name": "removeRequiredSignatory", + "docs": [], + "optionalAccountStrategy": "programId", + "accounts": [ + { + "kind": "instructionAccountNode", + "name": "governanceAccount", + "isWritable": true, + "isSigner": true, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "requiredSignatoryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [] + }, + { + "kind": "instructionAccountNode", + "name": "beneficiaryAccount", + "isWritable": true, + "isSigner": false, + "isOptional": false, + "docs": [ + "Beneficiary Account which would receive lamports from the disposed RequiredSignatory Account" + ] + } + ], + "arguments": [ + { + "kind": "instructionArgumentNode", + "name": "discriminator", + "defaultValueStrategy": "omitted", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "defaultValue": { + "kind": "numberValueNode", + "number": 30 + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ] + } + ], + "definedTypes": [ + { + "kind": "definedTypeNode", + "name": "governanceConfig", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "communityVoteThreshold", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + } + }, + { + "kind": "structFieldTypeNode", + "name": "minCommunityWeightToCreateProposal", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "minTransactionHoldUpTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingBaseTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityVoteTipping", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteTipping" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilVoteThreshold", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilVetoVoteThreshold", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + } + }, + { + "kind": "structFieldTypeNode", + "name": "minCouncilWeightToCreateProposal", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilVoteTipping", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteTipping" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityVetoVoteThreshold", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "voteThreshold" + } + }, + { + "kind": "structFieldTypeNode", + "name": "votingCoolOffTime", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "depositExemptProposalCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "nativeTreasury", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [] + } + }, + { + "kind": "definedTypeNode", + "name": "proposalOption", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "label", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteWeight", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "voteResult", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "optionVoteResult" + } + }, + { + "kind": "structFieldTypeNode", + "name": "transactionsExecutedCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "transactionsCount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "transactionsNextIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "instructionData", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "programId", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "accounts", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "definedTypeLinkNode", + "name": "accountMetaData" + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "data", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "bytesTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "accountMetaData", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "pubkey", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "isSigner", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "isWritable", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "realmConfigParams", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "useCouncilMint", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "minCommunityWeightToCreateGovernance", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityMintMaxVoterWeightSource", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "mintMaxVoterWeightSource" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityTokenConfigArgs", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenConfigParams" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilTokenConfigArgs", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenConfigParams" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "governingTokenConfigParams", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "useVoterWeightAddin", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "useMaxVoterWeightAddin", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "tokenType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenType" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "governingTokenConfigAccountArgs", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "voterWeightAddin", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVoterWeightAddin", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "tokenType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenType" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "realmConfig", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "legacy1", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "legacy2", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 6 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "minCommunityWeightToCreateGovernance", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityMintMaxVoterWeightSource", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "mintMaxVoterWeightSource" + } + }, + { + "kind": "structFieldTypeNode", + "name": "councilMint", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "realmConfigParamsV1", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "useCouncilMint", + "docs": [], + "type": { + "kind": "booleanTypeNode", + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "minCommunityWeightToCreateGovernance", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "communityMintMaxVoterWeightSource", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "mintMaxVoterWeightSource" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "governingTokenConfig", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "voterWeightAddin", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVoterWeightAddin", + "docs": [], + "type": { + "kind": "optionTypeNode", + "fixed": false, + "item": { + "kind": "publicKeyTypeNode" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "tokenType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "governingTokenType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 8 + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "voteChoice", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "rank", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "weightPercentage", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "reserved110", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "reserved64", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 64 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved32", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 32 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved14", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 14 + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "reserved119", + "docs": [], + "type": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "reserved64", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 64 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved32", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 32 + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "reserved23", + "docs": [], + "type": { + "kind": "arrayTypeNode", + "item": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + }, + "count": { + "kind": "fixedCountNode", + "value": 23 + } + } + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "governanceAccountType", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "uninitialized" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "realmV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "tokenOwnerRecordV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "governanceV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "programGovernanceV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "proposalV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "signatoryRecordV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "voteRecordV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "proposalInstructionV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "mintGovernanceV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "tokenGovernanceV1" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "realmConfig" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "voteRecordV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "proposalTransactionV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "proposalV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "programMetadata" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "realmV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "tokenOwnerRecordV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "governanceV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "programGovernanceV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "mintGovernanceV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "tokenGovernanceV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "signatoryRecordV2" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "proposalDeposit" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "requiredSignatory" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "proposalState", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "draft" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "signingOff" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "voting" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "succeeded" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "executing" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "completed" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "cancelled" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "defeated" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "executingWithErrors" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "vetoed" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "voteThreshold", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumTupleVariantTypeNode", + "name": "yesVotePercentage", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + ] + } + }, + { + "kind": "enumTupleVariantTypeNode", + "name": "quorumPercentage", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + ] + } + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "disabled" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "voteTipping", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "strict" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "early" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "disabled" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "transactionExecutionStatus", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "none" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "success" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "error" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "instructionExecutionFlags", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "none" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "ordered" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "useTransaction" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "mintMaxVoterWeightSource", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumTupleVariantTypeNode", + "name": "supplyFraction", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + ] + } + }, + { + "kind": "enumTupleVariantTypeNode", + "name": "absolute", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + ] + } + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "voteWeightV1", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumTupleVariantTypeNode", + "name": "yes", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + ] + } + }, + { + "kind": "enumTupleVariantTypeNode", + "name": "no", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + ] + } + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "optionVoteResult", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "none" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "succeeded" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "defeated" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "voteType", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "singleChoice" + }, + { + "kind": "enumStructVariantTypeNode", + "name": "multiChoice", + "struct": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "choiceType", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "multiChoiceType" + } + }, + { + "kind": "structFieldTypeNode", + "name": "minVoterOptions", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxVoterOptions", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "structFieldTypeNode", + "name": "maxWinningOptions", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + ] + } + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "multiChoiceType", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "fullWeight" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "weighted" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "setRealmAuthorityAction", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "setUnchecked" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "setChecked" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "remove" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "governanceInstructionV1", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumStructVariantTypeNode", + "name": "createRealm", + "struct": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "name", + "docs": [], + "type": { + "kind": "sizePrefixTypeNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + }, + { + "kind": "structFieldTypeNode", + "name": "configArgs", + "docs": [], + "type": { + "kind": "definedTypeLinkNode", + "name": "realmConfigParamsV1" + } + } + ] + } + }, + { + "kind": "enumStructVariantTypeNode", + "name": "depositGoverningTokens", + "struct": { + "kind": "structTypeNode", + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "amount", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ] + } + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "governingTokenType", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "liquid" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "membership" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "dormant" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "vote", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumTupleVariantTypeNode", + "name": "approve", + "tuple": { + "kind": "tupleTypeNode", + "items": [ + { + "kind": "arrayTypeNode", + "item": { + "kind": "definedTypeLinkNode", + "name": "voteChoice" + }, + "count": { + "kind": "prefixedCountNode", + "prefix": { + "kind": "numberTypeNode", + "format": "u32", + "endian": "le" + } + } + } + ] + } + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "deny" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "abstain" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "veto" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "voteKind", + "docs": [], + "type": { + "kind": "enumTypeNode", + "variants": [ + { + "kind": "enumEmptyVariantTypeNode", + "name": "electorate" + }, + { + "kind": "enumEmptyVariantTypeNode", + "name": "veto" + } + ], + "size": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + } + }, + { + "kind": "definedTypeNode", + "name": "unixTimestamp", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "i64", + "endian": "le" + } + }, + { + "kind": "definedTypeNode", + "name": "slot", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u64", + "endian": "le" + } + } + ], + "pdas": [ + { + "kind": "pdaNode", + "name": "realm", + "docs": [ + "Realm account identified by its name" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "name", + "docs": [], + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "communityTokenHolding", + "docs": [ + "Community token holding account of a realm" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "communityMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "councilTokenHolding", + "docs": [ + "Council token holding account of a realm" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "councilMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "realmConfig", + "docs": [ + "Configuration of a realm" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "realm-config" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "tokenOwnerRecord", + "docs": [ + "Token owner's record within a realm" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governingTokenOwner", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "governingTokenHolding", + "docs": [ + "Governing token holding account" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "governance", + "docs": [ + "Governance account within a realm" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "account-governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "realm", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "seed", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "nativeTreasury", + "docs": [ + "Governance's native SOL treasury account" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "native-treasury" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "proposal", + "docs": [ + "Governance proposal" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governingTokenMint", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "proposalSeed", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "proposalDeposit", + "docs": [ + "Proposal deposit made by a specific payer" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "proposal-deposit" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "depositPayer", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "signatoryRecord", + "docs": [ + "Signatory's record on a proposal" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "proposalTransaction", + "docs": [ + "Transaction within a proposal option" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "optionIndex", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u8", + "endian": "le" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "index", + "docs": [], + "type": { + "kind": "numberTypeNode", + "format": "u16", + "endian": "le" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "voteRecord", + "docs": [ + "Vote record on a proposal" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "governance" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "proposal", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "tokenOwnerRecord", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "requiredSignatory", + "docs": [ + "Required signatory on a governance" + ], + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "kind": "stringTypeNode", + "encoding": "utf8" + }, + "value": { + "kind": "stringValueNode", + "string": "required-signatory" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "governance", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "signatory", + "docs": [], + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + } + ], + "errors": [ + { + "kind": "errorNode", + "name": "invalidInstruction", + "code": 500, + "message": "Invalid instruction passed to program", + "docs": [ + "InvalidInstruction: Invalid instruction passed to program" + ] + }, + { + "kind": "errorNode", + "name": "realmAlreadyExists", + "code": 501, + "message": "Realm with the given name and governing mints already exists", + "docs": [ + "RealmAlreadyExists: Realm with the given name and governing mints already exists" + ] + }, + { + "kind": "errorNode", + "name": "invalidRealm", + "code": 502, + "message": "Invalid realm", + "docs": [ + "InvalidRealm: Invalid realm" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningTokenMint", + "code": 503, + "message": "Invalid Governing Token Mint", + "docs": [ + "InvalidGoverningTokenMint: Invalid Governing Token Mint" + ] + }, + { + "kind": "errorNode", + "name": "governingTokenOwnerMustSign", + "code": 504, + "message": "Governing Token Owner must sign transaction", + "docs": [ + "GoverningTokenOwnerMustSign: Governing Token Owner must sign transaction" + ] + }, + { + "kind": "errorNode", + "name": "governingTokenOwnerOrDelegateMustSign", + "code": 505, + "message": "Governing Token Owner or Delegate must sign transaction", + "docs": [ + "GoverningTokenOwnerOrDelegateMustSign: Governing Token Owner or Delegate must sign transaction" + ] + }, + { + "kind": "errorNode", + "name": "allVotesMustBeRelinquishedToWithdrawGoverningTokens", + "code": 506, + "message": "All votes must be relinquished to withdraw governing tokens", + "docs": [ + "AllVotesMustBeRelinquishedToWithdrawGoverningTokens: All votes must be relinquished to withdraw governing tokens" + ] + }, + { + "kind": "errorNode", + "name": "invalidTokenOwnerRecordAccountAddress", + "code": 507, + "message": "Invalid Token Owner Record account address", + "docs": [ + "InvalidTokenOwnerRecordAccountAddress: Invalid Token Owner Record account address" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningMintForTokenOwnerRecord", + "code": 508, + "message": "Invalid GoverningMint for TokenOwnerRecord", + "docs": [ + "InvalidGoverningMintForTokenOwnerRecord: Invalid GoverningMint for TokenOwnerRecord" + ] + }, + { + "kind": "errorNode", + "name": "invalidRealmForTokenOwnerRecord", + "code": 509, + "message": "Invalid Realm for TokenOwnerRecord", + "docs": [ + "InvalidRealmForTokenOwnerRecord: Invalid Realm for TokenOwnerRecord" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalForProposalTransaction", + "code": 510, + "message": "Invalid Proposal for ProposalTransaction,", + "docs": [ + "InvalidProposalForProposalTransaction: Invalid Proposal for ProposalTransaction," + ] + }, + { + "kind": "errorNode", + "name": "invalidSignatoryAddress", + "code": 511, + "message": "Invalid Signatory account address", + "docs": [ + "InvalidSignatoryAddress: Invalid Signatory account address" + ] + }, + { + "kind": "errorNode", + "name": "signatoryAlreadySignedOff", + "code": 512, + "message": "Signatory already signed off", + "docs": [ + "SignatoryAlreadySignedOff: Signatory already signed off" + ] + }, + { + "kind": "errorNode", + "name": "signatoryMustSign", + "code": 513, + "message": "Signatory must sign", + "docs": [ + "SignatoryMustSign: Signatory must sign" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalOwnerAccount", + "code": 514, + "message": "Invalid Proposal Owner", + "docs": [ + "InvalidProposalOwnerAccount: Invalid Proposal Owner" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalForVoterRecord", + "code": 515, + "message": "Invalid Proposal for VoterRecord", + "docs": [ + "InvalidProposalForVoterRecord: Invalid Proposal for VoterRecord" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningTokenOwnerForVoteRecord", + "code": 516, + "message": "Invalid GoverningTokenOwner for VoteRecord", + "docs": [ + "InvalidGoverningTokenOwnerForVoteRecord: Invalid GoverningTokenOwner for VoteRecord" + ] + }, + { + "kind": "errorNode", + "name": "invalidVoteThresholdPercentage", + "code": 517, + "message": "Invalid Governance config: Vote threshold percentage out of range", + "docs": [ + "InvalidVoteThresholdPercentage: Invalid Governance config: Vote threshold percentage out of range" + ] + }, + { + "kind": "errorNode", + "name": "proposalAlreadyExists", + "code": 518, + "message": "Proposal for the given Governance, Governing Token Mint and index already exists", + "docs": [ + "ProposalAlreadyExists: Proposal for the given Governance, Governing Token Mint and index already exists" + ] + }, + { + "kind": "errorNode", + "name": "voteAlreadyExists", + "code": 519, + "message": "Token Owner already voted on the Proposal", + "docs": [ + "VoteAlreadyExists: Token Owner already voted on the Proposal" + ] + }, + { + "kind": "errorNode", + "name": "notEnoughTokensToCreateProposal", + "code": 520, + "message": "Owner doesn't have enough governing tokens to create Proposal", + "docs": [ + "NotEnoughTokensToCreateProposal: Owner doesn't have enough governing tokens to create Proposal" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotEditSignatories", + "code": 521, + "message": "Invalid State: Can't edit Signatories", + "docs": [ + "InvalidStateCannotEditSignatories: Invalid State: Can't edit Signatories" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalState", + "code": 522, + "message": "Invalid Proposal state", + "docs": [ + "InvalidProposalState: Invalid Proposal state" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotEditTransactions", + "code": 523, + "message": "Invalid State: Can't edit transactions", + "docs": [ + "InvalidStateCannotEditTransactions: Invalid State: Can't edit transactions" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotExecuteTransaction", + "code": 524, + "message": "Invalid State: Can't execute transaction", + "docs": [ + "InvalidStateCannotExecuteTransaction: Invalid State: Can't execute transaction" + ] + }, + { + "kind": "errorNode", + "name": "cannotExecuteTransactionWithinHoldUpTime", + "code": 525, + "message": "Can't execute transaction within its hold up time", + "docs": [ + "CannotExecuteTransactionWithinHoldUpTime: Can't execute transaction within its hold up time" + ] + }, + { + "kind": "errorNode", + "name": "transactionAlreadyExecuted", + "code": 526, + "message": "Transaction already executed", + "docs": [ + "TransactionAlreadyExecuted: Transaction already executed" + ] + }, + { + "kind": "errorNode", + "name": "invalidTransactionIndex", + "code": 527, + "message": "Invalid Transaction index", + "docs": [ + "InvalidTransactionIndex: Invalid Transaction index" + ] + }, + { + "kind": "errorNode", + "name": "transactionHoldUpTimeBelowRequiredMin", + "code": 528, + "message": "Transaction hold up time is below the min specified by Governance", + "docs": [ + "TransactionHoldUpTimeBelowRequiredMin: Transaction hold up time is below the min specified by Governance" + ] + }, + { + "kind": "errorNode", + "name": "transactionAlreadyExists", + "code": 529, + "message": "Transaction at the given index for the Proposal already exists", + "docs": [ + "TransactionAlreadyExists: Transaction at the given index for the Proposal already exists" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotSignOff", + "code": 530, + "message": "Invalid State: Can't sign off", + "docs": [ + "InvalidStateCannotSignOff: Invalid State: Can't sign off" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotVote", + "code": 531, + "message": "Invalid State: Can't vote", + "docs": [ + "InvalidStateCannotVote: Invalid State: Can't vote" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotFinalize", + "code": 532, + "message": "Invalid State: Can't finalize vote", + "docs": [ + "InvalidStateCannotFinalize: Invalid State: Can't finalize vote" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateCannotCancelProposal", + "code": 533, + "message": "Invalid State: Can't cancel Proposal", + "docs": [ + "InvalidStateCannotCancelProposal: Invalid State: Can't cancel Proposal" + ] + }, + { + "kind": "errorNode", + "name": "voteAlreadyRelinquished", + "code": 534, + "message": "Vote already relinquished", + "docs": [ + "VoteAlreadyRelinquished: Vote already relinquished" + ] + }, + { + "kind": "errorNode", + "name": "cannotFinalizeVotingInProgress", + "code": 535, + "message": "Can't finalize vote. Voting still in progress", + "docs": [ + "CannotFinalizeVotingInProgress: Can't finalize vote. Voting still in progress" + ] + }, + { + "kind": "errorNode", + "name": "proposalVotingTimeExpired", + "code": 536, + "message": "Proposal voting time expired", + "docs": [ + "ProposalVotingTimeExpired: Proposal voting time expired" + ] + }, + { + "kind": "errorNode", + "name": "invalidSignatoryMint", + "code": 537, + "message": "Invalid Signatory Mint", + "docs": [ + "InvalidSignatoryMint: Invalid Signatory Mint" + ] + }, + { + "kind": "errorNode", + "name": "invalidGovernanceForProposal", + "code": 538, + "message": "Proposal does not belong to the given Governance", + "docs": [ + "InvalidGovernanceForProposal: Proposal does not belong to the given Governance" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningMintForProposal", + "code": 539, + "message": "Proposal does not belong to given Governing Mint", + "docs": [ + "InvalidGoverningMintForProposal: Proposal does not belong to given Governing Mint" + ] + }, + { + "kind": "errorNode", + "name": "mintAuthorityMustSign", + "code": 540, + "message": "Current mint authority must sign transaction", + "docs": [ + "MintAuthorityMustSign: Current mint authority must sign transaction" + ] + }, + { + "kind": "errorNode", + "name": "invalidMintAuthority", + "code": 541, + "message": "Invalid mint authority", + "docs": [ + "InvalidMintAuthority: Invalid mint authority" + ] + }, + { + "kind": "errorNode", + "name": "mintHasNoAuthority", + "code": 542, + "message": "Mint has no authority", + "docs": [ + "MintHasNoAuthority: Mint has no authority" + ] + }, + { + "kind": "errorNode", + "name": "splTokenAccountWithInvalidOwner", + "code": 543, + "message": "Invalid Token account owner", + "docs": [ + "SplTokenAccountWithInvalidOwner: Invalid Token account owner" + ] + }, + { + "kind": "errorNode", + "name": "splTokenMintWithInvalidOwner", + "code": 544, + "message": "Invalid Mint account owner", + "docs": [ + "SplTokenMintWithInvalidOwner: Invalid Mint account owner" + ] + }, + { + "kind": "errorNode", + "name": "splTokenAccountNotInitialized", + "code": 545, + "message": "Token Account is not initialized", + "docs": [ + "SplTokenAccountNotInitialized: Token Account is not initialized" + ] + }, + { + "kind": "errorNode", + "name": "splTokenAccountDoesNotExist", + "code": 546, + "message": "Token Account doesn't exist", + "docs": [ + "SplTokenAccountDoesNotExist: Token Account doesn't exist" + ] + }, + { + "kind": "errorNode", + "name": "splTokenInvalidTokenAccountData", + "code": 547, + "message": "Token account data is invalid", + "docs": [ + "SplTokenInvalidTokenAccountData: Token account data is invalid" + ] + }, + { + "kind": "errorNode", + "name": "splTokenInvalidMintAccountData", + "code": 548, + "message": "Token mint account data is invalid", + "docs": [ + "SplTokenInvalidMintAccountData: Token mint account data is invalid" + ] + }, + { + "kind": "errorNode", + "name": "splTokenMintNotInitialized", + "code": 549, + "message": "Token Mint account is not initialized", + "docs": [ + "SplTokenMintNotInitialized: Token Mint account is not initialized" + ] + }, + { + "kind": "errorNode", + "name": "splTokenMintDoesNotExist", + "code": 550, + "message": "Token Mint account doesn't exist", + "docs": [ + "SplTokenMintDoesNotExist: Token Mint account doesn't exist" + ] + }, + { + "kind": "errorNode", + "name": "invalidProgramDataAccountAddress", + "code": 551, + "message": "Invalid ProgramData account address", + "docs": [ + "InvalidProgramDataAccountAddress: Invalid ProgramData account address" + ] + }, + { + "kind": "errorNode", + "name": "invalidProgramDataAccountData", + "code": 552, + "message": "Invalid ProgramData account Data", + "docs": [ + "InvalidProgramDataAccountData: Invalid ProgramData account Data" + ] + }, + { + "kind": "errorNode", + "name": "invalidUpgradeAuthority", + "code": 553, + "message": "Provided upgrade authority doesn't match current program upgrade authority", + "docs": [ + "InvalidUpgradeAuthority: Provided upgrade authority doesn't match current program upgrade authority" + ] + }, + { + "kind": "errorNode", + "name": "upgradeAuthorityMustSign", + "code": 554, + "message": "Current program upgrade authority must sign transaction", + "docs": [ + "UpgradeAuthorityMustSign: Current program upgrade authority must sign transaction" + ] + }, + { + "kind": "errorNode", + "name": "programNotUpgradable", + "code": 555, + "message": "Given program is not upgradable", + "docs": [ + "ProgramNotUpgradable: Given program is not upgradable" + ] + }, + { + "kind": "errorNode", + "name": "invalidTokenOwner", + "code": 556, + "message": "Invalid token owner", + "docs": [ + "InvalidTokenOwner: Invalid token owner" + ] + }, + { + "kind": "errorNode", + "name": "tokenOwnerMustSign", + "code": 557, + "message": "Current token owner must sign transaction", + "docs": [ + "TokenOwnerMustSign: Current token owner must sign transaction" + ] + }, + { + "kind": "errorNode", + "name": "voteThresholdTypeNotSupported", + "code": 558, + "message": "Given VoteThresholdType is not supported", + "docs": [ + "VoteThresholdTypeNotSupported: Given VoteThresholdType is not supported" + ] + }, + { + "kind": "errorNode", + "name": "voteWeightSourceNotSupported", + "code": 559, + "message": "Given VoteWeightSource is not supported", + "docs": [ + "VoteWeightSourceNotSupported: Given VoteWeightSource is not supported" + ] + }, + { + "kind": "errorNode", + "name": "legacy1", + "code": 560, + "message": "Legacy1", + "docs": [ + "Legacy1: Legacy1" + ] + }, + { + "kind": "errorNode", + "name": "governancePdaMustSign", + "code": 561, + "message": "Governance PDA must sign", + "docs": [ + "GovernancePdaMustSign: Governance PDA must sign" + ] + }, + { + "kind": "errorNode", + "name": "transactionAlreadyFlaggedWithError", + "code": 562, + "message": "Transaction already flagged with error", + "docs": [ + "TransactionAlreadyFlaggedWithError: Transaction already flagged with error" + ] + }, + { + "kind": "errorNode", + "name": "invalidRealmForGovernance", + "code": 563, + "message": "Invalid Realm for Governance", + "docs": [ + "InvalidRealmForGovernance: Invalid Realm for Governance" + ] + }, + { + "kind": "errorNode", + "name": "invalidAuthorityForRealm", + "code": 564, + "message": "Invalid Authority for Realm", + "docs": [ + "InvalidAuthorityForRealm: Invalid Authority for Realm" + ] + }, + { + "kind": "errorNode", + "name": "realmHasNoAuthority", + "code": 565, + "message": "Realm has no authority", + "docs": [ + "RealmHasNoAuthority: Realm has no authority" + ] + }, + { + "kind": "errorNode", + "name": "realmAuthorityMustSign", + "code": 566, + "message": "Realm authority must sign", + "docs": [ + "RealmAuthorityMustSign: Realm authority must sign" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningTokenHoldingAccount", + "code": 567, + "message": "Invalid governing token holding account", + "docs": [ + "InvalidGoverningTokenHoldingAccount: Invalid governing token holding account" + ] + }, + { + "kind": "errorNode", + "name": "realmCouncilMintChangeIsNotSupported", + "code": 568, + "message": "Realm council mint change is not supported", + "docs": [ + "RealmCouncilMintChangeIsNotSupported: Realm council mint change is not supported" + ] + }, + { + "kind": "errorNode", + "name": "invalidMaxVoterWeightAbsoluteValue", + "code": 569, + "message": "Invalid max voter weight absolute value", + "docs": [ + "InvalidMaxVoterWeightAbsoluteValue: Invalid max voter weight absolute value" + ] + }, + { + "kind": "errorNode", + "name": "invalidMaxVoterWeightSupplyFraction", + "code": 570, + "message": "Invalid max voter weight supply fraction", + "docs": [ + "InvalidMaxVoterWeightSupplyFraction: Invalid max voter weight supply fraction" + ] + }, + { + "kind": "errorNode", + "name": "notEnoughTokensToCreateGovernance", + "code": 571, + "message": "Owner doesn't have enough governing tokens to create Governance", + "docs": [ + "NotEnoughTokensToCreateGovernance: Owner doesn't have enough governing tokens to create Governance" + ] + }, + { + "kind": "errorNode", + "name": "tooManyOutstandingProposals", + "code": 572, + "message": "Too many outstanding proposals", + "docs": [ + "TooManyOutstandingProposals: Too many outstanding proposals" + ] + }, + { + "kind": "errorNode", + "name": "allProposalsMustBeFinalisedToWithdrawGoverningTokens", + "code": 573, + "message": "All proposals must be finalized to withdraw governing tokens", + "docs": [ + "AllProposalsMustBeFinalisedToWithdrawGoverningTokens: All proposals must be finalized to withdraw governing tokens" + ] + }, + { + "kind": "errorNode", + "name": "invalidVoterWeightRecordForRealm", + "code": 574, + "message": "Invalid VoterWeightRecord for Realm", + "docs": [ + "InvalidVoterWeightRecordForRealm: Invalid VoterWeightRecord for Realm" + ] + }, + { + "kind": "errorNode", + "name": "invalidVoterWeightRecordForGoverningTokenMint", + "code": 575, + "message": "Invalid VoterWeightRecord for GoverningTokenMint", + "docs": [ + "InvalidVoterWeightRecordForGoverningTokenMint: Invalid VoterWeightRecord for GoverningTokenMint" + ] + }, + { + "kind": "errorNode", + "name": "invalidVoterWeightRecordForTokenOwner", + "code": 576, + "message": "Invalid VoterWeightRecord for TokenOwner", + "docs": [ + "InvalidVoterWeightRecordForTokenOwner: Invalid VoterWeightRecord for TokenOwner" + ] + }, + { + "kind": "errorNode", + "name": "voterWeightRecordExpired", + "code": 577, + "message": "VoterWeightRecord expired", + "docs": [ + "VoterWeightRecordExpired: VoterWeightRecord expired" + ] + }, + { + "kind": "errorNode", + "name": "invalidRealmConfigForRealm", + "code": 578, + "message": "Invalid RealmConfig for Realm", + "docs": [ + "InvalidRealmConfigForRealm: Invalid RealmConfig for Realm" + ] + }, + { + "kind": "errorNode", + "name": "tokenOwnerRecordAlreadyExists", + "code": 579, + "message": "TokenOwnerRecord already exists", + "docs": [ + "TokenOwnerRecordAlreadyExists: TokenOwnerRecord already exists" + ] + }, + { + "kind": "errorNode", + "name": "governingTokenDepositsNotAllowed", + "code": 580, + "message": "Governing token deposits not allowed", + "docs": [ + "GoverningTokenDepositsNotAllowed: Governing token deposits not allowed" + ] + }, + { + "kind": "errorNode", + "name": "invalidVoteChoiceWeightPercentage", + "code": 581, + "message": "Invalid vote choice weight percentage", + "docs": [ + "InvalidVoteChoiceWeightPercentage: Invalid vote choice weight percentage" + ] + }, + { + "kind": "errorNode", + "name": "voteTypeNotSupported", + "code": 582, + "message": "Vote type not supported", + "docs": [ + "VoteTypeNotSupported: Vote type not supported" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalOptions", + "code": 583, + "message": "Invalid proposal options", + "docs": [ + "InvalidProposalOptions: Invalid proposal options" + ] + }, + { + "kind": "errorNode", + "name": "proposalIsNotExecutable", + "code": 584, + "message": "Proposal is not not executable", + "docs": [ + "ProposalIsNotExecutable: Proposal is not not executable" + ] + }, + { + "kind": "errorNode", + "name": "denyVoteIsNotAllowed", + "code": 585, + "message": "Deny vote is not allowed", + "docs": [ + "DenyVoteIsNotAllowed: Deny vote is not allowed" + ] + }, + { + "kind": "errorNode", + "name": "cannotExecuteDefeatedOption", + "code": 586, + "message": "Cannot execute defeated option", + "docs": [ + "CannotExecuteDefeatedOption: Cannot execute defeated option" + ] + }, + { + "kind": "errorNode", + "name": "voterWeightRecordInvalidAction", + "code": 587, + "message": "VoterWeightRecord invalid action", + "docs": [ + "VoterWeightRecordInvalidAction: VoterWeightRecord invalid action" + ] + }, + { + "kind": "errorNode", + "name": "voterWeightRecordInvalidActionTarget", + "code": 588, + "message": "VoterWeightRecord invalid action target", + "docs": [ + "VoterWeightRecordInvalidActionTarget: VoterWeightRecord invalid action target" + ] + }, + { + "kind": "errorNode", + "name": "invalidMaxVoterWeightRecordForRealm", + "code": 589, + "message": "Invalid MaxVoterWeightRecord for Realm", + "docs": [ + "InvalidMaxVoterWeightRecordForRealm: Invalid MaxVoterWeightRecord for Realm" + ] + }, + { + "kind": "errorNode", + "name": "invalidMaxVoterWeightRecordForGoverningTokenMint", + "code": 590, + "message": "Invalid MaxVoterWeightRecord for GoverningTokenMint", + "docs": [ + "InvalidMaxVoterWeightRecordForGoverningTokenMint: Invalid MaxVoterWeightRecord for GoverningTokenMint" + ] + }, + { + "kind": "errorNode", + "name": "maxVoterWeightRecordExpired", + "code": 591, + "message": "MaxVoterWeightRecord expired", + "docs": [ + "MaxVoterWeightRecordExpired: MaxVoterWeightRecord expired" + ] + }, + { + "kind": "errorNode", + "name": "notSupportedVoteType", + "code": 592, + "message": "Not supported VoteType", + "docs": [ + "NotSupportedVoteType: Not supported VoteType" + ] + }, + { + "kind": "errorNode", + "name": "realmConfigChangeNotAllowed", + "code": 593, + "message": "RealmConfig change not allowed", + "docs": [ + "RealmConfigChangeNotAllowed: RealmConfig change not allowed" + ] + }, + { + "kind": "errorNode", + "name": "governanceConfigChangeNotAllowed", + "code": 594, + "message": "GovernanceConfig change not allowed", + "docs": [ + "GovernanceConfigChangeNotAllowed: GovernanceConfig change not allowed" + ] + }, + { + "kind": "errorNode", + "name": "atLeastOneVoteThresholdRequired", + "code": 595, + "message": "At least one VoteThreshold is required", + "docs": [ + "AtLeastOneVoteThresholdRequired: At least one VoteThreshold is required" + ] + }, + { + "kind": "errorNode", + "name": "reservedBufferMustBeEmpty", + "code": 596, + "message": "Reserved buffer must be empty", + "docs": [ + "ReservedBufferMustBeEmpty: Reserved buffer must be empty" + ] + }, + { + "kind": "errorNode", + "name": "cannotRelinquishInFinalizingState", + "code": 597, + "message": "Cannot Relinquish in Finalizing state", + "docs": [ + "CannotRelinquishInFinalizingState: Cannot Relinquish in Finalizing state" + ] + }, + { + "kind": "errorNode", + "name": "invalidRealmConfigAddress", + "code": 598, + "message": "Invalid RealmConfig account address", + "docs": [ + "InvalidRealmConfigAddress: Invalid RealmConfig account address" + ] + }, + { + "kind": "errorNode", + "name": "cannotDepositDormantTokens", + "code": 599, + "message": "Cannot deposit dormant tokens", + "docs": [ + "CannotDepositDormantTokens: Cannot deposit dormant tokens" + ] + }, + { + "kind": "errorNode", + "name": "cannotWithdrawMembershipTokens", + "code": 600, + "message": "Cannot withdraw membership tokens", + "docs": [ + "CannotWithdrawMembershipTokens: Cannot withdraw membership tokens" + ] + }, + { + "kind": "errorNode", + "name": "cannotRevokeGoverningTokens", + "code": 601, + "message": "Cannot revoke GoverningTokens", + "docs": [ + "CannotRevokeGoverningTokens: Cannot revoke GoverningTokens" + ] + }, + { + "kind": "errorNode", + "name": "invalidRevokeAmount", + "code": 602, + "message": "Invalid Revoke amount", + "docs": [ + "InvalidRevokeAmount: Invalid Revoke amount" + ] + }, + { + "kind": "errorNode", + "name": "invalidGoverningTokenSource", + "code": 603, + "message": "Invalid GoverningToken source", + "docs": [ + "InvalidGoverningTokenSource: Invalid GoverningToken source" + ] + }, + { + "kind": "errorNode", + "name": "cannotChangeCommunityTokenTypeToMembership", + "code": 604, + "message": "Cannot change community TokenType to Membership", + "docs": [ + "CannotChangeCommunityTokenTypeToMembership: Cannot change community TokenType to Membership" + ] + }, + { + "kind": "errorNode", + "name": "voterWeightThresholdDisabled", + "code": 605, + "message": "Voter weight threshold disabled", + "docs": [ + "VoterWeightThresholdDisabled: Voter weight threshold disabled" + ] + }, + { + "kind": "errorNode", + "name": "voteNotAllowedInCoolOffTime", + "code": 606, + "message": "Vote not allowed in cool off time", + "docs": [ + "VoteNotAllowedInCoolOffTime: Vote not allowed in cool off time" + ] + }, + { + "kind": "errorNode", + "name": "cannotRefundProposalDeposit", + "code": 607, + "message": "Cannot refund ProposalDeposit", + "docs": [ + "CannotRefundProposalDeposit: Cannot refund ProposalDeposit" + ] + }, + { + "kind": "errorNode", + "name": "invalidProposalForProposalDeposit", + "code": 608, + "message": "Invalid Proposal for ProposalDeposit", + "docs": [ + "InvalidProposalForProposalDeposit: Invalid Proposal for ProposalDeposit" + ] + }, + { + "kind": "errorNode", + "name": "invalidDepositExemptProposalCount", + "code": 609, + "message": "Invalid deposit_exempt_proposal_count", + "docs": [ + "InvalidDepositExemptProposalCount: Invalid deposit_exempt_proposal_count" + ] + }, + { + "kind": "errorNode", + "name": "governingTokenMintNotAllowedToVote", + "code": 610, + "message": "GoverningTokenMint not allowed to vote", + "docs": [ + "GoverningTokenMintNotAllowedToVote: GoverningTokenMint not allowed to vote" + ] + }, + { + "kind": "errorNode", + "name": "invalidDepositPayerForProposalDeposit", + "code": 611, + "message": "Invalid deposit Payer for ProposalDeposit", + "docs": [ + "InvalidDepositPayerForProposalDeposit: Invalid deposit Payer for ProposalDeposit" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateNotFinal", + "code": 612, + "message": "Invalid State: Proposal is not in final state", + "docs": [ + "InvalidStateNotFinal: Invalid State: Proposal is not in final state" + ] + }, + { + "kind": "errorNode", + "name": "invalidStateToCompleteProposal", + "code": 613, + "message": "Invalid state for proposal state transition to Completed", + "docs": [ + "InvalidStateToCompleteProposal: Invalid state for proposal state transition to Completed" + ] + }, + { + "kind": "errorNode", + "name": "invalidNumberOfVoteChoices", + "code": 614, + "message": "Invalid number of vote choices", + "docs": [ + "InvalidNumberOfVoteChoices: Invalid number of vote choices" + ] + }, + { + "kind": "errorNode", + "name": "rankedVoteIsNotSupported", + "code": 615, + "message": "Ranked vote is not supported", + "docs": [ + "RankedVoteIsNotSupported: Ranked vote is not supported" + ] + }, + { + "kind": "errorNode", + "name": "choiceWeightMustBe100Percent", + "code": 616, + "message": "Choice weight must be 100%", + "docs": [ + "ChoiceWeightMustBe100Percent: Choice weight must be 100%" + ] + }, + { + "kind": "errorNode", + "name": "singleChoiceOnlyIsAllowed", + "code": 617, + "message": "Single choice only is allowed", + "docs": [ + "SingleChoiceOnlyIsAllowed: Single choice only is allowed" + ] + }, + { + "kind": "errorNode", + "name": "atLeastSingleChoiceIsRequired", + "code": 618, + "message": "At least single choice is required", + "docs": [ + "AtLeastSingleChoiceIsRequired: At least single choice is required" + ] + }, + { + "kind": "errorNode", + "name": "totalVoteWeightMustBe100Percent", + "code": 619, + "message": "Total vote weight must be 100%", + "docs": [ + "TotalVoteWeightMustBe100Percent: Total vote weight must be 100%" + ] + }, + { + "kind": "errorNode", + "name": "invalidMultiChoiceProposalParameters", + "code": 620, + "message": "Invalid multi choice proposal parameters", + "docs": [ + "InvalidMultiChoiceProposalParameters: Invalid multi choice proposal parameters" + ] + }, + { + "kind": "errorNode", + "name": "invalidGovernanceForRequiredSignatory", + "code": 621, + "message": "Invalid Governance for RequiredSignatory", + "docs": [ + "InvalidGovernanceForRequiredSignatory: Invalid Governance for RequiredSignatory" + ] + }, + { + "kind": "errorNode", + "name": "signatoryRecordAlreadyExists", + "code": 622, + "message": "Signatory Record has already been created", + "docs": [ + "SignatoryRecordAlreadyExists: Signatory Record has already been created" + ] + }, + { + "kind": "errorNode", + "name": "instructionDeprecated", + "code": 623, + "message": "Instruction has been removed", + "docs": [ + "InstructionDeprecated: Instruction has been removed" + ] + }, + { + "kind": "errorNode", + "name": "missingRequiredSignatories", + "code": 624, + "message": "Proposal is missing required signatories", + "docs": [ + "MissingRequiredSignatories: Proposal is missing required signatories" + ] + } + ] + }, + "additionalPrograms": [] +} diff --git a/e2e/governance/src/generated/accounts/governance_v1.rs b/e2e/governance/src/generated/accounts/governance_v1.rs new file mode 100644 index 0000000..35e33c2 --- /dev/null +++ b/e2e/governance/src/generated/accounts/governance_v1.rs @@ -0,0 +1,180 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GovernanceV1 { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub governed_account: Address, + pub proposals_count: u32, + pub config: GovernanceConfig, +} + +impl GovernanceV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `GovernanceV1::PREFIX` + /// 1. realm (`Address`) + /// 2. seed (`Address`) + pub const PREFIX: &'static [u8] = b"account-governance"; + + pub fn create_pda( + realm: Address, + seed: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"account-governance", + realm.as_ref(), + seed.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(realm: &Address, seed: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"account-governance", realm.as_ref(), seed.as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for GovernanceV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_governance_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_governance_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_governance_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GovernanceV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_governance_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_governance_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_governance_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GovernanceV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for GovernanceV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for GovernanceV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for GovernanceV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for GovernanceV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for GovernanceV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/governance_v2.rs b/e2e/governance/src/generated/accounts/governance_v2.rs new file mode 100644 index 0000000..4814a88 --- /dev/null +++ b/e2e/governance/src/generated/accounts/governance_v2.rs @@ -0,0 +1,184 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::GovernanceConfig; +use crate::generated::types::Reserved119; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GovernanceV2 { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub governed_account: Address, + pub reserved1: u32, + pub config: GovernanceConfig, + pub reserved_v2: Reserved119, + pub required_signatories_count: u8, + pub active_proposal_count: u64, +} + +impl GovernanceV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `GovernanceV2::PREFIX` + /// 1. realm (`Address`) + /// 2. seed (`Address`) + pub const PREFIX: &'static [u8] = b"account-governance"; + + pub fn create_pda( + realm: Address, + seed: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"account-governance", + realm.as_ref(), + seed.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(realm: &Address, seed: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"account-governance", realm.as_ref(), seed.as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for GovernanceV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_governance_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_governance_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_governance_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GovernanceV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_governance_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_governance_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_governance_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GovernanceV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for GovernanceV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for GovernanceV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for GovernanceV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for GovernanceV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for GovernanceV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/legacy_token_owner_record.rs b/e2e/governance/src/generated/accounts/legacy_token_owner_record.rs new file mode 100644 index 0000000..cbc690d --- /dev/null +++ b/e2e/governance/src/generated/accounts/legacy_token_owner_record.rs @@ -0,0 +1,198 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct LegacyTokenOwnerRecord { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub governing_token_mint: Address, + pub governing_token_owner: Address, + pub governing_token_deposit_amount: u64, + pub unrelinquished_votes_count: u32, + pub total_votes_count: u32, + pub outstanding_proposal_count: u8, + pub reserved: [u8; 7], + pub governance_delegate: Option
, + pub reserved_v2: [u8; 128], +} + +impl LegacyTokenOwnerRecord { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `LegacyTokenOwnerRecord::PREFIX` + /// 1. realm (`Address`) + /// 2. governing_token_mint (`Address`) + /// 3. governing_token_owner (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + realm: Address, + governing_token_mint: Address, + governing_token_owner: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + realm: &Address, + governing_token_mint: &Address, + governing_token_owner: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for LegacyTokenOwnerRecord { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_legacy_token_owner_record( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_legacy_token_owner_record(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_legacy_token_owner_record( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = + Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = LegacyTokenOwnerRecord::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_legacy_token_owner_record( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_legacy_token_owner_record(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_legacy_token_owner_record( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = LegacyTokenOwnerRecord::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for LegacyTokenOwnerRecord { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for LegacyTokenOwnerRecord {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for LegacyTokenOwnerRecord { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for LegacyTokenOwnerRecord {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for LegacyTokenOwnerRecord { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/mod.rs b/e2e/governance/src/generated/accounts/mod.rs new file mode 100644 index 0000000..4160ab4 --- /dev/null +++ b/e2e/governance/src/generated/accounts/mod.rs @@ -0,0 +1,46 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#governance_v1; +pub(crate) mod r#governance_v2; +pub(crate) mod r#legacy_token_owner_record; +pub(crate) mod r#program_metadata; +pub(crate) mod r#proposal_deposit; +pub(crate) mod r#proposal_instruction_v1; +pub(crate) mod r#proposal_transaction_v2; +pub(crate) mod r#proposal_v1; +pub(crate) mod r#proposal_v2; +pub(crate) mod r#realm_config_account; +pub(crate) mod r#realm_v1; +pub(crate) mod r#realm_v2; +pub(crate) mod r#required_signatory; +pub(crate) mod r#signatory_record_v1; +pub(crate) mod r#signatory_record_v2; +pub(crate) mod r#token_owner_record_v1; +pub(crate) mod r#token_owner_record_v2; +pub(crate) mod r#vote_record_v1; +pub(crate) mod r#vote_record_v2; + +pub use self::r#governance_v1::*; +pub use self::r#governance_v2::*; +pub use self::r#legacy_token_owner_record::*; +pub use self::r#program_metadata::*; +pub use self::r#proposal_deposit::*; +pub use self::r#proposal_instruction_v1::*; +pub use self::r#proposal_transaction_v2::*; +pub use self::r#proposal_v1::*; +pub use self::r#proposal_v2::*; +pub use self::r#realm_config_account::*; +pub use self::r#realm_v1::*; +pub use self::r#realm_v2::*; +pub use self::r#required_signatory::*; +pub use self::r#signatory_record_v1::*; +pub use self::r#signatory_record_v2::*; +pub use self::r#token_owner_record_v1::*; +pub use self::r#token_owner_record_v2::*; +pub use self::r#vote_record_v1::*; +pub use self::r#vote_record_v2::*; diff --git a/e2e/governance/src/generated/accounts/program_metadata.rs b/e2e/governance/src/generated/accounts/program_metadata.rs new file mode 100644 index 0000000..dfe5617 --- /dev/null +++ b/e2e/governance/src/generated/accounts/program_metadata.rs @@ -0,0 +1,146 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::Slot; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProgramMetadata { + pub account_type: GovernanceAccountType, + pub updated_at: Slot, + pub version: String, + pub reserved: [u8; 64], +} + +impl ProgramMetadata { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProgramMetadata { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_program_metadata( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_program_metadata(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_program_metadata( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProgramMetadata::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_program_metadata( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_program_metadata(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_program_metadata( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProgramMetadata::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProgramMetadata { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProgramMetadata {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProgramMetadata { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProgramMetadata {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProgramMetadata { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/proposal_deposit.rs b/e2e/governance/src/generated/accounts/proposal_deposit.rs new file mode 100644 index 0000000..ed75d1e --- /dev/null +++ b/e2e/governance/src/generated/accounts/proposal_deposit.rs @@ -0,0 +1,182 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalDeposit { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub deposit_payer: Address, + pub reserved: [u8; 64], +} + +impl ProposalDeposit { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `ProposalDeposit::PREFIX` + /// 1. proposal (`Address`) + /// 2. deposit_payer (`Address`) + pub const PREFIX: &'static [u8] = b"proposal-deposit"; + + pub fn create_pda( + proposal: Address, + deposit_payer: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"proposal-deposit", + proposal.as_ref(), + deposit_payer.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(proposal: &Address, deposit_payer: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"proposal-deposit", + proposal.as_ref(), + deposit_payer.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProposalDeposit { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_proposal_deposit( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_proposal_deposit(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_proposal_deposit( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalDeposit::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_proposal_deposit( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_proposal_deposit(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_proposal_deposit( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalDeposit::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProposalDeposit { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProposalDeposit {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProposalDeposit { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProposalDeposit {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProposalDeposit { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/proposal_instruction_v1.rs b/e2e/governance/src/generated/accounts/proposal_instruction_v1.rs new file mode 100644 index 0000000..f52a3a1 --- /dev/null +++ b/e2e/governance/src/generated/accounts/proposal_instruction_v1.rs @@ -0,0 +1,197 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::InstructionData; +use crate::generated::types::TransactionExecutionStatus; +use crate::generated::types::UnixTimestamp; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalInstructionV1 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub instruction_index: u16, + pub hold_up_time: u32, + pub instruction: InstructionData, + pub executed_at: Option, + pub execution_status: TransactionExecutionStatus, +} + +impl ProposalInstructionV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `ProposalInstructionV1::PREFIX` + /// 1. proposal (`Address`) + /// 2. option_index (`u8`) + /// 3. index (`u16`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + option_index: u8, + index: u16, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + proposal: &Address, + option_index: u8, + index: u16, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProposalInstructionV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_proposal_instruction_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_proposal_instruction_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_proposal_instruction_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = + Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalInstructionV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_proposal_instruction_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_proposal_instruction_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_proposal_instruction_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalInstructionV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProposalInstructionV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProposalInstructionV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProposalInstructionV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProposalInstructionV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProposalInstructionV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/proposal_transaction_v2.rs b/e2e/governance/src/generated/accounts/proposal_transaction_v2.rs new file mode 100644 index 0000000..673cab9 --- /dev/null +++ b/e2e/governance/src/generated/accounts/proposal_transaction_v2.rs @@ -0,0 +1,199 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::InstructionData; +use crate::generated::types::TransactionExecutionStatus; +use crate::generated::types::UnixTimestamp; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalTransactionV2 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub option_index: u8, + pub transaction_index: u16, + pub hold_up_time: u32, + pub instructions: Vec, + pub executed_at: Option, + pub execution_status: TransactionExecutionStatus, + pub reserved_v2: [u8; 8], +} + +impl ProposalTransactionV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `ProposalTransactionV2::PREFIX` + /// 1. proposal (`Address`) + /// 2. option_index (`u8`) + /// 3. index (`u16`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + option_index: u8, + index: u16, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + proposal: &Address, + option_index: u8, + index: u16, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProposalTransactionV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_proposal_transaction_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_proposal_transaction_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_proposal_transaction_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = + Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalTransactionV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_proposal_transaction_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_proposal_transaction_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_proposal_transaction_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalTransactionV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProposalTransactionV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProposalTransactionV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProposalTransactionV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProposalTransactionV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProposalTransactionV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/proposal_v1.rs b/e2e/governance/src/generated/accounts/proposal_v1.rs new file mode 100644 index 0000000..f85d14c --- /dev/null +++ b/e2e/governance/src/generated/accounts/proposal_v1.rs @@ -0,0 +1,215 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::InstructionExecutionFlags; +use crate::generated::types::ProposalState; +use crate::generated::types::Slot; +use crate::generated::types::UnixTimestamp; +use crate::generated::types::VoteThreshold; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalV1 { + pub account_type: GovernanceAccountType, + pub governance: Address, + pub governing_token_mint: Address, + pub state: ProposalState, + pub token_owner_record: Address, + pub signatories_count: u8, + pub signatories_signed_off_count: u8, + pub yes_votes_count: u64, + pub no_votes_count: u64, + pub instructions_executed_count: u16, + pub instructions_count: u16, + pub instructions_next_index: u16, + pub draft_at: UnixTimestamp, + pub signing_off_at: Option, + pub voting_at: Option, + pub voting_at_slot: Option, + pub voting_completed_at: Option, + pub executing_at: Option, + pub closed_at: Option, + pub execution_flags: InstructionExecutionFlags, + pub max_vote_weight: Option, + pub vote_threshold: Option, + pub name: String, + pub description_link: String, +} + +impl ProposalV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `ProposalV1::PREFIX` + /// 1. governance (`Address`) + /// 2. governing_token_mint (`Address`) + /// 3. proposal_seed (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + governance: Address, + governing_token_mint: Address, + proposal_seed: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + governance: &Address, + governing_token_mint: &Address, + proposal_seed: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProposalV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_proposal_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_proposal_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_proposal_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_proposal_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_proposal_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_proposal_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProposalV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProposalV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProposalV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProposalV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProposalV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/proposal_v2.rs b/e2e/governance/src/generated/accounts/proposal_v2.rs new file mode 100644 index 0000000..103cf8f --- /dev/null +++ b/e2e/governance/src/generated/accounts/proposal_v2.rs @@ -0,0 +1,221 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::InstructionExecutionFlags; +use crate::generated::types::ProposalOption; +use crate::generated::types::ProposalState; +use crate::generated::types::Slot; +use crate::generated::types::UnixTimestamp; +use crate::generated::types::VoteThreshold; +use crate::generated::types::VoteType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalV2 { + pub account_type: GovernanceAccountType, + pub governance: Address, + pub governing_token_mint: Address, + pub state: ProposalState, + pub token_owner_record: Address, + pub signatories_count: u8, + pub signatories_signed_off_count: u8, + pub vote_type: VoteType, + pub options: Vec, + pub deny_vote_weight: Option, + pub reserved1: u8, + pub abstain_vote_weight: Option, + pub start_voting_at: Option, + pub draft_at: UnixTimestamp, + pub signing_off_at: Option, + pub voting_at: Option, + pub voting_at_slot: Option, + pub voting_completed_at: Option, + pub executing_at: Option, + pub closed_at: Option, + pub execution_flags: InstructionExecutionFlags, + pub max_vote_weight: Option, + pub max_voting_time: Option, + pub vote_threshold: Option, + pub reserved: [u8; 64], + pub name: String, + pub description_link: String, + pub veto_vote_weight: u64, +} + +impl ProposalV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `ProposalV2::PREFIX` + /// 1. governance (`Address`) + /// 2. governing_token_mint (`Address`) + /// 3. proposal_seed (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + governance: Address, + governing_token_mint: Address, + proposal_seed: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + governance: &Address, + governing_token_mint: &Address, + proposal_seed: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ProposalV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_proposal_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_proposal_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_proposal_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_proposal_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_proposal_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_proposal_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ProposalV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for ProposalV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ProposalV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ProposalV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ProposalV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ProposalV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/realm_config_account.rs b/e2e/governance/src/generated/accounts/realm_config_account.rs new file mode 100644 index 0000000..4e77661 --- /dev/null +++ b/e2e/governance/src/generated/accounts/realm_config_account.rs @@ -0,0 +1,174 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::GoverningTokenConfig; +use crate::generated::types::Reserved110; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmConfigAccount { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub community_token_config: GoverningTokenConfig, + pub council_token_config: GoverningTokenConfig, + pub reserved: Reserved110, +} + +impl RealmConfigAccount { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `RealmConfigAccount::PREFIX` + /// 1. realm (`Address`) + pub const PREFIX: &'static [u8] = b"realm-config"; + + pub fn create_pda( + realm: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[b"realm-config", realm.as_ref(), &[bump]], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(realm: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"realm-config", realm.as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for RealmConfigAccount { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_realm_config_account( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_realm_config_account(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_realm_config_account( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmConfigAccount::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_realm_config_account( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_realm_config_account(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_realm_config_account( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmConfigAccount::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for RealmConfigAccount { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for RealmConfigAccount {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for RealmConfigAccount { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for RealmConfigAccount {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for RealmConfigAccount { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/realm_v1.rs b/e2e/governance/src/generated/accounts/realm_v1.rs new file mode 100644 index 0000000..567bfe6 --- /dev/null +++ b/e2e/governance/src/generated/accounts/realm_v1.rs @@ -0,0 +1,176 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::RealmConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; +use spl_collections::TrailingStr; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmV1 { + pub account_type: GovernanceAccountType, + pub community_mint: Address, + pub config: RealmConfig, + pub reserved: [u8; 6], + pub voting_proposal_count: u16, + pub authority: Option
, + pub name: String, +} + +impl RealmV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `RealmV1::PREFIX` + /// 1. name (`TrailingStr`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + name: TrailingStr, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[b"governance", name.to_string().as_ref(), &[bump]], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(name: TrailingStr) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"governance", name.to_string().as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for RealmV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_realm_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_realm_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_realm_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_realm_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_realm_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_realm_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for RealmV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for RealmV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for RealmV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for RealmV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for RealmV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/realm_v2.rs b/e2e/governance/src/generated/accounts/realm_v2.rs new file mode 100644 index 0000000..52873d9 --- /dev/null +++ b/e2e/governance/src/generated/accounts/realm_v2.rs @@ -0,0 +1,177 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::RealmConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; +use spl_collections::TrailingStr; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmV2 { + pub account_type: GovernanceAccountType, + pub community_mint: Address, + pub config: RealmConfig, + pub reserved: [u8; 6], + pub legacy1: u16, + pub authority: Option
, + pub name: String, + pub reserved_v2: [u8; 128], +} + +impl RealmV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `RealmV2::PREFIX` + /// 1. name (`TrailingStr`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + name: TrailingStr, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[b"governance", name.to_string().as_ref(), &[bump]], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(name: TrailingStr) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"governance", name.to_string().as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for RealmV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_realm_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_realm_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_realm_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_realm_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_realm_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_realm_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RealmV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for RealmV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for RealmV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for RealmV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for RealmV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for RealmV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/required_signatory.rs b/e2e/governance/src/generated/accounts/required_signatory.rs new file mode 100644 index 0000000..9c6ba22 --- /dev/null +++ b/e2e/governance/src/generated/accounts/required_signatory.rs @@ -0,0 +1,182 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RequiredSignatory { + pub account_type: GovernanceAccountType, + pub account_version: u8, + pub governance: Address, + pub signatory: Address, +} + +impl RequiredSignatory { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `RequiredSignatory::PREFIX` + /// 1. governance (`Address`) + /// 2. signatory (`Address`) + pub const PREFIX: &'static [u8] = b"required-signatory"; + + pub fn create_pda( + governance: Address, + signatory: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"required-signatory", + governance.as_ref(), + signatory.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(governance: &Address, signatory: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"required-signatory", + governance.as_ref(), + signatory.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for RequiredSignatory { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_required_signatory( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_required_signatory(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_required_signatory( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RequiredSignatory::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_required_signatory( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_required_signatory(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_required_signatory( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = RequiredSignatory::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for RequiredSignatory { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for RequiredSignatory {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for RequiredSignatory { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for RequiredSignatory {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for RequiredSignatory { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/signatory_record_v1.rs b/e2e/governance/src/generated/accounts/signatory_record_v1.rs new file mode 100644 index 0000000..4e5ae19 --- /dev/null +++ b/e2e/governance/src/generated/accounts/signatory_record_v1.rs @@ -0,0 +1,178 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SignatoryRecordV1 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub signatory: Address, + pub signed_off: bool, +} + +impl SignatoryRecordV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `SignatoryRecordV1::PREFIX` + /// 1. proposal (`Address`) + /// 2. signatory (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + signatory: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + signatory.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(proposal: &Address, signatory: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"governance", proposal.as_ref(), signatory.as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for SignatoryRecordV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_signatory_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_signatory_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_signatory_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = SignatoryRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_signatory_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_signatory_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_signatory_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = SignatoryRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for SignatoryRecordV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for SignatoryRecordV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for SignatoryRecordV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for SignatoryRecordV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for SignatoryRecordV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/signatory_record_v2.rs b/e2e/governance/src/generated/accounts/signatory_record_v2.rs new file mode 100644 index 0000000..0d983f7 --- /dev/null +++ b/e2e/governance/src/generated/accounts/signatory_record_v2.rs @@ -0,0 +1,179 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SignatoryRecordV2 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub signatory: Address, + pub signed_off: bool, + pub reserved_v2: [u8; 8], +} + +impl SignatoryRecordV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `SignatoryRecordV2::PREFIX` + /// 1. proposal (`Address`) + /// 2. signatory (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + signatory: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + signatory.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda(proposal: &Address, signatory: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[b"governance", proposal.as_ref(), signatory.as_ref()], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for SignatoryRecordV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_signatory_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_signatory_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_signatory_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = SignatoryRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_signatory_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_signatory_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_signatory_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = SignatoryRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for SignatoryRecordV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for SignatoryRecordV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for SignatoryRecordV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for SignatoryRecordV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for SignatoryRecordV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/token_owner_record_v1.rs b/e2e/governance/src/generated/accounts/token_owner_record_v1.rs new file mode 100644 index 0000000..ec598ec --- /dev/null +++ b/e2e/governance/src/generated/accounts/token_owner_record_v1.rs @@ -0,0 +1,196 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct TokenOwnerRecordV1 { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub governing_token_mint: Address, + pub governing_token_owner: Address, + pub governing_token_deposit_amount: u64, + pub unrelinquished_votes_count: u64, + pub outstanding_proposal_count: u8, + pub version: u8, + pub reserved: [u8; 6], + pub governance_delegate: Option
, +} + +impl TokenOwnerRecordV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `TokenOwnerRecordV1::PREFIX` + /// 1. realm (`Address`) + /// 2. governing_token_mint (`Address`) + /// 3. governing_token_owner (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + realm: Address, + governing_token_mint: Address, + governing_token_owner: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + realm: &Address, + governing_token_mint: &Address, + governing_token_owner: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for TokenOwnerRecordV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_token_owner_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_token_owner_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_token_owner_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = TokenOwnerRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_token_owner_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_token_owner_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_token_owner_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = TokenOwnerRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for TokenOwnerRecordV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for TokenOwnerRecordV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for TokenOwnerRecordV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for TokenOwnerRecordV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for TokenOwnerRecordV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/token_owner_record_v2.rs b/e2e/governance/src/generated/accounts/token_owner_record_v2.rs new file mode 100644 index 0000000..d2cbf3d --- /dev/null +++ b/e2e/governance/src/generated/accounts/token_owner_record_v2.rs @@ -0,0 +1,197 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct TokenOwnerRecordV2 { + pub account_type: GovernanceAccountType, + pub realm: Address, + pub governing_token_mint: Address, + pub governing_token_owner: Address, + pub governing_token_deposit_amount: u64, + pub unrelinquished_votes_count: u64, + pub outstanding_proposal_count: u8, + pub version: u8, + pub reserved: [u8; 6], + pub governance_delegate: Option
, + pub reserved_v2: [u8; 128], +} + +impl TokenOwnerRecordV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `TokenOwnerRecordV2::PREFIX` + /// 1. realm (`Address`) + /// 2. governing_token_mint (`Address`) + /// 3. governing_token_owner (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + realm: Address, + governing_token_mint: Address, + governing_token_owner: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + realm: &Address, + governing_token_mint: &Address, + governing_token_owner: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for TokenOwnerRecordV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_token_owner_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_token_owner_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_token_owner_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = TokenOwnerRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_token_owner_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_token_owner_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_token_owner_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = TokenOwnerRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for TokenOwnerRecordV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for TokenOwnerRecordV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for TokenOwnerRecordV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for TokenOwnerRecordV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for TokenOwnerRecordV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/vote_record_v1.rs b/e2e/governance/src/generated/accounts/vote_record_v1.rs new file mode 100644 index 0000000..33f964d --- /dev/null +++ b/e2e/governance/src/generated/accounts/vote_record_v1.rs @@ -0,0 +1,187 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::VoteWeightV1; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct VoteRecordV1 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub governing_token_owner: Address, + pub is_relinquished: bool, + pub vote_weight: VoteWeightV1, +} + +impl VoteRecordV1 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `VoteRecordV1::PREFIX` + /// 1. proposal (`Address`) + /// 2. token_owner_record (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + token_owner_record: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + token_owner_record.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + proposal: &Address, + token_owner_record: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + proposal.as_ref(), + token_owner_record.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for VoteRecordV1 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_vote_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_vote_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_vote_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VoteRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_vote_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_vote_record_v1(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_vote_record_v1( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VoteRecordV1::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for VoteRecordV1 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for VoteRecordV1 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for VoteRecordV1 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for VoteRecordV1 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for VoteRecordV1 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/accounts/vote_record_v2.rs b/e2e/governance/src/generated/accounts/vote_record_v2.rs new file mode 100644 index 0000000..5a6ebd6 --- /dev/null +++ b/e2e/governance/src/generated/accounts/vote_record_v2.rs @@ -0,0 +1,189 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceAccountType; +use crate::generated::types::Vote; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct VoteRecordV2 { + pub account_type: GovernanceAccountType, + pub proposal: Address, + pub governing_token_owner: Address, + pub is_relinquished: bool, + pub voter_weight: u64, + pub vote: Vote, + pub reserved_v2: [u8; 8], +} + +impl VoteRecordV2 { + /// Prefix values used to generate a PDA for this account. + /// + /// Values are positional and appear in the following order: + /// + /// 0. `VoteRecordV2::PREFIX` + /// 1. proposal (`Address`) + /// 2. token_owner_record (`Address`) + pub const PREFIX: &'static [u8] = b"governance"; + + pub fn create_pda( + proposal: Address, + token_owner_record: Address, + bump: u8, + ) -> Result { + solana_address::Address::create_program_address( + &[ + b"governance", + proposal.as_ref(), + token_owner_record.as_ref(), + &[bump], + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + pub fn find_pda( + proposal: &Address, + token_owner_record: &Address, + ) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + b"governance", + proposal.as_ref(), + token_owner_record.as_ref(), + ], + &crate::SPL_GOVERNANCE_ID, + ) + } + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for VoteRecordV2 { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) + } +} + +#[cfg(feature = "fetch")] +pub fn fetch_vote_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_vote_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_vote_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( + "Account not found: {address}" + )))?; + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VoteRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }); + } + Ok(decoded_accounts) +} + +#[cfg(feature = "fetch")] +pub fn fetch_maybe_vote_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_vote_record_v2(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_vote_record_v2( + rpc: &solana_client::rpc_client::RpcClient, + addresses: &[solana_address::Address], +) -> Result>, std::io::Error> { + let accounts = rpc + .get_multiple_accounts(addresses) + .map_err(|e| std::io::Error::other(e.to_string()))?; + let mut decoded_accounts: Vec> = Vec::new(); + for i in 0..addresses.len() { + let address = addresses[i]; + if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SPL_GOVERNANCE_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VoteRecordV2::from_bytes(&account.data)?; + decoded_accounts.push(crate::shared::MaybeAccount::Exists( + crate::shared::DecodedAccount { + address, + account: account.clone(), + data, + }, + )); + } else { + decoded_accounts.push(crate::shared::MaybeAccount::NotFound(address)); + } + } + Ok(decoded_accounts) +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for VoteRecordV2 { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for VoteRecordV2 {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for VoteRecordV2 { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::SPL_GOVERNANCE_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for VoteRecordV2 {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for VoteRecordV2 { + const DISCRIMINATOR: &[u8] = &[0; 8]; +} diff --git a/e2e/governance/src/generated/errors/mod.rs b/e2e/governance/src/generated/errors/mod.rs new file mode 100644 index 0000000..b84bbdc --- /dev/null +++ b/e2e/governance/src/generated/errors/mod.rs @@ -0,0 +1,10 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod spl_governance; + +pub use self::spl_governance::SplGovernanceError; diff --git a/e2e/governance/src/generated/errors/spl_governance.rs b/e2e/governance/src/generated/errors/spl_governance.rs new file mode 100644 index 0000000..6e19600 --- /dev/null +++ b/e2e/governance/src/generated/errors/spl_governance.rs @@ -0,0 +1,394 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use num_derive::FromPrimitive; +use thiserror::Error; + +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum SplGovernanceError { + /// 500 - Invalid instruction passed to program + #[error("Invalid instruction passed to program")] + InvalidInstruction = 0x1F4, + /// 501 - Realm with the given name and governing mints already exists + #[error("Realm with the given name and governing mints already exists")] + RealmAlreadyExists = 0x1F5, + /// 502 - Invalid realm + #[error("Invalid realm")] + InvalidRealm = 0x1F6, + /// 503 - Invalid Governing Token Mint + #[error("Invalid Governing Token Mint")] + InvalidGoverningTokenMint = 0x1F7, + /// 504 - Governing Token Owner must sign transaction + #[error("Governing Token Owner must sign transaction")] + GoverningTokenOwnerMustSign = 0x1F8, + /// 505 - Governing Token Owner or Delegate must sign transaction + #[error("Governing Token Owner or Delegate must sign transaction")] + GoverningTokenOwnerOrDelegateMustSign = 0x1F9, + /// 506 - All votes must be relinquished to withdraw governing tokens + #[error("All votes must be relinquished to withdraw governing tokens")] + AllVotesMustBeRelinquishedToWithdrawGoverningTokens = 0x1FA, + /// 507 - Invalid Token Owner Record account address + #[error("Invalid Token Owner Record account address")] + InvalidTokenOwnerRecordAccountAddress = 0x1FB, + /// 508 - Invalid GoverningMint for TokenOwnerRecord + #[error("Invalid GoverningMint for TokenOwnerRecord")] + InvalidGoverningMintForTokenOwnerRecord = 0x1FC, + /// 509 - Invalid Realm for TokenOwnerRecord + #[error("Invalid Realm for TokenOwnerRecord")] + InvalidRealmForTokenOwnerRecord = 0x1FD, + /// 510 - Invalid Proposal for ProposalTransaction, + #[error("Invalid Proposal for ProposalTransaction,")] + InvalidProposalForProposalTransaction = 0x1FE, + /// 511 - Invalid Signatory account address + #[error("Invalid Signatory account address")] + InvalidSignatoryAddress = 0x1FF, + /// 512 - Signatory already signed off + #[error("Signatory already signed off")] + SignatoryAlreadySignedOff = 0x200, + /// 513 - Signatory must sign + #[error("Signatory must sign")] + SignatoryMustSign = 0x201, + /// 514 - Invalid Proposal Owner + #[error("Invalid Proposal Owner")] + InvalidProposalOwnerAccount = 0x202, + /// 515 - Invalid Proposal for VoterRecord + #[error("Invalid Proposal for VoterRecord")] + InvalidProposalForVoterRecord = 0x203, + /// 516 - Invalid GoverningTokenOwner for VoteRecord + #[error("Invalid GoverningTokenOwner for VoteRecord")] + InvalidGoverningTokenOwnerForVoteRecord = 0x204, + /// 517 - Invalid Governance config: Vote threshold percentage out of range + #[error("Invalid Governance config: Vote threshold percentage out of range")] + InvalidVoteThresholdPercentage = 0x205, + /// 518 - Proposal for the given Governance, Governing Token Mint and index already exists + #[error("Proposal for the given Governance, Governing Token Mint and index already exists")] + ProposalAlreadyExists = 0x206, + /// 519 - Token Owner already voted on the Proposal + #[error("Token Owner already voted on the Proposal")] + VoteAlreadyExists = 0x207, + /// 520 - Owner doesn't have enough governing tokens to create Proposal + #[error("Owner doesn't have enough governing tokens to create Proposal")] + NotEnoughTokensToCreateProposal = 0x208, + /// 521 - Invalid State: Can't edit Signatories + #[error("Invalid State: Can't edit Signatories")] + InvalidStateCannotEditSignatories = 0x209, + /// 522 - Invalid Proposal state + #[error("Invalid Proposal state")] + InvalidProposalState = 0x20A, + /// 523 - Invalid State: Can't edit transactions + #[error("Invalid State: Can't edit transactions")] + InvalidStateCannotEditTransactions = 0x20B, + /// 524 - Invalid State: Can't execute transaction + #[error("Invalid State: Can't execute transaction")] + InvalidStateCannotExecuteTransaction = 0x20C, + /// 525 - Can't execute transaction within its hold up time + #[error("Can't execute transaction within its hold up time")] + CannotExecuteTransactionWithinHoldUpTime = 0x20D, + /// 526 - Transaction already executed + #[error("Transaction already executed")] + TransactionAlreadyExecuted = 0x20E, + /// 527 - Invalid Transaction index + #[error("Invalid Transaction index")] + InvalidTransactionIndex = 0x20F, + /// 528 - Transaction hold up time is below the min specified by Governance + #[error("Transaction hold up time is below the min specified by Governance")] + TransactionHoldUpTimeBelowRequiredMin = 0x210, + /// 529 - Transaction at the given index for the Proposal already exists + #[error("Transaction at the given index for the Proposal already exists")] + TransactionAlreadyExists = 0x211, + /// 530 - Invalid State: Can't sign off + #[error("Invalid State: Can't sign off")] + InvalidStateCannotSignOff = 0x212, + /// 531 - Invalid State: Can't vote + #[error("Invalid State: Can't vote")] + InvalidStateCannotVote = 0x213, + /// 532 - Invalid State: Can't finalize vote + #[error("Invalid State: Can't finalize vote")] + InvalidStateCannotFinalize = 0x214, + /// 533 - Invalid State: Can't cancel Proposal + #[error("Invalid State: Can't cancel Proposal")] + InvalidStateCannotCancelProposal = 0x215, + /// 534 - Vote already relinquished + #[error("Vote already relinquished")] + VoteAlreadyRelinquished = 0x216, + /// 535 - Can't finalize vote. Voting still in progress + #[error("Can't finalize vote. Voting still in progress")] + CannotFinalizeVotingInProgress = 0x217, + /// 536 - Proposal voting time expired + #[error("Proposal voting time expired")] + ProposalVotingTimeExpired = 0x218, + /// 537 - Invalid Signatory Mint + #[error("Invalid Signatory Mint")] + InvalidSignatoryMint = 0x219, + /// 538 - Proposal does not belong to the given Governance + #[error("Proposal does not belong to the given Governance")] + InvalidGovernanceForProposal = 0x21A, + /// 539 - Proposal does not belong to given Governing Mint + #[error("Proposal does not belong to given Governing Mint")] + InvalidGoverningMintForProposal = 0x21B, + /// 540 - Current mint authority must sign transaction + #[error("Current mint authority must sign transaction")] + MintAuthorityMustSign = 0x21C, + /// 541 - Invalid mint authority + #[error("Invalid mint authority")] + InvalidMintAuthority = 0x21D, + /// 542 - Mint has no authority + #[error("Mint has no authority")] + MintHasNoAuthority = 0x21E, + /// 543 - Invalid Token account owner + #[error("Invalid Token account owner")] + SplTokenAccountWithInvalidOwner = 0x21F, + /// 544 - Invalid Mint account owner + #[error("Invalid Mint account owner")] + SplTokenMintWithInvalidOwner = 0x220, + /// 545 - Token Account is not initialized + #[error("Token Account is not initialized")] + SplTokenAccountNotInitialized = 0x221, + /// 546 - Token Account doesn't exist + #[error("Token Account doesn't exist")] + SplTokenAccountDoesNotExist = 0x222, + /// 547 - Token account data is invalid + #[error("Token account data is invalid")] + SplTokenInvalidTokenAccountData = 0x223, + /// 548 - Token mint account data is invalid + #[error("Token mint account data is invalid")] + SplTokenInvalidMintAccountData = 0x224, + /// 549 - Token Mint account is not initialized + #[error("Token Mint account is not initialized")] + SplTokenMintNotInitialized = 0x225, + /// 550 - Token Mint account doesn't exist + #[error("Token Mint account doesn't exist")] + SplTokenMintDoesNotExist = 0x226, + /// 551 - Invalid ProgramData account address + #[error("Invalid ProgramData account address")] + InvalidProgramDataAccountAddress = 0x227, + /// 552 - Invalid ProgramData account Data + #[error("Invalid ProgramData account Data")] + InvalidProgramDataAccountData = 0x228, + /// 553 - Provided upgrade authority doesn't match current program upgrade authority + #[error("Provided upgrade authority doesn't match current program upgrade authority")] + InvalidUpgradeAuthority = 0x229, + /// 554 - Current program upgrade authority must sign transaction + #[error("Current program upgrade authority must sign transaction")] + UpgradeAuthorityMustSign = 0x22A, + /// 555 - Given program is not upgradable + #[error("Given program is not upgradable")] + ProgramNotUpgradable = 0x22B, + /// 556 - Invalid token owner + #[error("Invalid token owner")] + InvalidTokenOwner = 0x22C, + /// 557 - Current token owner must sign transaction + #[error("Current token owner must sign transaction")] + TokenOwnerMustSign = 0x22D, + /// 558 - Given VoteThresholdType is not supported + #[error("Given VoteThresholdType is not supported")] + VoteThresholdTypeNotSupported = 0x22E, + /// 559 - Given VoteWeightSource is not supported + #[error("Given VoteWeightSource is not supported")] + VoteWeightSourceNotSupported = 0x22F, + /// 560 - Legacy1 + #[error("Legacy1")] + Legacy1 = 0x230, + /// 561 - Governance PDA must sign + #[error("Governance PDA must sign")] + GovernancePdaMustSign = 0x231, + /// 562 - Transaction already flagged with error + #[error("Transaction already flagged with error")] + TransactionAlreadyFlaggedWithError = 0x232, + /// 563 - Invalid Realm for Governance + #[error("Invalid Realm for Governance")] + InvalidRealmForGovernance = 0x233, + /// 564 - Invalid Authority for Realm + #[error("Invalid Authority for Realm")] + InvalidAuthorityForRealm = 0x234, + /// 565 - Realm has no authority + #[error("Realm has no authority")] + RealmHasNoAuthority = 0x235, + /// 566 - Realm authority must sign + #[error("Realm authority must sign")] + RealmAuthorityMustSign = 0x236, + /// 567 - Invalid governing token holding account + #[error("Invalid governing token holding account")] + InvalidGoverningTokenHoldingAccount = 0x237, + /// 568 - Realm council mint change is not supported + #[error("Realm council mint change is not supported")] + RealmCouncilMintChangeIsNotSupported = 0x238, + /// 569 - Invalid max voter weight absolute value + #[error("Invalid max voter weight absolute value")] + InvalidMaxVoterWeightAbsoluteValue = 0x239, + /// 570 - Invalid max voter weight supply fraction + #[error("Invalid max voter weight supply fraction")] + InvalidMaxVoterWeightSupplyFraction = 0x23A, + /// 571 - Owner doesn't have enough governing tokens to create Governance + #[error("Owner doesn't have enough governing tokens to create Governance")] + NotEnoughTokensToCreateGovernance = 0x23B, + /// 572 - Too many outstanding proposals + #[error("Too many outstanding proposals")] + TooManyOutstandingProposals = 0x23C, + /// 573 - All proposals must be finalized to withdraw governing tokens + #[error("All proposals must be finalized to withdraw governing tokens")] + AllProposalsMustBeFinalisedToWithdrawGoverningTokens = 0x23D, + /// 574 - Invalid VoterWeightRecord for Realm + #[error("Invalid VoterWeightRecord for Realm")] + InvalidVoterWeightRecordForRealm = 0x23E, + /// 575 - Invalid VoterWeightRecord for GoverningTokenMint + #[error("Invalid VoterWeightRecord for GoverningTokenMint")] + InvalidVoterWeightRecordForGoverningTokenMint = 0x23F, + /// 576 - Invalid VoterWeightRecord for TokenOwner + #[error("Invalid VoterWeightRecord for TokenOwner")] + InvalidVoterWeightRecordForTokenOwner = 0x240, + /// 577 - VoterWeightRecord expired + #[error("VoterWeightRecord expired")] + VoterWeightRecordExpired = 0x241, + /// 578 - Invalid RealmConfig for Realm + #[error("Invalid RealmConfig for Realm")] + InvalidRealmConfigForRealm = 0x242, + /// 579 - TokenOwnerRecord already exists + #[error("TokenOwnerRecord already exists")] + TokenOwnerRecordAlreadyExists = 0x243, + /// 580 - Governing token deposits not allowed + #[error("Governing token deposits not allowed")] + GoverningTokenDepositsNotAllowed = 0x244, + /// 581 - Invalid vote choice weight percentage + #[error("Invalid vote choice weight percentage")] + InvalidVoteChoiceWeightPercentage = 0x245, + /// 582 - Vote type not supported + #[error("Vote type not supported")] + VoteTypeNotSupported = 0x246, + /// 583 - Invalid proposal options + #[error("Invalid proposal options")] + InvalidProposalOptions = 0x247, + /// 584 - Proposal is not not executable + #[error("Proposal is not not executable")] + ProposalIsNotExecutable = 0x248, + /// 585 - Deny vote is not allowed + #[error("Deny vote is not allowed")] + DenyVoteIsNotAllowed = 0x249, + /// 586 - Cannot execute defeated option + #[error("Cannot execute defeated option")] + CannotExecuteDefeatedOption = 0x24A, + /// 587 - VoterWeightRecord invalid action + #[error("VoterWeightRecord invalid action")] + VoterWeightRecordInvalidAction = 0x24B, + /// 588 - VoterWeightRecord invalid action target + #[error("VoterWeightRecord invalid action target")] + VoterWeightRecordInvalidActionTarget = 0x24C, + /// 589 - Invalid MaxVoterWeightRecord for Realm + #[error("Invalid MaxVoterWeightRecord for Realm")] + InvalidMaxVoterWeightRecordForRealm = 0x24D, + /// 590 - Invalid MaxVoterWeightRecord for GoverningTokenMint + #[error("Invalid MaxVoterWeightRecord for GoverningTokenMint")] + InvalidMaxVoterWeightRecordForGoverningTokenMint = 0x24E, + /// 591 - MaxVoterWeightRecord expired + #[error("MaxVoterWeightRecord expired")] + MaxVoterWeightRecordExpired = 0x24F, + /// 592 - Not supported VoteType + #[error("Not supported VoteType")] + NotSupportedVoteType = 0x250, + /// 593 - RealmConfig change not allowed + #[error("RealmConfig change not allowed")] + RealmConfigChangeNotAllowed = 0x251, + /// 594 - GovernanceConfig change not allowed + #[error("GovernanceConfig change not allowed")] + GovernanceConfigChangeNotAllowed = 0x252, + /// 595 - At least one VoteThreshold is required + #[error("At least one VoteThreshold is required")] + AtLeastOneVoteThresholdRequired = 0x253, + /// 596 - Reserved buffer must be empty + #[error("Reserved buffer must be empty")] + ReservedBufferMustBeEmpty = 0x254, + /// 597 - Cannot Relinquish in Finalizing state + #[error("Cannot Relinquish in Finalizing state")] + CannotRelinquishInFinalizingState = 0x255, + /// 598 - Invalid RealmConfig account address + #[error("Invalid RealmConfig account address")] + InvalidRealmConfigAddress = 0x256, + /// 599 - Cannot deposit dormant tokens + #[error("Cannot deposit dormant tokens")] + CannotDepositDormantTokens = 0x257, + /// 600 - Cannot withdraw membership tokens + #[error("Cannot withdraw membership tokens")] + CannotWithdrawMembershipTokens = 0x258, + /// 601 - Cannot revoke GoverningTokens + #[error("Cannot revoke GoverningTokens")] + CannotRevokeGoverningTokens = 0x259, + /// 602 - Invalid Revoke amount + #[error("Invalid Revoke amount")] + InvalidRevokeAmount = 0x25A, + /// 603 - Invalid GoverningToken source + #[error("Invalid GoverningToken source")] + InvalidGoverningTokenSource = 0x25B, + /// 604 - Cannot change community TokenType to Membership + #[error("Cannot change community TokenType to Membership")] + CannotChangeCommunityTokenTypeToMembership = 0x25C, + /// 605 - Voter weight threshold disabled + #[error("Voter weight threshold disabled")] + VoterWeightThresholdDisabled = 0x25D, + /// 606 - Vote not allowed in cool off time + #[error("Vote not allowed in cool off time")] + VoteNotAllowedInCoolOffTime = 0x25E, + /// 607 - Cannot refund ProposalDeposit + #[error("Cannot refund ProposalDeposit")] + CannotRefundProposalDeposit = 0x25F, + /// 608 - Invalid Proposal for ProposalDeposit + #[error("Invalid Proposal for ProposalDeposit")] + InvalidProposalForProposalDeposit = 0x260, + /// 609 - Invalid deposit_exempt_proposal_count + #[error("Invalid deposit_exempt_proposal_count")] + InvalidDepositExemptProposalCount = 0x261, + /// 610 - GoverningTokenMint not allowed to vote + #[error("GoverningTokenMint not allowed to vote")] + GoverningTokenMintNotAllowedToVote = 0x262, + /// 611 - Invalid deposit Payer for ProposalDeposit + #[error("Invalid deposit Payer for ProposalDeposit")] + InvalidDepositPayerForProposalDeposit = 0x263, + /// 612 - Invalid State: Proposal is not in final state + #[error("Invalid State: Proposal is not in final state")] + InvalidStateNotFinal = 0x264, + /// 613 - Invalid state for proposal state transition to Completed + #[error("Invalid state for proposal state transition to Completed")] + InvalidStateToCompleteProposal = 0x265, + /// 614 - Invalid number of vote choices + #[error("Invalid number of vote choices")] + InvalidNumberOfVoteChoices = 0x266, + /// 615 - Ranked vote is not supported + #[error("Ranked vote is not supported")] + RankedVoteIsNotSupported = 0x267, + /// 616 - Choice weight must be 100% + #[error("Choice weight must be 100%")] + ChoiceWeightMustBe100Percent = 0x268, + /// 617 - Single choice only is allowed + #[error("Single choice only is allowed")] + SingleChoiceOnlyIsAllowed = 0x269, + /// 618 - At least single choice is required + #[error("At least single choice is required")] + AtLeastSingleChoiceIsRequired = 0x26A, + /// 619 - Total vote weight must be 100% + #[error("Total vote weight must be 100%")] + TotalVoteWeightMustBe100Percent = 0x26B, + /// 620 - Invalid multi choice proposal parameters + #[error("Invalid multi choice proposal parameters")] + InvalidMultiChoiceProposalParameters = 0x26C, + /// 621 - Invalid Governance for RequiredSignatory + #[error("Invalid Governance for RequiredSignatory")] + InvalidGovernanceForRequiredSignatory = 0x26D, + /// 622 - Signatory Record has already been created + #[error("Signatory Record has already been created")] + SignatoryRecordAlreadyExists = 0x26E, + /// 623 - Instruction has been removed + #[error("Instruction has been removed")] + InstructionDeprecated = 0x26F, + /// 624 - Proposal is missing required signatories + #[error("Proposal is missing required signatories")] + MissingRequiredSignatories = 0x270, +} + +impl From for solana_program_error::ProgramError { + fn from(e: SplGovernanceError) -> Self { + solana_program_error::ProgramError::Custom(e as u32) + } +} diff --git a/e2e/governance/src/generated/instructions/add_required_signatory.rs b/e2e/governance/src/generated/instructions/add_required_signatory.rs new file mode 100644 index 0000000..fb0627a --- /dev/null +++ b/e2e/governance/src/generated/instructions/add_required_signatory.rs @@ -0,0 +1,395 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +pub const ADD_REQUIRED_SIGNATORY_DISCRIMINATOR: u8 = 29; + +/// Accounts. +#[derive(Debug)] +pub struct AddRequiredSignatory { + /// The Governance account the config is for + pub governance_account: solana_address::Address, + + pub required_signatory_account: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl AddRequiredSignatory { + pub fn instruction( + &self, + args: AddRequiredSignatoryInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: AddRequiredSignatoryInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.required_signatory_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = AddRequiredSignatoryInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct AddRequiredSignatoryInstructionData { + discriminator: u8, +} + +impl AddRequiredSignatoryInstructionData { + pub fn new() -> Self { + Self { discriminator: 29 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for AddRequiredSignatoryInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct AddRequiredSignatoryInstructionArgs { + pub signatory: Address, +} + +impl AddRequiredSignatoryInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `AddRequiredSignatory`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +/// 1. `[writable]` required_signatory_account +/// 2. `[signer]` payer +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct AddRequiredSignatoryBuilder { + governance_account: solana_address::Address, + required_signatory_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + signatory: Address, + __remaining_accounts: Vec, +} + +impl AddRequiredSignatoryBuilder { + pub fn new( + governance_account: solana_address::Address, + required_signatory_account: solana_address::Address, + payer: solana_address::Address, + signatory: Address, + ) -> Self { + Self { + governance_account, + required_signatory_account, + payer, + system_program: None, + signatory, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let required_signatory_account = self.required_signatory_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = AddRequiredSignatory { + governance_account, + required_signatory_account, + payer, + system_program, + }; + let args = AddRequiredSignatoryInstructionArgs { + signatory: self.signatory.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `add_required_signatory` CPI accounts. +pub struct AddRequiredSignatoryCpiAccounts<'a, 'b> { + /// The Governance account the config is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `add_required_signatory` CPI instruction. +pub struct AddRequiredSignatoryCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The Governance account the config is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: AddRequiredSignatoryInstructionArgs, +} + +impl<'a, 'b> AddRequiredSignatoryCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: AddRequiredSignatoryCpiAccounts<'a, 'b>, + args: AddRequiredSignatoryInstructionArgs, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + required_signatory_account: accounts.required_signatory_account, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.required_signatory_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = AddRequiredSignatoryInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.required_signatory_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `AddRequiredSignatory` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +/// 1. `[writable]` required_signatory_account +/// 2. `[signer]` payer +/// 3. `[]` system_program +#[derive(Clone, Debug)] +pub struct AddRequiredSignatoryCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> AddRequiredSignatoryCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + signatory: Address, + ) -> Self { + let instruction = Box::new(AddRequiredSignatoryCpiBuilderInstruction { + __program, + governance_account, + required_signatory_account, + payer, + system_program, + signatory, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = AddRequiredSignatoryInstructionArgs { + signatory: self.instruction.signatory.clone(), + }; + let instruction = AddRequiredSignatoryCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + required_signatory_account: self.instruction.required_signatory_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct AddRequiredSignatoryCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + signatory: Address, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/add_signatory.rs b/e2e/governance/src/generated/instructions/add_signatory.rs new file mode 100644 index 0000000..d1deb2e --- /dev/null +++ b/e2e/governance/src/generated/instructions/add_signatory.rs @@ -0,0 +1,445 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +pub const ADD_SIGNATORY_DISCRIMINATOR: u8 = 7; + +/// Accounts. +#[derive(Debug)] +pub struct AddSignatory { + /// Proposal Account associated with the governance + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + /// Signatory Record Account + pub signatory_record_account: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl AddSignatory { + pub fn instruction( + &self, + args: AddSignatoryInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: AddSignatoryInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.signatory_record_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = AddSignatoryInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct AddSignatoryInstructionData { + discriminator: u8, +} + +impl AddSignatoryInstructionData { + pub fn new() -> Self { + Self { discriminator: 7 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for AddSignatoryInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct AddSignatoryInstructionArgs { + pub signatory: Address, +} + +impl AddSignatoryInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `AddSignatory`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` signatory_record_account +/// 4. `[signer]` payer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct AddSignatoryBuilder { + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + signatory_record_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + signatory: Address, + __remaining_accounts: Vec, +} + +impl AddSignatoryBuilder { + pub fn new( + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + signatory_record_account: solana_address::Address, + payer: solana_address::Address, + signatory: Address, + ) -> Self { + Self { + proposal_account, + token_owner_record, + governance_authority, + signatory_record_account, + payer, + system_program: None, + signatory, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governance_authority = self.governance_authority; + let signatory_record_account = self.signatory_record_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = AddSignatory { + proposal_account, + token_owner_record, + governance_authority, + signatory_record_account, + payer, + system_program, + }; + let args = AddSignatoryInstructionArgs { + signatory: self.signatory.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `add_signatory` CPI accounts. +pub struct AddSignatoryCpiAccounts<'a, 'b> { + /// Proposal Account associated with the governance + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// Signatory Record Account + pub signatory_record_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `add_signatory` CPI instruction. +pub struct AddSignatoryCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Proposal Account associated with the governance + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// Signatory Record Account + pub signatory_record_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: AddSignatoryInstructionArgs, +} + +impl<'a, 'b> AddSignatoryCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: AddSignatoryCpiAccounts<'a, 'b>, + args: AddSignatoryInstructionArgs, + ) -> Self { + Self { + __program: program, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governance_authority: accounts.governance_authority, + signatory_record_account: accounts.signatory_record_account, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.signatory_record_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = AddSignatoryInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(7 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.signatory_record_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `AddSignatory` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` signatory_record_account +/// 4. `[signer]` payer +/// 5. `[]` system_program +#[derive(Clone, Debug)] +pub struct AddSignatoryCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> AddSignatoryCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + signatory_record_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + signatory: Address, + ) -> Self { + let instruction = Box::new(AddSignatoryCpiBuilderInstruction { + __program, + proposal_account, + token_owner_record, + governance_authority, + signatory_record_account, + payer, + system_program, + signatory, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = AddSignatoryInstructionArgs { + signatory: self.instruction.signatory.clone(), + }; + let instruction = AddSignatoryCpi { + __program: self.instruction.__program, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governance_authority: self.instruction.governance_authority, + signatory_record_account: self.instruction.signatory_record_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct AddSignatoryCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + signatory_record_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + signatory: Address, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/cancel_proposal.rs b/e2e/governance/src/generated/instructions/cancel_proposal.rs new file mode 100644 index 0000000..a027923 --- /dev/null +++ b/e2e/governance/src/generated/instructions/cancel_proposal.rs @@ -0,0 +1,373 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CANCEL_PROPOSAL_DISCRIMINATOR: u8 = 11; + +/// Accounts. +#[derive(Debug)] +pub struct CancelProposal { + pub realm_account: solana_address::Address, + + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Governance authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, +} + +impl CancelProposal { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CancelProposalInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CancelProposalInstructionData { + discriminator: u8, +} + +impl CancelProposalInstructionData { + pub fn new() -> Self { + Self { discriminator: 11 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CancelProposalInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CancelProposal`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[signer]` governance_authority +#[derive(Clone, Debug)] +pub struct CancelProposalBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + __remaining_accounts: Vec, +} + +impl CancelProposalBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + ) -> Self { + Self { + realm_account, + governance_account, + proposal_account, + token_owner_record, + governance_authority, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governance_authority = self.governance_authority; + let accounts = CancelProposal { + realm_account, + governance_account, + proposal_account, + token_owner_record, + governance_authority, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `cancel_proposal` CPI accounts. +pub struct CancelProposalCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, +} + +/// `cancel_proposal` CPI instruction. +pub struct CancelProposalCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CancelProposalCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CancelProposalCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governance_authority: accounts.governance_authority, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = CancelProposalInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CancelProposal` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[signer]` governance_authority +#[derive(Clone, Debug)] +pub struct CancelProposalCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CancelProposalCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CancelProposalCpiBuilderInstruction { + __program, + realm_account, + governance_account, + proposal_account, + token_owner_record, + governance_authority, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = CancelProposalCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governance_authority: self.instruction.governance_authority, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CancelProposalCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/cast_vote.rs b/e2e/governance/src/generated/instructions/cast_vote.rs new file mode 100644 index 0000000..b7def36 --- /dev/null +++ b/e2e/governance/src/generated/instructions/cast_vote.rs @@ -0,0 +1,709 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::Vote; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CAST_VOTE_DISCRIMINATOR: u8 = 13; + +/// Accounts. +#[derive(Debug)] +pub struct CastVote { + pub realm_account: solana_address::Address, + + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord of the Proposal owner + pub proposal_token_owner_record: solana_address::Address, + /// TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub voter_token_owner_record: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record] + pub proposal_vote_record: solana_address::Address, + /// The Governing Token Mint which is used to cast the vote (vote_governing_token_mint). + /// The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes. + /// For Veto vote the voting token mint is the mint of the opposite voting population. + /// Council mint to veto Community proposals and Community mint to veto Council proposals + /// Note: In the current version only Council veto is supported + pub governing_token_mint: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config_account: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option, +} + +impl CastVote { + pub fn instruction(&self, args: CastVoteInstructionArgs) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CastVoteInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(13 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.voter_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_vote_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config_account, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CastVoteInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CastVoteInstructionData { + discriminator: u8, +} + +impl CastVoteInstructionData { + pub fn new() -> Self { + Self { discriminator: 13 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CastVoteInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CastVoteInstructionArgs { + pub vote: Vote, +} + +impl CastVoteInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CastVote`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` proposal_token_owner_record +/// 4. `[writable]` voter_token_owner_record +/// 5. `[signer]` governance_authority +/// 6. `[writable]` proposal_vote_record +/// 7. `[]` governing_token_mint +/// 8. `[signer]` payer +/// 9. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 10. `[]` realm_config_account +/// 11. `[optional]` voter_weight_record +/// 12. `[optional]` max_voter_weight_record +#[derive(Clone, Debug)] +pub struct CastVoteBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + proposal_token_owner_record: solana_address::Address, + voter_token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_vote_record: solana_address::Address, + governing_token_mint: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + realm_config_account: solana_address::Address, + voter_weight_record: Option, + max_voter_weight_record: Option, + vote: Vote, + __remaining_accounts: Vec, +} + +impl CastVoteBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + proposal_token_owner_record: solana_address::Address, + voter_token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_vote_record: solana_address::Address, + governing_token_mint: solana_address::Address, + payer: solana_address::Address, + realm_config_account: solana_address::Address, + vote: Vote, + ) -> Self { + Self { + realm_account, + governance_account, + proposal_account, + proposal_token_owner_record, + voter_token_owner_record, + governance_authority, + proposal_vote_record, + governing_token_mint, + payer, + system_program: None, + realm_config_account, + voter_weight_record: None, + max_voter_weight_record: None, + vote, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// `[optional account]` + /// Optional Max Voter Weight Record + #[inline(always)] + pub fn max_voter_weight_record( + &mut self, + max_voter_weight_record: Option, + ) -> &mut Self { + self.max_voter_weight_record = max_voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let proposal_token_owner_record = self.proposal_token_owner_record; + let voter_token_owner_record = self.voter_token_owner_record; + let governance_authority = self.governance_authority; + let proposal_vote_record = self.proposal_vote_record; + let governing_token_mint = self.governing_token_mint; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let realm_config_account = self.realm_config_account; + let voter_weight_record = self.voter_weight_record; + let max_voter_weight_record = self.max_voter_weight_record; + let accounts = CastVote { + realm_account, + governance_account, + proposal_account, + proposal_token_owner_record, + voter_token_owner_record, + governance_authority, + proposal_vote_record, + governing_token_mint, + payer, + system_program, + realm_config_account, + voter_weight_record, + max_voter_weight_record, + }; + let args = CastVoteInstructionArgs { + vote: self.vote.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `cast_vote` CPI accounts. +pub struct CastVoteCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the Proposal owner + pub proposal_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub voter_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record] + pub proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + /// The Governing Token Mint which is used to cast the vote (vote_governing_token_mint). + /// The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes. + /// For Veto vote the voting token mint is the mint of the opposite voting population. + /// Council mint to veto Community proposals and Community mint to veto Council proposals + /// Note: In the current version only Council veto is supported + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `cast_vote` CPI instruction. +pub struct CastVoteCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the Proposal owner + pub proposal_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the voter. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub voter_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal,token_owner_record] + pub proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + /// The Governing Token Mint which is used to cast the vote (vote_governing_token_mint). + /// The voting token mint is the governing_token_mint of the Proposal for Approve, Deny and Abstain votes. + /// For Veto vote the voting token mint is the mint of the opposite voting population. + /// Council mint to veto Community proposals and Community mint to veto Council proposals + /// Note: In the current version only Council veto is supported + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CastVoteInstructionArgs, +} + +impl<'a, 'b> CastVoteCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CastVoteCpiAccounts<'a, 'b>, + args: CastVoteInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + proposal_token_owner_record: accounts.proposal_token_owner_record, + voter_token_owner_record: accounts.voter_token_owner_record, + governance_authority: accounts.governance_authority, + proposal_vote_record: accounts.proposal_vote_record, + governing_token_mint: accounts.governing_token_mint, + payer: accounts.payer, + system_program: accounts.system_program, + realm_config_account: accounts.realm_config_account, + voter_weight_record: accounts.voter_weight_record, + max_voter_weight_record: accounts.max_voter_weight_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(13 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.voter_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_vote_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config_account.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CastVoteInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(14 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.proposal_token_owner_record.clone()); + account_infos.push(self.voter_token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.proposal_vote_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.realm_config_account.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + account_infos.push(max_voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CastVote` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` proposal_token_owner_record +/// 4. `[writable]` voter_token_owner_record +/// 5. `[signer]` governance_authority +/// 6. `[writable]` proposal_vote_record +/// 7. `[]` governing_token_mint +/// 8. `[signer]` payer +/// 9. `[]` system_program +/// 10. `[]` realm_config_account +/// 11. `[optional]` voter_weight_record +/// 12. `[optional]` max_voter_weight_record +#[derive(Clone, Debug)] +pub struct CastVoteCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CastVoteCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + voter_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + vote: Vote, + ) -> Self { + let instruction = Box::new(CastVoteCpiBuilderInstruction { + __program, + realm_account, + governance_account, + proposal_account, + proposal_token_owner_record, + voter_token_owner_record, + governance_authority, + proposal_vote_record, + governing_token_mint, + payer, + system_program, + realm_config_account, + voter_weight_record: None, + max_voter_weight_record: None, + vote, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// `[optional account]` + /// Optional Max Voter Weight Record + #[inline(always)] + pub fn max_voter_weight_record( + &mut self, + max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.max_voter_weight_record = max_voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CastVoteInstructionArgs { + vote: self.instruction.vote.clone(), + }; + let instruction = CastVoteCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + proposal_token_owner_record: self.instruction.proposal_token_owner_record, + voter_token_owner_record: self.instruction.voter_token_owner_record, + governance_authority: self.instruction.governance_authority, + proposal_vote_record: self.instruction.proposal_vote_record, + governing_token_mint: self.instruction.governing_token_mint, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + realm_config_account: self.instruction.realm_config_account, + voter_weight_record: self.instruction.voter_weight_record, + max_voter_weight_record: self.instruction.max_voter_weight_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CastVoteCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + voter_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + vote: Vote, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/complete_proposal.rs b/e2e/governance/src/generated/instructions/complete_proposal.rs new file mode 100644 index 0000000..d731fe2 --- /dev/null +++ b/e2e/governance/src/generated/instructions/complete_proposal.rs @@ -0,0 +1,319 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const COMPLETE_PROPOSAL_DISCRIMINATOR: u8 = 28; + +/// Accounts. +#[derive(Debug)] +pub struct CompleteProposal { + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Token Owner or Delegate + pub complete_proposal_authority: solana_address::Address, +} + +impl CompleteProposal { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.complete_proposal_authority, + true, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CompleteProposalInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CompleteProposalInstructionData { + discriminator: u8, +} + +impl CompleteProposalInstructionData { + pub fn new() -> Self { + Self { discriminator: 28 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CompleteProposalInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CompleteProposal`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` complete_proposal_authority +#[derive(Clone, Debug)] +pub struct CompleteProposalBuilder { + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + complete_proposal_authority: solana_address::Address, + __remaining_accounts: Vec, +} + +impl CompleteProposalBuilder { + pub fn new( + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + complete_proposal_authority: solana_address::Address, + ) -> Self { + Self { + proposal_account, + token_owner_record, + complete_proposal_authority, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let complete_proposal_authority = self.complete_proposal_authority; + let accounts = CompleteProposal { + proposal_account, + token_owner_record, + complete_proposal_authority, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `complete_proposal` CPI accounts. +pub struct CompleteProposalCpiAccounts<'a, 'b> { + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Token Owner or Delegate + pub complete_proposal_authority: &'b solana_account_info::AccountInfo<'a>, +} + +/// `complete_proposal` CPI instruction. +pub struct CompleteProposalCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Token Owner or Delegate + pub complete_proposal_authority: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CompleteProposalCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CompleteProposalCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + complete_proposal_authority: accounts.complete_proposal_authority, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.complete_proposal_authority.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = CompleteProposalInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.complete_proposal_authority.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CompleteProposal` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` complete_proposal_authority +#[derive(Clone, Debug)] +pub struct CompleteProposalCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CompleteProposalCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + complete_proposal_authority: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CompleteProposalCpiBuilderInstruction { + __program, + proposal_account, + token_owner_record, + complete_proposal_authority, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = CompleteProposalCpi { + __program: self.instruction.__program, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + complete_proposal_authority: self.instruction.complete_proposal_authority, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CompleteProposalCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + complete_proposal_authority: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_governance.rs b/e2e/governance/src/generated/instructions/create_governance.rs new file mode 100644 index 0000000..4a97a49 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_governance.rs @@ -0,0 +1,563 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_GOVERNANCE_DISCRIMINATOR: u8 = 4; + +/// Accounts. +#[derive(Debug)] +pub struct CreateGovernance { + /// Realm account the created governance belongs to + pub realm_account: solana_address::Address, + /// seeds=['account-governance', realm, governed_account] + pub governance_account: solana_address::Address, + /// Account governed by this Governance (governing_account). + /// Note: the account doesn't have to exist and can be used only as a unique identified for the Governance account + pub governed_account: solana_address::Address, + /// Used only if not signed by RealmAuthority + pub governing_token_owner_record: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, + + pub governance_authority: solana_address::Address, + /// seeds=['realm-config', realm] + pub realm_config_account: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, +} + +impl CreateGovernance { + pub fn instruction( + &self, + args: CreateGovernanceInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateGovernanceInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governed_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config_account, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateGovernanceInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateGovernanceInstructionData { + discriminator: u8, +} + +impl CreateGovernanceInstructionData { + pub fn new() -> Self { + Self { discriminator: 4 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateGovernanceInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateGovernanceInstructionArgs { + pub config: GovernanceConfig, +} + +impl CreateGovernanceInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateGovernance`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[]` governed_account +/// 3. `[]` governing_token_owner_record +/// 4. `[signer]` payer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 6. `[signer]` governance_authority +/// 7. `[]` realm_config_account +/// 8. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateGovernanceBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + governed_account: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + governance_authority: solana_address::Address, + realm_config_account: solana_address::Address, + voter_weight_record: Option, + config: GovernanceConfig, + __remaining_accounts: Vec, +} + +impl CreateGovernanceBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + governed_account: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + governance_authority: solana_address::Address, + realm_config_account: solana_address::Address, + config: GovernanceConfig, + ) -> Self { + Self { + realm_account, + governance_account, + governed_account, + governing_token_owner_record, + payer, + system_program: None, + governance_authority, + realm_config_account, + voter_weight_record: None, + config, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let governed_account = self.governed_account; + let governing_token_owner_record = self.governing_token_owner_record; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let governance_authority = self.governance_authority; + let realm_config_account = self.realm_config_account; + let voter_weight_record = self.voter_weight_record; + let accounts = CreateGovernance { + realm_account, + governance_account, + governed_account, + governing_token_owner_record, + payer, + system_program, + governance_authority, + realm_config_account, + voter_weight_record, + }; + let args = CreateGovernanceInstructionArgs { + config: self.config.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_governance` CPI accounts. +pub struct CreateGovernanceCpiAccounts<'a, 'b> { + /// Realm account the created governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['account-governance', realm, governed_account] + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Account governed by this Governance (governing_account). + /// Note: the account doesn't have to exist and can be used only as a unique identified for the Governance account + pub governed_account: &'b solana_account_info::AccountInfo<'a>, + /// Used only if not signed by RealmAuthority + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_governance` CPI instruction. +pub struct CreateGovernanceCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Realm account the created governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['account-governance', realm, governed_account] + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Account governed by this Governance (governing_account). + /// Note: the account doesn't have to exist and can be used only as a unique identified for the Governance account + pub governed_account: &'b solana_account_info::AccountInfo<'a>, + /// Used only if not signed by RealmAuthority + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateGovernanceInstructionArgs, +} + +impl<'a, 'b> CreateGovernanceCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateGovernanceCpiAccounts<'a, 'b>, + args: CreateGovernanceInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + governed_account: accounts.governed_account, + governing_token_owner_record: accounts.governing_token_owner_record, + payer: accounts.payer, + system_program: accounts.system_program, + governance_authority: accounts.governance_authority, + realm_config_account: accounts.realm_config_account, + voter_weight_record: accounts.voter_weight_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governed_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config_account.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateGovernanceInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(10 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.governed_account.clone()); + account_infos.push(self.governing_token_owner_record.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.realm_config_account.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateGovernance` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[]` governed_account +/// 3. `[]` governing_token_owner_record +/// 4. `[signer]` payer +/// 5. `[]` system_program +/// 6. `[signer]` governance_authority +/// 7. `[]` realm_config_account +/// 8. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateGovernanceCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateGovernanceCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + ) -> Self { + let instruction = Box::new(CreateGovernanceCpiBuilderInstruction { + __program, + realm_account, + governance_account, + governed_account, + governing_token_owner_record, + payer, + system_program, + governance_authority, + realm_config_account, + voter_weight_record: None, + config, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateGovernanceInstructionArgs { + config: self.instruction.config.clone(), + }; + let instruction = CreateGovernanceCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + governed_account: self.instruction.governed_account, + governing_token_owner_record: self.instruction.governing_token_owner_record, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + governance_authority: self.instruction.governance_authority, + realm_config_account: self.instruction.realm_config_account, + voter_weight_record: self.instruction.voter_weight_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateGovernanceCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + config: GovernanceConfig, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_mint_governance.rs b/e2e/governance/src/generated/instructions/create_mint_governance.rs new file mode 100644 index 0000000..a4c3ed1 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_mint_governance.rs @@ -0,0 +1,634 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_MINT_GOVERNANCE_DISCRIMINATOR: u8 = 17; + +/// Accounts. +#[derive(Debug)] +pub struct CreateMintGovernance { + /// Realm account the created Governance belongs to + pub realm_account: solana_address::Address, + /// Mint Governance account. seeds=['mint-governance', realm, governed_mint] + pub mint_governance_account: solana_address::Address, + /// Mint governed by this Governance account + pub governed_mint: solana_address::Address, + /// Current Mint authority (MintTokens and optionally FreezeAccount) + pub mint_authority: solana_address::Address, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: solana_address::Address, + + pub payer: solana_address::Address, + + pub token_program: solana_address::Address, + + pub system_program: solana_address::Address, + + pub governance_authority: solana_address::Address, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, +} + +impl CreateMintGovernance { + pub fn instruction( + &self, + args: CreateMintGovernanceInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateMintGovernanceInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.mint_governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governed_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.mint_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateMintGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateMintGovernanceInstructionData { + discriminator: u8, +} + +impl CreateMintGovernanceInstructionData { + pub fn new() -> Self { + Self { discriminator: 17 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateMintGovernanceInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateMintGovernanceInstructionArgs { + pub config: GovernanceConfig, + pub transfer_mint_authorities: bool, +} + +impl CreateMintGovernanceInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateMintGovernance`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` mint_governance_account +/// 2. `[writable]` governed_mint +/// 3. `[signer]` mint_authority +/// 4. `[]` governing_token_owner_record +/// 5. `[signer]` payer +/// 6. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 8. `[signer]` governance_authority +/// 9. `[]` realm_config +/// 10. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateMintGovernanceBuilder { + realm_account: solana_address::Address, + mint_governance_account: solana_address::Address, + governed_mint: solana_address::Address, + mint_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + token_program: Option, + system_program: Option, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + voter_weight_record: Option, + config: GovernanceConfig, + transfer_mint_authorities: bool, + __remaining_accounts: Vec, +} + +impl CreateMintGovernanceBuilder { + pub fn new( + realm_account: solana_address::Address, + mint_governance_account: solana_address::Address, + governed_mint: solana_address::Address, + mint_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + config: GovernanceConfig, + transfer_mint_authorities: bool, + ) -> Self { + Self { + realm_account, + mint_governance_account, + governed_mint, + mint_authority, + governing_token_owner_record, + payer, + token_program: None, + system_program: None, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_mint_authorities, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let mint_governance_account = self.mint_governance_account; + let governed_mint = self.governed_mint; + let mint_authority = self.mint_authority; + let governing_token_owner_record = self.governing_token_owner_record; + let payer = self.payer; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let governance_authority = self.governance_authority; + let realm_config = self.realm_config; + let voter_weight_record = self.voter_weight_record; + let accounts = CreateMintGovernance { + realm_account, + mint_governance_account, + governed_mint, + mint_authority, + governing_token_owner_record, + payer, + token_program, + system_program, + governance_authority, + realm_config, + voter_weight_record, + }; + let args = CreateMintGovernanceInstructionArgs { + config: self.config.clone(), + transfer_mint_authorities: self.transfer_mint_authorities.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_mint_governance` CPI accounts. +pub struct CreateMintGovernanceCpiAccounts<'a, 'b> { + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Mint Governance account. seeds=['mint-governance', realm, governed_mint] + pub mint_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Mint governed by this Governance account + pub governed_mint: &'b solana_account_info::AccountInfo<'a>, + /// Current Mint authority (MintTokens and optionally FreezeAccount) + pub mint_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_mint_governance` CPI instruction. +pub struct CreateMintGovernanceCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Mint Governance account. seeds=['mint-governance', realm, governed_mint] + pub mint_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Mint governed by this Governance account + pub governed_mint: &'b solana_account_info::AccountInfo<'a>, + /// Current Mint authority (MintTokens and optionally FreezeAccount) + pub mint_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateMintGovernanceInstructionArgs, +} + +impl<'a, 'b> CreateMintGovernanceCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateMintGovernanceCpiAccounts<'a, 'b>, + args: CreateMintGovernanceInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + mint_governance_account: accounts.mint_governance_account, + governed_mint: accounts.governed_mint, + mint_authority: accounts.mint_authority, + governing_token_owner_record: accounts.governing_token_owner_record, + payer: accounts.payer, + token_program: accounts.token_program, + system_program: accounts.system_program, + governance_authority: accounts.governance_authority, + realm_config: accounts.realm_config, + voter_weight_record: accounts.voter_weight_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.mint_governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governed_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.mint_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateMintGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(12 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.mint_governance_account.clone()); + account_infos.push(self.governed_mint.clone()); + account_infos.push(self.mint_authority.clone()); + account_infos.push(self.governing_token_owner_record.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateMintGovernance` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` mint_governance_account +/// 2. `[writable]` governed_mint +/// 3. `[signer]` mint_authority +/// 4. `[]` governing_token_owner_record +/// 5. `[signer]` payer +/// 6. `[]` token_program +/// 7. `[]` system_program +/// 8. `[signer]` governance_authority +/// 9. `[]` realm_config +/// 10. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateMintGovernanceCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateMintGovernanceCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + mint_governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_mint: &'b solana_account_info::AccountInfo<'a>, + mint_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + transfer_mint_authorities: bool, + ) -> Self { + let instruction = Box::new(CreateMintGovernanceCpiBuilderInstruction { + __program, + realm_account, + mint_governance_account, + governed_mint, + mint_authority, + governing_token_owner_record, + payer, + token_program, + system_program, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_mint_authorities, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateMintGovernanceInstructionArgs { + config: self.instruction.config.clone(), + transfer_mint_authorities: self.instruction.transfer_mint_authorities.clone(), + }; + let instruction = CreateMintGovernanceCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + mint_governance_account: self.instruction.mint_governance_account, + governed_mint: self.instruction.governed_mint, + mint_authority: self.instruction.mint_authority, + governing_token_owner_record: self.instruction.governing_token_owner_record, + payer: self.instruction.payer, + token_program: self.instruction.token_program, + system_program: self.instruction.system_program, + governance_authority: self.instruction.governance_authority, + realm_config: self.instruction.realm_config, + voter_weight_record: self.instruction.voter_weight_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateMintGovernanceCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + mint_governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_mint: &'b solana_account_info::AccountInfo<'a>, + mint_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + config: GovernanceConfig, + transfer_mint_authorities: bool, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_native_treasury.rs b/e2e/governance/src/generated/instructions/create_native_treasury.rs new file mode 100644 index 0000000..58f6940 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_native_treasury.rs @@ -0,0 +1,358 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_NATIVE_TREASURY_DISCRIMINATOR: u8 = 25; + +/// Accounts. +#[derive(Debug)] +pub struct CreateNativeTreasury { + /// Governance account the treasury account is for + pub governance_account: solana_address::Address, + /// seeds=['native-treasury', governance] + pub native_treasury_account: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl CreateNativeTreasury { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.native_treasury_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CreateNativeTreasuryInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateNativeTreasuryInstructionData { + discriminator: u8, +} + +impl CreateNativeTreasuryInstructionData { + pub fn new() -> Self { + Self { discriminator: 25 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateNativeTreasuryInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CreateNativeTreasury`. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` native_treasury_account +/// 2. `[signer]` payer +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreateNativeTreasuryBuilder { + governance_account: solana_address::Address, + native_treasury_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + __remaining_accounts: Vec, +} + +impl CreateNativeTreasuryBuilder { + pub fn new( + governance_account: solana_address::Address, + native_treasury_account: solana_address::Address, + payer: solana_address::Address, + ) -> Self { + Self { + governance_account, + native_treasury_account, + payer, + system_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let native_treasury_account = self.native_treasury_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreateNativeTreasury { + governance_account, + native_treasury_account, + payer, + system_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `create_native_treasury` CPI accounts. +pub struct CreateNativeTreasuryCpiAccounts<'a, 'b> { + /// Governance account the treasury account is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['native-treasury', governance] + pub native_treasury_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_native_treasury` CPI instruction. +pub struct CreateNativeTreasuryCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Governance account the treasury account is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['native-treasury', governance] + pub native_treasury_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CreateNativeTreasuryCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateNativeTreasuryCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + native_treasury_account: accounts.native_treasury_account, + payer: accounts.payer, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.native_treasury_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = CreateNativeTreasuryInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.native_treasury_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateNativeTreasury` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` native_treasury_account +/// 2. `[signer]` payer +/// 3. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreateNativeTreasuryCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateNativeTreasuryCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + native_treasury_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CreateNativeTreasuryCpiBuilderInstruction { + __program, + governance_account, + native_treasury_account, + payer, + system_program, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = CreateNativeTreasuryCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + native_treasury_account: self.instruction.native_treasury_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateNativeTreasuryCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + native_treasury_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_program_governance.rs b/e2e/governance/src/generated/instructions/create_program_governance.rs new file mode 100644 index 0000000..7a73cc0 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_program_governance.rs @@ -0,0 +1,654 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_PROGRAM_GOVERNANCE_DISCRIMINATOR: u8 = 5; + +/// Accounts. +#[derive(Debug)] +pub struct CreateProgramGovernance { + /// Realm account the created Governance belongs to + pub realm_account: solana_address::Address, + /// Program Governance account. seeds: ['program-governance', realm, governed_program] + pub program_governance_account: solana_address::Address, + /// Program governed by this Governance account + pub governed_program: solana_address::Address, + /// Program Data account of the Program governed by this Governance account + pub program_data: solana_address::Address, + /// Current Upgrade Authority account of the Program governed by this Governance account + pub current_upgrade_authority: solana_address::Address, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: solana_address::Address, + + pub payer: solana_address::Address, + /// bpf_upgradeable_loader_program program + pub bpf_upgradeable_loader_program: solana_address::Address, + + pub system_program: solana_address::Address, + + pub governance_authority: solana_address::Address, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, +} + +impl CreateProgramGovernance { + pub fn instruction( + &self, + args: CreateProgramGovernanceInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateProgramGovernanceInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(12 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.program_governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governed_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.program_data, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.current_upgrade_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.bpf_upgradeable_loader_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateProgramGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateProgramGovernanceInstructionData { + discriminator: u8, +} + +impl CreateProgramGovernanceInstructionData { + pub fn new() -> Self { + Self { discriminator: 5 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateProgramGovernanceInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateProgramGovernanceInstructionArgs { + pub config: GovernanceConfig, + pub transfer_upgrade_authority: bool, +} + +impl CreateProgramGovernanceInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateProgramGovernance`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` program_governance_account +/// 2. `[]` governed_program +/// 3. `[writable]` program_data +/// 4. `[signer]` current_upgrade_authority +/// 5. `[]` governing_token_owner_record +/// 6. `[signer]` payer +/// 7. `[]` bpf_upgradeable_loader_program +/// 8. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 9. `[signer]` governance_authority +/// 10. `[]` realm_config +/// 11. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateProgramGovernanceBuilder { + realm_account: solana_address::Address, + program_governance_account: solana_address::Address, + governed_program: solana_address::Address, + program_data: solana_address::Address, + current_upgrade_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + bpf_upgradeable_loader_program: solana_address::Address, + system_program: Option, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + voter_weight_record: Option, + config: GovernanceConfig, + transfer_upgrade_authority: bool, + __remaining_accounts: Vec, +} + +impl CreateProgramGovernanceBuilder { + pub fn new( + realm_account: solana_address::Address, + program_governance_account: solana_address::Address, + governed_program: solana_address::Address, + program_data: solana_address::Address, + current_upgrade_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + bpf_upgradeable_loader_program: solana_address::Address, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + config: GovernanceConfig, + transfer_upgrade_authority: bool, + ) -> Self { + Self { + realm_account, + program_governance_account, + governed_program, + program_data, + current_upgrade_authority, + governing_token_owner_record, + payer, + bpf_upgradeable_loader_program, + system_program: None, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_upgrade_authority, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let program_governance_account = self.program_governance_account; + let governed_program = self.governed_program; + let program_data = self.program_data; + let current_upgrade_authority = self.current_upgrade_authority; + let governing_token_owner_record = self.governing_token_owner_record; + let payer = self.payer; + let bpf_upgradeable_loader_program = self.bpf_upgradeable_loader_program; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let governance_authority = self.governance_authority; + let realm_config = self.realm_config; + let voter_weight_record = self.voter_weight_record; + let accounts = CreateProgramGovernance { + realm_account, + program_governance_account, + governed_program, + program_data, + current_upgrade_authority, + governing_token_owner_record, + payer, + bpf_upgradeable_loader_program, + system_program, + governance_authority, + realm_config, + voter_weight_record, + }; + let args = CreateProgramGovernanceInstructionArgs { + config: self.config.clone(), + transfer_upgrade_authority: self.transfer_upgrade_authority.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_program_governance` CPI accounts. +pub struct CreateProgramGovernanceCpiAccounts<'a, 'b> { + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Program Governance account. seeds: ['program-governance', realm, governed_program] + pub program_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Program governed by this Governance account + pub governed_program: &'b solana_account_info::AccountInfo<'a>, + /// Program Data account of the Program governed by this Governance account + pub program_data: &'b solana_account_info::AccountInfo<'a>, + /// Current Upgrade Authority account of the Program governed by this Governance account + pub current_upgrade_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// bpf_upgradeable_loader_program program + pub bpf_upgradeable_loader_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_program_governance` CPI instruction. +pub struct CreateProgramGovernanceCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Program Governance account. seeds: ['program-governance', realm, governed_program] + pub program_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Program governed by this Governance account + pub governed_program: &'b solana_account_info::AccountInfo<'a>, + /// Program Data account of the Program governed by this Governance account + pub program_data: &'b solana_account_info::AccountInfo<'a>, + /// Current Upgrade Authority account of the Program governed by this Governance account + pub current_upgrade_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority) + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// bpf_upgradeable_loader_program program + pub bpf_upgradeable_loader_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateProgramGovernanceInstructionArgs, +} + +impl<'a, 'b> CreateProgramGovernanceCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateProgramGovernanceCpiAccounts<'a, 'b>, + args: CreateProgramGovernanceInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + program_governance_account: accounts.program_governance_account, + governed_program: accounts.governed_program, + program_data: accounts.program_data, + current_upgrade_authority: accounts.current_upgrade_authority, + governing_token_owner_record: accounts.governing_token_owner_record, + payer: accounts.payer, + bpf_upgradeable_loader_program: accounts.bpf_upgradeable_loader_program, + system_program: accounts.system_program, + governance_authority: accounts.governance_authority, + realm_config: accounts.realm_config, + voter_weight_record: accounts.voter_weight_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(12 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.program_governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governed_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.program_data.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.current_upgrade_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.bpf_upgradeable_loader_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateProgramGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(13 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.program_governance_account.clone()); + account_infos.push(self.governed_program.clone()); + account_infos.push(self.program_data.clone()); + account_infos.push(self.current_upgrade_authority.clone()); + account_infos.push(self.governing_token_owner_record.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.bpf_upgradeable_loader_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateProgramGovernance` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` program_governance_account +/// 2. `[]` governed_program +/// 3. `[writable]` program_data +/// 4. `[signer]` current_upgrade_authority +/// 5. `[]` governing_token_owner_record +/// 6. `[signer]` payer +/// 7. `[]` bpf_upgradeable_loader_program +/// 8. `[]` system_program +/// 9. `[signer]` governance_authority +/// 10. `[]` realm_config +/// 11. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateProgramGovernanceCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateProgramGovernanceCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + program_governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_program: &'b solana_account_info::AccountInfo<'a>, + program_data: &'b solana_account_info::AccountInfo<'a>, + current_upgrade_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + bpf_upgradeable_loader_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + transfer_upgrade_authority: bool, + ) -> Self { + let instruction = Box::new(CreateProgramGovernanceCpiBuilderInstruction { + __program, + realm_account, + program_governance_account, + governed_program, + program_data, + current_upgrade_authority, + governing_token_owner_record, + payer, + bpf_upgradeable_loader_program, + system_program, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_upgrade_authority, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateProgramGovernanceInstructionArgs { + config: self.instruction.config.clone(), + transfer_upgrade_authority: self.instruction.transfer_upgrade_authority.clone(), + }; + let instruction = CreateProgramGovernanceCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + program_governance_account: self.instruction.program_governance_account, + governed_program: self.instruction.governed_program, + program_data: self.instruction.program_data, + current_upgrade_authority: self.instruction.current_upgrade_authority, + governing_token_owner_record: self.instruction.governing_token_owner_record, + payer: self.instruction.payer, + bpf_upgradeable_loader_program: self.instruction.bpf_upgradeable_loader_program, + system_program: self.instruction.system_program, + governance_authority: self.instruction.governance_authority, + realm_config: self.instruction.realm_config, + voter_weight_record: self.instruction.voter_weight_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateProgramGovernanceCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + program_governance_account: &'b solana_account_info::AccountInfo<'a>, + governed_program: &'b solana_account_info::AccountInfo<'a>, + program_data: &'b solana_account_info::AccountInfo<'a>, + current_upgrade_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + bpf_upgradeable_loader_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + config: GovernanceConfig, + transfer_upgrade_authority: bool, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_proposal.rs b/e2e/governance/src/generated/instructions/create_proposal.rs new file mode 100644 index 0000000..d79f42c --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_proposal.rs @@ -0,0 +1,704 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::VoteType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +pub const CREATE_PROPOSAL_DISCRIMINATOR: u8 = 6; + +/// Accounts. +#[derive(Debug)] +pub struct CreateProposal { + /// Realm account the created Proposal belongs to + pub realm_account: solana_address::Address, + /// Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index] + pub proposal_account: solana_address::Address, + /// Governance account + pub governance_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Token Mint the Proposal is created for + pub governing_token_mint: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, + /// Optional Proposal deposit is required when there are more active + /// proposals than the configured deposit exempt amount. + /// PDA seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: Option, +} + +impl CreateProposal { + pub fn instruction( + &self, + args: CreateProposalInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateProposalInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(proposal_deposit_account) = self.proposal_deposit_account { + accounts.push(solana_instruction::AccountMeta::new_readonly( + proposal_deposit_account, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateProposalInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateProposalInstructionData { + discriminator: u8, +} + +impl CreateProposalInstructionData { + pub fn new() -> Self { + Self { discriminator: 6 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateProposalInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateProposalInstructionArgs { + pub name: String, + pub description_link: String, + pub vote_type: VoteType, + pub options: Vec, + pub use_deny_option: bool, + pub proposal_seed: Address, +} + +impl CreateProposalInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateProposal`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` proposal_account +/// 2. `[writable]` governance_account +/// 3. `[writable]` token_owner_record +/// 4. `[]` governing_token_mint +/// 5. `[signer]` governance_authority +/// 6. `[signer]` payer +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 8. `[]` realm_config +/// 9. `[writable, optional]` voter_weight_record +/// 10. `[optional]` proposal_deposit_account +#[derive(Clone, Debug)] +pub struct CreateProposalBuilder { + realm_account: solana_address::Address, + proposal_account: solana_address::Address, + governance_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + governance_authority: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + realm_config: solana_address::Address, + voter_weight_record: Option, + proposal_deposit_account: Option, + name: String, + description_link: String, + vote_type: VoteType, + options: Vec, + use_deny_option: bool, + proposal_seed: Address, + __remaining_accounts: Vec, +} + +impl CreateProposalBuilder { + pub fn new( + realm_account: solana_address::Address, + proposal_account: solana_address::Address, + governance_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + governance_authority: solana_address::Address, + payer: solana_address::Address, + realm_config: solana_address::Address, + name: String, + description_link: String, + vote_type: VoteType, + options: Vec, + use_deny_option: bool, + proposal_seed: Address, + ) -> Self { + Self { + realm_account, + proposal_account, + governance_account, + token_owner_record, + governing_token_mint, + governance_authority, + payer, + system_program: None, + realm_config, + voter_weight_record: None, + proposal_deposit_account: None, + name, + description_link, + vote_type, + options, + use_deny_option, + proposal_seed, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// `[optional account]` + /// Optional Proposal deposit is required when there are more active + /// proposals than the configured deposit exempt amount. + /// PDA seeds: ['proposal-deposit', proposal, deposit payer] + #[inline(always)] + pub fn proposal_deposit_account( + &mut self, + proposal_deposit_account: Option, + ) -> &mut Self { + self.proposal_deposit_account = proposal_deposit_account; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let proposal_account = self.proposal_account; + let governance_account = self.governance_account; + let token_owner_record = self.token_owner_record; + let governing_token_mint = self.governing_token_mint; + let governance_authority = self.governance_authority; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let realm_config = self.realm_config; + let voter_weight_record = self.voter_weight_record; + let proposal_deposit_account = self.proposal_deposit_account; + let accounts = CreateProposal { + realm_account, + proposal_account, + governance_account, + token_owner_record, + governing_token_mint, + governance_authority, + payer, + system_program, + realm_config, + voter_weight_record, + proposal_deposit_account, + }; + let args = CreateProposalInstructionArgs { + name: self.name.clone(), + description_link: self.description_link.clone(), + vote_type: self.vote_type.clone(), + options: self.options.clone(), + use_deny_option: self.use_deny_option.clone(), + proposal_seed: self.proposal_seed.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_proposal` CPI accounts. +pub struct CreateProposalCpiAccounts<'a, 'b> { + /// Realm account the created Proposal belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index] + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// Governance account + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Token Mint the Proposal is created for + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Proposal deposit is required when there are more active + /// proposals than the configured deposit exempt amount. + /// PDA seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_proposal` CPI instruction. +pub struct CreateProposalCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Realm account the created Proposal belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Proposal account. PDA seeds ['governance',governance, governing_token_mint, proposal_index] + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// Governance account + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Token Mint the Proposal is created for + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Proposal deposit is required when there are more active + /// proposals than the configured deposit exempt amount. + /// PDA seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateProposalInstructionArgs, +} + +impl<'a, 'b> CreateProposalCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateProposalCpiAccounts<'a, 'b>, + args: CreateProposalInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + proposal_account: accounts.proposal_account, + governance_account: accounts.governance_account, + token_owner_record: accounts.token_owner_record, + governing_token_mint: accounts.governing_token_mint, + governance_authority: accounts.governance_authority, + payer: accounts.payer, + system_program: accounts.system_program, + realm_config: accounts.realm_config, + voter_weight_record: accounts.voter_weight_record, + proposal_deposit_account: accounts.proposal_deposit_account, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(proposal_deposit_account) = self.proposal_deposit_account { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *proposal_deposit_account.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateProposalInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(12 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + if let Some(proposal_deposit_account) = self.proposal_deposit_account { + account_infos.push(proposal_deposit_account.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateProposal` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` proposal_account +/// 2. `[writable]` governance_account +/// 3. `[writable]` token_owner_record +/// 4. `[]` governing_token_mint +/// 5. `[signer]` governance_authority +/// 6. `[signer]` payer +/// 7. `[]` system_program +/// 8. `[]` realm_config +/// 9. `[writable, optional]` voter_weight_record +/// 10. `[optional]` proposal_deposit_account +#[derive(Clone, Debug)] +pub struct CreateProposalCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateProposalCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + name: String, + description_link: String, + vote_type: VoteType, + options: Vec, + use_deny_option: bool, + proposal_seed: Address, + ) -> Self { + let instruction = Box::new(CreateProposalCpiBuilderInstruction { + __program, + realm_account, + proposal_account, + governance_account, + token_owner_record, + governing_token_mint, + governance_authority, + payer, + system_program, + realm_config, + voter_weight_record: None, + proposal_deposit_account: None, + name, + description_link, + vote_type, + options, + use_deny_option, + proposal_seed, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// `[optional account]` + /// Optional Proposal deposit is required when there are more active + /// proposals than the configured deposit exempt amount. + /// PDA seeds: ['proposal-deposit', proposal, deposit payer] + #[inline(always)] + pub fn proposal_deposit_account( + &mut self, + proposal_deposit_account: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.proposal_deposit_account = proposal_deposit_account; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateProposalInstructionArgs { + name: self.instruction.name.clone(), + description_link: self.instruction.description_link.clone(), + vote_type: self.instruction.vote_type.clone(), + options: self.instruction.options.clone(), + use_deny_option: self.instruction.use_deny_option.clone(), + proposal_seed: self.instruction.proposal_seed.clone(), + }; + let instruction = CreateProposalCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + proposal_account: self.instruction.proposal_account, + governance_account: self.instruction.governance_account, + token_owner_record: self.instruction.token_owner_record, + governing_token_mint: self.instruction.governing_token_mint, + governance_authority: self.instruction.governance_authority, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + realm_config: self.instruction.realm_config, + voter_weight_record: self.instruction.voter_weight_record, + proposal_deposit_account: self.instruction.proposal_deposit_account, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateProposalCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + proposal_deposit_account: Option<&'b solana_account_info::AccountInfo<'a>>, + name: String, + description_link: String, + vote_type: VoteType, + options: Vec, + use_deny_option: bool, + proposal_seed: Address, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_realm.rs b/e2e/governance/src/generated/instructions/create_realm.rs new file mode 100644 index 0000000..a597d1c --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_realm.rs @@ -0,0 +1,922 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::RealmConfigParams; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_REALM_DISCRIMINATOR: u8 = 0; + +/// Accounts. +#[derive(Debug)] +pub struct CreateRealm { + /// Governance Realm account + pub realm_account: solana_address::Address, + /// The authority of the Realm + pub realm_authority: solana_address::Address, + /// The mint address of the token to be used as the community mint + pub community_token_mint: solana_address::Address, + /// The account to hold the community tokens. + /// PDA seeds=['governance', realm, community_mint] + pub community_token_holding_account: solana_address::Address, + /// the payer of this transaction + pub payer: solana_address::Address, + /// System Program + pub system_program: solana_address::Address, + /// SPL Token Program + pub token_program: solana_address::Address, + /// SysVar Rent + pub rent: solana_address::Address, + /// The mint address of the token to be used as the council mint + pub council_token_mint: Option, + /// The account to hold the council tokens. + /// PDA seeds: ['governance',realm,council_mint] + /// + pub council_token_holding_account: Option, + /// Realm Config account + pub realm_config: solana_address::Address, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin: Option, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin: Option, + /// Optional Council Voter Weight Addin Program Id + pub council_voter_weight_addin: Option, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin: Option, +} + +impl CreateRealm { + pub fn instruction(&self, args: CreateRealmInstructionArgs) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateRealmInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.community_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.community_token_holding_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.payer, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.rent, false, + )); + if let Some(council_token_mint) = self.council_token_mint { + accounts.push(solana_instruction::AccountMeta::new_readonly( + council_token_mint, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + accounts.push(solana_instruction::AccountMeta::new( + council_token_holding_account, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.push(solana_instruction::AccountMeta::new( + self.realm_config, + false, + )); + if let Some(community_voter_weight_addin) = self.community_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + community_voter_weight_addin, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_community_voter_weight_addin) = self.max_community_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_community_voter_weight_addin, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_voter_weight_addin) = self.council_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + council_voter_weight_addin, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_council_voter_weight_addin) = self.max_council_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_council_voter_weight_addin, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateRealmInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateRealmInstructionData { + discriminator: u8, +} + +impl CreateRealmInstructionData { + pub fn new() -> Self { + Self { discriminator: 0 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateRealmInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateRealmInstructionArgs { + pub name: String, + pub config_args: RealmConfigParams, +} + +impl CreateRealmInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateRealm`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[]` realm_authority +/// 2. `[]` community_token_mint +/// 3. `[writable]` community_token_holding_account +/// 4. `[writable, signer]` payer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 6. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 7. `[optional]` rent (default to `SysvarRent111111111111111111111111111111111`) +/// 8. `[optional]` council_token_mint +/// 9. `[writable, optional]` council_token_holding_account +/// 10. `[writable]` realm_config +/// 11. `[optional]` community_voter_weight_addin +/// 12. `[optional]` max_community_voter_weight_addin +/// 13. `[optional]` council_voter_weight_addin +/// 14. `[optional]` max_council_voter_weight_addin +#[derive(Clone, Debug)] +pub struct CreateRealmBuilder { + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + community_token_mint: solana_address::Address, + community_token_holding_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + token_program: Option, + rent: Option, + council_token_mint: Option, + council_token_holding_account: Option, + realm_config: solana_address::Address, + community_voter_weight_addin: Option, + max_community_voter_weight_addin: Option, + council_voter_weight_addin: Option, + max_council_voter_weight_addin: Option, + name: String, + config_args: RealmConfigParams, + __remaining_accounts: Vec, +} + +impl CreateRealmBuilder { + pub fn new( + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + community_token_mint: solana_address::Address, + community_token_holding_account: solana_address::Address, + payer: solana_address::Address, + realm_config: solana_address::Address, + name: String, + config_args: RealmConfigParams, + ) -> Self { + Self { + realm_account, + realm_authority, + community_token_mint, + community_token_holding_account, + payer, + system_program: None, + token_program: None, + rent: None, + council_token_mint: None, + council_token_holding_account: None, + realm_config, + community_voter_weight_addin: None, + max_community_voter_weight_addin: None, + council_voter_weight_addin: None, + max_council_voter_weight_addin: None, + name, + config_args, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// System Program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token Program + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// `[optional account, default to 'SysvarRent111111111111111111111111111111111']` + /// SysVar Rent + #[inline(always)] + pub fn rent(&mut self, rent: solana_address::Address) -> &mut Self { + self.rent = Some(rent); + self + } + /// `[optional account]` + /// The mint address of the token to be used as the council mint + #[inline(always)] + pub fn council_token_mint( + &mut self, + council_token_mint: Option, + ) -> &mut Self { + self.council_token_mint = council_token_mint; + self + } + /// `[optional account]` + /// The account to hold the council tokens. + /// PDA seeds: ['governance',realm,council_mint] + /// + #[inline(always)] + pub fn council_token_holding_account( + &mut self, + council_token_holding_account: Option, + ) -> &mut Self { + self.council_token_holding_account = council_token_holding_account; + self + } + /// `[optional account]` + /// Optional Community Voter Weight Addin Program Id + #[inline(always)] + pub fn community_voter_weight_addin( + &mut self, + community_voter_weight_addin: Option, + ) -> &mut Self { + self.community_voter_weight_addin = community_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Max Community Voter Weight Addin Program Id + #[inline(always)] + pub fn max_community_voter_weight_addin( + &mut self, + max_community_voter_weight_addin: Option, + ) -> &mut Self { + self.max_community_voter_weight_addin = max_community_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Council Voter Weight Addin Program Id + #[inline(always)] + pub fn council_voter_weight_addin( + &mut self, + council_voter_weight_addin: Option, + ) -> &mut Self { + self.council_voter_weight_addin = council_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Max Council Voter Weight Addin Program Id + #[inline(always)] + pub fn max_council_voter_weight_addin( + &mut self, + max_council_voter_weight_addin: Option, + ) -> &mut Self { + self.max_council_voter_weight_addin = max_council_voter_weight_addin; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let realm_authority = self.realm_authority; + let community_token_mint = self.community_token_mint; + let community_token_holding_account = self.community_token_holding_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let rent = self.rent.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let council_token_mint = self.council_token_mint; + let council_token_holding_account = self.council_token_holding_account; + let realm_config = self.realm_config; + let community_voter_weight_addin = self.community_voter_weight_addin; + let max_community_voter_weight_addin = self.max_community_voter_weight_addin; + let council_voter_weight_addin = self.council_voter_weight_addin; + let max_council_voter_weight_addin = self.max_council_voter_weight_addin; + let accounts = CreateRealm { + realm_account, + realm_authority, + community_token_mint, + community_token_holding_account, + payer, + system_program, + token_program, + rent, + council_token_mint, + council_token_holding_account, + realm_config, + community_voter_weight_addin, + max_community_voter_weight_addin, + council_voter_weight_addin, + max_council_voter_weight_addin, + }; + let args = CreateRealmInstructionArgs { + name: self.name.clone(), + config_args: self.config_args.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_realm` CPI accounts. +pub struct CreateRealmCpiAccounts<'a, 'b> { + /// Governance Realm account + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// The authority of the Realm + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the token to be used as the community mint + pub community_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The account to hold the community tokens. + /// PDA seeds=['governance', realm, community_mint] + pub community_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// the payer of this transaction + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// System Program + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// SysVar Rent + pub rent: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the token to be used as the council mint + pub council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The account to hold the council tokens. + /// PDA seeds: ['governance',realm,council_mint] + /// + pub council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Realm Config account + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Council Voter Weight Addin Program Id + pub council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_realm` CPI instruction. +pub struct CreateRealmCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Governance Realm account + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// The authority of the Realm + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the token to be used as the community mint + pub community_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The account to hold the community tokens. + /// PDA seeds=['governance', realm, community_mint] + pub community_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// the payer of this transaction + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// System Program + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// SysVar Rent + pub rent: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the token to be used as the council mint + pub council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The account to hold the council tokens. + /// PDA seeds: ['governance',realm,council_mint] + /// + pub council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Realm Config account + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Council Voter Weight Addin Program Id + pub council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateRealmInstructionArgs, +} + +impl<'a, 'b> CreateRealmCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateRealmCpiAccounts<'a, 'b>, + args: CreateRealmInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + realm_authority: accounts.realm_authority, + community_token_mint: accounts.community_token_mint, + community_token_holding_account: accounts.community_token_holding_account, + payer: accounts.payer, + system_program: accounts.system_program, + token_program: accounts.token_program, + rent: accounts.rent, + council_token_mint: accounts.council_token_mint, + council_token_holding_account: accounts.council_token_holding_account, + realm_config: accounts.realm_config, + community_voter_weight_addin: accounts.community_voter_weight_addin, + max_community_voter_weight_addin: accounts.max_community_voter_weight_addin, + council_voter_weight_addin: accounts.council_voter_weight_addin, + max_council_voter_weight_addin: accounts.max_council_voter_weight_addin, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.community_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.community_token_holding_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(*self.payer.key, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.rent.key, + false, + )); + if let Some(council_token_mint) = self.council_token_mint { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *council_token_mint.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + accounts.push(solana_instruction::AccountMeta::new( + *council_token_holding_account.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_config.key, + false, + )); + if let Some(community_voter_weight_addin) = self.community_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *community_voter_weight_addin.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_community_voter_weight_addin) = self.max_community_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_community_voter_weight_addin.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_voter_weight_addin) = self.council_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *council_voter_weight_addin.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_council_voter_weight_addin) = self.max_council_voter_weight_addin { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_council_voter_weight_addin.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateRealmInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(16 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.realm_authority.clone()); + account_infos.push(self.community_token_mint.clone()); + account_infos.push(self.community_token_holding_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.rent.clone()); + if let Some(council_token_mint) = self.council_token_mint { + account_infos.push(council_token_mint.clone()); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + account_infos.push(council_token_holding_account.clone()); + } + account_infos.push(self.realm_config.clone()); + if let Some(community_voter_weight_addin) = self.community_voter_weight_addin { + account_infos.push(community_voter_weight_addin.clone()); + } + if let Some(max_community_voter_weight_addin) = self.max_community_voter_weight_addin { + account_infos.push(max_community_voter_weight_addin.clone()); + } + if let Some(council_voter_weight_addin) = self.council_voter_weight_addin { + account_infos.push(council_voter_weight_addin.clone()); + } + if let Some(max_council_voter_weight_addin) = self.max_council_voter_weight_addin { + account_infos.push(max_council_voter_weight_addin.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateRealm` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[]` realm_authority +/// 2. `[]` community_token_mint +/// 3. `[writable]` community_token_holding_account +/// 4. `[writable, signer]` payer +/// 5. `[]` system_program +/// 6. `[]` token_program +/// 7. `[]` rent +/// 8. `[optional]` council_token_mint +/// 9. `[writable, optional]` council_token_holding_account +/// 10. `[writable]` realm_config +/// 11. `[optional]` community_voter_weight_addin +/// 12. `[optional]` max_community_voter_weight_addin +/// 13. `[optional]` council_voter_weight_addin +/// 14. `[optional]` max_council_voter_weight_addin +#[derive(Clone, Debug)] +pub struct CreateRealmCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateRealmCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + community_token_mint: &'b solana_account_info::AccountInfo<'a>, + community_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + name: String, + config_args: RealmConfigParams, + ) -> Self { + let instruction = Box::new(CreateRealmCpiBuilderInstruction { + __program, + realm_account, + realm_authority, + community_token_mint, + community_token_holding_account, + payer, + system_program, + token_program, + rent, + council_token_mint: None, + council_token_holding_account: None, + realm_config, + community_voter_weight_addin: None, + max_community_voter_weight_addin: None, + council_voter_weight_addin: None, + max_council_voter_weight_addin: None, + name, + config_args, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// The mint address of the token to be used as the council mint + #[inline(always)] + pub fn council_token_mint( + &mut self, + council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_token_mint = council_token_mint; + self + } + /// `[optional account]` + /// The account to hold the council tokens. + /// PDA seeds: ['governance',realm,council_mint] + /// + #[inline(always)] + pub fn council_token_holding_account( + &mut self, + council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_token_holding_account = council_token_holding_account; + self + } + /// `[optional account]` + /// Optional Community Voter Weight Addin Program Id + #[inline(always)] + pub fn community_voter_weight_addin( + &mut self, + community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.community_voter_weight_addin = community_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Max Community Voter Weight Addin Program Id + #[inline(always)] + pub fn max_community_voter_weight_addin( + &mut self, + max_community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.max_community_voter_weight_addin = max_community_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Council Voter Weight Addin Program Id + #[inline(always)] + pub fn council_voter_weight_addin( + &mut self, + council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_voter_weight_addin = council_voter_weight_addin; + self + } + /// `[optional account]` + /// Optional Max Council Voter Weight Addin Program Id + #[inline(always)] + pub fn max_council_voter_weight_addin( + &mut self, + max_council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.max_council_voter_weight_addin = max_council_voter_weight_addin; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateRealmInstructionArgs { + name: self.instruction.name.clone(), + config_args: self.instruction.config_args.clone(), + }; + let instruction = CreateRealmCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + realm_authority: self.instruction.realm_authority, + community_token_mint: self.instruction.community_token_mint, + community_token_holding_account: self.instruction.community_token_holding_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + token_program: self.instruction.token_program, + rent: self.instruction.rent, + council_token_mint: self.instruction.council_token_mint, + council_token_holding_account: self.instruction.council_token_holding_account, + realm_config: self.instruction.realm_config, + community_voter_weight_addin: self.instruction.community_voter_weight_addin, + max_community_voter_weight_addin: self.instruction.max_community_voter_weight_addin, + council_voter_weight_addin: self.instruction.council_voter_weight_addin, + max_council_voter_weight_addin: self.instruction.max_council_voter_weight_addin, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateRealmCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + community_token_mint: &'b solana_account_info::AccountInfo<'a>, + community_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + max_community_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + max_council_voter_weight_addin: Option<&'b solana_account_info::AccountInfo<'a>>, + name: String, + config_args: RealmConfigParams, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_token_governance.rs b/e2e/governance/src/generated/instructions/create_token_governance.rs new file mode 100644 index 0000000..1d610f4 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_token_governance.rs @@ -0,0 +1,634 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_TOKEN_GOVERNANCE_DISCRIMINATOR: u8 = 18; + +/// Accounts. +#[derive(Debug)] +pub struct CreateTokenGovernance { + /// Realm account the created Governance belongs to + pub realm_account: solana_address::Address, + /// Token Governance account. seeds=['token-governance', realm, governed_token] + pub token_governance_account: solana_address::Address, + /// Token account governed by this Governance account + pub token_account: solana_address::Address, + /// Current token account authority (AccountOwner and optionally CloseAccount + pub token_account_authority: solana_address::Address, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority + pub governing_token_owner_record: solana_address::Address, + + pub payer: solana_address::Address, + + pub token_program: solana_address::Address, + + pub system_program: solana_address::Address, + + pub governance_authority: solana_address::Address, + /// seeds=['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Voter Weight Record + pub voter_weight_record: Option, +} + +impl CreateTokenGovernance { + pub fn instruction( + &self, + args: CreateTokenGovernanceInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateTokenGovernanceInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_account_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateTokenGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateTokenGovernanceInstructionData { + discriminator: u8, +} + +impl CreateTokenGovernanceInstructionData { + pub fn new() -> Self { + Self { discriminator: 18 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateTokenGovernanceInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateTokenGovernanceInstructionArgs { + pub config: GovernanceConfig, + pub transfer_account_authorities: bool, +} + +impl CreateTokenGovernanceInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateTokenGovernance`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` token_governance_account +/// 2. `[writable]` token_account +/// 3. `[signer]` token_account_authority +/// 4. `[]` governing_token_owner_record +/// 5. `[signer]` payer +/// 6. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 8. `[signer]` governance_authority +/// 9. `[]` realm_config +/// 10. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateTokenGovernanceBuilder { + realm_account: solana_address::Address, + token_governance_account: solana_address::Address, + token_account: solana_address::Address, + token_account_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + token_program: Option, + system_program: Option, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + voter_weight_record: Option, + config: GovernanceConfig, + transfer_account_authorities: bool, + __remaining_accounts: Vec, +} + +impl CreateTokenGovernanceBuilder { + pub fn new( + realm_account: solana_address::Address, + token_governance_account: solana_address::Address, + token_account: solana_address::Address, + token_account_authority: solana_address::Address, + governing_token_owner_record: solana_address::Address, + payer: solana_address::Address, + governance_authority: solana_address::Address, + realm_config: solana_address::Address, + config: GovernanceConfig, + transfer_account_authorities: bool, + ) -> Self { + Self { + realm_account, + token_governance_account, + token_account, + token_account_authority, + governing_token_owner_record, + payer, + token_program: None, + system_program: None, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_account_authorities, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option, + ) -> &mut Self { + self.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let token_governance_account = self.token_governance_account; + let token_account = self.token_account; + let token_account_authority = self.token_account_authority; + let governing_token_owner_record = self.governing_token_owner_record; + let payer = self.payer; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let governance_authority = self.governance_authority; + let realm_config = self.realm_config; + let voter_weight_record = self.voter_weight_record; + let accounts = CreateTokenGovernance { + realm_account, + token_governance_account, + token_account, + token_account_authority, + governing_token_owner_record, + payer, + token_program, + system_program, + governance_authority, + realm_config, + voter_weight_record, + }; + let args = CreateTokenGovernanceInstructionArgs { + config: self.config.clone(), + transfer_account_authorities: self.transfer_account_authorities.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_token_governance` CPI accounts. +pub struct CreateTokenGovernanceCpiAccounts<'a, 'b> { + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Token Governance account. seeds=['token-governance', realm, governed_token] + pub token_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Token account governed by this Governance account + pub token_account: &'b solana_account_info::AccountInfo<'a>, + /// Current token account authority (AccountOwner and optionally CloseAccount + pub token_account_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `create_token_governance` CPI instruction. +pub struct CreateTokenGovernanceCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Realm account the created Governance belongs to + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// Token Governance account. seeds=['token-governance', realm, governed_token] + pub token_governance_account: &'b solana_account_info::AccountInfo<'a>, + /// Token account governed by this Governance account + pub token_account: &'b solana_account_info::AccountInfo<'a>, + /// Current token account authority (AccountOwner and optionally CloseAccount + pub token_account_authority: &'b solana_account_info::AccountInfo<'a>, + /// Governing TokenOwnerRecord account (Used only if not signed by RealmAuthority + pub governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Voter Weight Record + pub voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: CreateTokenGovernanceInstructionArgs, +} + +impl<'a, 'b> CreateTokenGovernanceCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateTokenGovernanceCpiAccounts<'a, 'b>, + args: CreateTokenGovernanceInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + token_governance_account: accounts.token_governance_account, + token_account: accounts.token_account, + token_account_authority: accounts.token_account_authority, + governing_token_owner_record: accounts.governing_token_owner_record, + payer: accounts.payer, + token_program: accounts.token_program, + system_program: accounts.system_program, + governance_authority: accounts.governance_authority, + realm_config: accounts.realm_config, + voter_weight_record: accounts.voter_weight_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_account_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config.key, + false, + )); + if let Some(voter_weight_record) = self.voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = CreateTokenGovernanceInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(12 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.token_governance_account.clone()); + account_infos.push(self.token_account.clone()); + account_infos.push(self.token_account_authority.clone()); + account_infos.push(self.governing_token_owner_record.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(voter_weight_record) = self.voter_weight_record { + account_infos.push(voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateTokenGovernance` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` token_governance_account +/// 2. `[writable]` token_account +/// 3. `[signer]` token_account_authority +/// 4. `[]` governing_token_owner_record +/// 5. `[signer]` payer +/// 6. `[]` token_program +/// 7. `[]` system_program +/// 8. `[signer]` governance_authority +/// 9. `[]` realm_config +/// 10. `[optional]` voter_weight_record +#[derive(Clone, Debug)] +pub struct CreateTokenGovernanceCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateTokenGovernanceCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + token_governance_account: &'b solana_account_info::AccountInfo<'a>, + token_account: &'b solana_account_info::AccountInfo<'a>, + token_account_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + transfer_account_authorities: bool, + ) -> Self { + let instruction = Box::new(CreateTokenGovernanceCpiBuilderInstruction { + __program, + realm_account, + token_governance_account, + token_account, + token_account_authority, + governing_token_owner_record, + payer, + token_program, + system_program, + governance_authority, + realm_config, + voter_weight_record: None, + config, + transfer_account_authorities, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Voter Weight Record + #[inline(always)] + pub fn voter_weight_record( + &mut self, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.voter_weight_record = voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = CreateTokenGovernanceInstructionArgs { + config: self.instruction.config.clone(), + transfer_account_authorities: self.instruction.transfer_account_authorities.clone(), + }; + let instruction = CreateTokenGovernanceCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + token_governance_account: self.instruction.token_governance_account, + token_account: self.instruction.token_account, + token_account_authority: self.instruction.token_account_authority, + governing_token_owner_record: self.instruction.governing_token_owner_record, + payer: self.instruction.payer, + token_program: self.instruction.token_program, + system_program: self.instruction.system_program, + governance_authority: self.instruction.governance_authority, + realm_config: self.instruction.realm_config, + voter_weight_record: self.instruction.voter_weight_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateTokenGovernanceCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + token_governance_account: &'b solana_account_info::AccountInfo<'a>, + token_account: &'b solana_account_info::AccountInfo<'a>, + token_account_authority: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + config: GovernanceConfig, + transfer_account_authorities: bool, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/create_token_owner_record.rs b/e2e/governance/src/generated/instructions/create_token_owner_record.rs new file mode 100644 index 0000000..bc91af5 --- /dev/null +++ b/e2e/governance/src/generated/instructions/create_token_owner_record.rs @@ -0,0 +1,423 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_TOKEN_OWNER_RECORD_DISCRIMINATOR: u8 = 23; + +/// Accounts. +#[derive(Debug)] +pub struct CreateTokenOwnerRecord { + pub realm_account: solana_address::Address, + + pub governing_token_owner_account: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: solana_address::Address, + + pub governing_token_mint: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl CreateTokenOwnerRecord { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CreateTokenOwnerRecordInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateTokenOwnerRecordInstructionData { + discriminator: u8, +} + +impl CreateTokenOwnerRecordInstructionData { + pub fn new() -> Self { + Self { discriminator: 23 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateTokenOwnerRecordInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CreateTokenOwnerRecord`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governing_token_owner_account +/// 2. `[writable, optional]` token_owner_record (default to PDA derived from 'tokenOwnerRecord') +/// 3. `[]` governing_token_mint +/// 4. `[signer]` payer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreateTokenOwnerRecordBuilder { + realm_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + token_owner_record: Option, + governing_token_mint: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + __remaining_accounts: Vec, +} + +impl CreateTokenOwnerRecordBuilder { + pub fn new( + realm_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + governing_token_mint: solana_address::Address, + payer: solana_address::Address, + ) -> Self { + Self { + realm_account, + governing_token_owner_account, + token_owner_record: None, + governing_token_mint, + payer, + system_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'tokenOwnerRecord']` + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + #[inline(always)] + pub fn token_owner_record(&mut self, token_owner_record: solana_address::Address) -> &mut Self { + self.token_owner_record = Some(token_owner_record); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governing_token_owner_account = self.governing_token_owner_account; + let token_owner_record = self.token_owner_record.unwrap_or_else(|| { + crate::pdas::find_token_owner_record_pda( + &self.realm_account, + &self.governing_token_mint, + &self.governing_token_owner_account, + ) + .0 + }); + let governing_token_mint = self.governing_token_mint; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreateTokenOwnerRecord { + realm_account, + governing_token_owner_account, + token_owner_record, + governing_token_mint, + payer, + system_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `create_token_owner_record` CPI accounts. +pub struct CreateTokenOwnerRecordCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_token_owner_record` CPI instruction. +pub struct CreateTokenOwnerRecordCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CreateTokenOwnerRecordCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateTokenOwnerRecordCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governing_token_owner_account: accounts.governing_token_owner_account, + token_owner_record: accounts.token_owner_record, + governing_token_mint: accounts.governing_token_mint, + payer: accounts.payer, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = CreateTokenOwnerRecordInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(7 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governing_token_owner_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateTokenOwnerRecord` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governing_token_owner_account +/// 2. `[writable]` token_owner_record +/// 3. `[]` governing_token_mint +/// 4. `[signer]` payer +/// 5. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreateTokenOwnerRecordCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateTokenOwnerRecordCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CreateTokenOwnerRecordCpiBuilderInstruction { + __program, + realm_account, + governing_token_owner_account, + token_owner_record, + governing_token_mint, + payer, + system_program, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = CreateTokenOwnerRecordCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governing_token_owner_account: self.instruction.governing_token_owner_account, + token_owner_record: self.instruction.token_owner_record, + governing_token_mint: self.instruction.governing_token_mint, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateTokenOwnerRecordCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/deposit_governing_tokens.rs b/e2e/governance/src/generated/instructions/deposit_governing_tokens.rs new file mode 100644 index 0000000..e6c2be4 --- /dev/null +++ b/e2e/governance/src/generated/instructions/deposit_governing_tokens.rs @@ -0,0 +1,560 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const DEPOSIT_GOVERNING_TOKENS_DISCRIMINATOR: u8 = 1; + +/// Accounts. +#[derive(Debug)] +pub struct DepositGoverningTokens { + pub realm_account: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: solana_address::Address, + /// It can either be spl-token TokenAccount or MintAccount. Tokens will be transferred or minted to the holding account + pub governing_token_source_account: solana_address::Address, + + pub governing_token_owner_account: solana_address::Address, + /// It should be owner for TokenAccount and mint_authority for MintAccount + pub governing_token_source_account_authority: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, + + pub token_program: solana_address::Address, + /// seeds=['realm-config', realm] + pub realm_config_account: solana_address::Address, +} + +impl DepositGoverningTokens { + pub fn instruction( + &self, + args: DepositGoverningTokensInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: DepositGoverningTokensInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_holding_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_source_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_account, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_source_account_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.payer, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = DepositGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct DepositGoverningTokensInstructionData { + discriminator: u8, +} + +impl DepositGoverningTokensInstructionData { + pub fn new() -> Self { + Self { discriminator: 1 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for DepositGoverningTokensInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct DepositGoverningTokensInstructionArgs { + pub amount: u64, +} + +impl DepositGoverningTokensInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `DepositGoverningTokens`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` governing_token_source_account +/// 3. `[signer]` governing_token_owner_account +/// 4. `[signer]` governing_token_source_account_authority +/// 5. `[writable]` token_owner_record +/// 6. `[writable, signer]` payer +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 8. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 9. `[]` realm_config_account +#[derive(Clone, Debug)] +pub struct DepositGoverningTokensBuilder { + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + governing_token_source_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + governing_token_source_account_authority: solana_address::Address, + token_owner_record: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + token_program: Option, + realm_config_account: solana_address::Address, + amount: u64, + __remaining_accounts: Vec, +} + +impl DepositGoverningTokensBuilder { + pub fn new( + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + governing_token_source_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + governing_token_source_account_authority: solana_address::Address, + token_owner_record: solana_address::Address, + payer: solana_address::Address, + realm_config_account: solana_address::Address, + amount: u64, + ) -> Self { + Self { + realm_account, + governing_token_holding_account, + governing_token_source_account, + governing_token_owner_account, + governing_token_source_account_authority, + token_owner_record, + payer, + system_program: None, + token_program: None, + realm_config_account, + amount, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governing_token_holding_account = self.governing_token_holding_account; + let governing_token_source_account = self.governing_token_source_account; + let governing_token_owner_account = self.governing_token_owner_account; + let governing_token_source_account_authority = + self.governing_token_source_account_authority; + let token_owner_record = self.token_owner_record; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let realm_config_account = self.realm_config_account; + let accounts = DepositGoverningTokens { + realm_account, + governing_token_holding_account, + governing_token_source_account, + governing_token_owner_account, + governing_token_source_account_authority, + token_owner_record, + payer, + system_program, + token_program, + realm_config_account, + }; + let args = DepositGoverningTokensInstructionArgs { + amount: self.amount.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `deposit_governing_tokens` CPI accounts. +pub struct DepositGoverningTokensCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// It can either be spl-token TokenAccount or MintAccount. Tokens will be transferred or minted to the holding account + pub governing_token_source_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// It should be owner for TokenAccount and mint_authority for MintAccount + pub governing_token_source_account_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `deposit_governing_tokens` CPI instruction. +pub struct DepositGoverningTokensCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// It can either be spl-token TokenAccount or MintAccount. Tokens will be transferred or minted to the holding account + pub governing_token_source_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// It should be owner for TokenAccount and mint_authority for MintAccount + pub governing_token_source_account_authority: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: DepositGoverningTokensInstructionArgs, +} + +impl<'a, 'b> DepositGoverningTokensCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: DepositGoverningTokensCpiAccounts<'a, 'b>, + args: DepositGoverningTokensInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governing_token_holding_account: accounts.governing_token_holding_account, + governing_token_source_account: accounts.governing_token_source_account, + governing_token_owner_account: accounts.governing_token_owner_account, + governing_token_source_account_authority: accounts + .governing_token_source_account_authority, + token_owner_record: accounts.token_owner_record, + payer: accounts.payer, + system_program: accounts.system_program, + token_program: accounts.token_program, + realm_config_account: accounts.realm_config_account, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_holding_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_source_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_account.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_source_account_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(*self.payer.key, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = DepositGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(11 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governing_token_holding_account.clone()); + account_infos.push(self.governing_token_source_account.clone()); + account_infos.push(self.governing_token_owner_account.clone()); + account_infos.push(self.governing_token_source_account_authority.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.realm_config_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `DepositGoverningTokens` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` governing_token_source_account +/// 3. `[signer]` governing_token_owner_account +/// 4. `[signer]` governing_token_source_account_authority +/// 5. `[writable]` token_owner_record +/// 6. `[writable, signer]` payer +/// 7. `[]` system_program +/// 8. `[]` token_program +/// 9. `[]` realm_config_account +#[derive(Clone, Debug)] +pub struct DepositGoverningTokensCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> DepositGoverningTokensCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_source_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_source_account_authority: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + ) -> Self { + let instruction = Box::new(DepositGoverningTokensCpiBuilderInstruction { + __program, + realm_account, + governing_token_holding_account, + governing_token_source_account, + governing_token_owner_account, + governing_token_source_account_authority, + token_owner_record, + payer, + system_program, + token_program, + realm_config_account, + amount, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = DepositGoverningTokensInstructionArgs { + amount: self.instruction.amount.clone(), + }; + let instruction = DepositGoverningTokensCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governing_token_holding_account: self.instruction.governing_token_holding_account, + governing_token_source_account: self.instruction.governing_token_source_account, + governing_token_owner_account: self.instruction.governing_token_owner_account, + governing_token_source_account_authority: self + .instruction + .governing_token_source_account_authority, + token_owner_record: self.instruction.token_owner_record, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + token_program: self.instruction.token_program, + realm_config_account: self.instruction.realm_config_account, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct DepositGoverningTokensCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_source_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_source_account_authority: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/execute_transaction.rs b/e2e/governance/src/generated/instructions/execute_transaction.rs new file mode 100644 index 0000000..a71279f --- /dev/null +++ b/e2e/governance/src/generated/instructions/execute_transaction.rs @@ -0,0 +1,323 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const EXECUTE_TRANSACTION_DISCRIMINATOR: u8 = 16; + +/// Accounts. +#[derive(Debug)] +pub struct ExecuteTransaction { + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + + pub proposal_transaction_account: solana_address::Address, +} + +impl ExecuteTransaction { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_transaction_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = ExecuteTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ExecuteTransactionInstructionData { + discriminator: u8, +} + +impl ExecuteTransactionInstructionData { + pub fn new() -> Self { + Self { discriminator: 16 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for ExecuteTransactionInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `ExecuteTransaction`. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` proposal_account +/// 2. `[writable]` proposal_transaction_account +#[derive(Clone, Debug)] +pub struct ExecuteTransactionBuilder { + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + proposal_transaction_account: solana_address::Address, + __remaining_accounts: Vec, +} + +impl ExecuteTransactionBuilder { + pub fn new( + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + proposal_transaction_account: solana_address::Address, + ) -> Self { + Self { + governance_account, + proposal_account, + proposal_transaction_account, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let proposal_transaction_account = self.proposal_transaction_account; + let accounts = ExecuteTransaction { + governance_account, + proposal_account, + proposal_transaction_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `execute_transaction` CPI accounts. +pub struct ExecuteTransactionCpiAccounts<'a, 'b> { + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `execute_transaction` CPI instruction. +pub struct ExecuteTransactionCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> ExecuteTransactionCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: ExecuteTransactionCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + proposal_transaction_account: accounts.proposal_transaction_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_transaction_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = ExecuteTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.proposal_transaction_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `ExecuteTransaction` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` proposal_account +/// 2. `[writable]` proposal_transaction_account +#[derive(Clone, Debug)] +pub struct ExecuteTransactionCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> ExecuteTransactionCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(ExecuteTransactionCpiBuilderInstruction { + __program, + governance_account, + proposal_account, + proposal_transaction_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = ExecuteTransactionCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + proposal_transaction_account: self.instruction.proposal_transaction_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct ExecuteTransactionCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/finalize_vote.rs b/e2e/governance/src/generated/instructions/finalize_vote.rs new file mode 100644 index 0000000..fd7a1e5 --- /dev/null +++ b/e2e/governance/src/generated/instructions/finalize_vote.rs @@ -0,0 +1,461 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const FINALIZE_VOTE_DISCRIMINATOR: u8 = 14; + +/// Accounts. +#[derive(Debug)] +pub struct FinalizeVote { + pub realm_account: solana_address::Address, + + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord of the Proposal owner + pub token_owner_record: solana_address::Address, + + pub governing_token_mint: solana_address::Address, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option, +} + +impl FinalizeVote { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config, + false, + )); + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_voter_weight_record, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let data = FinalizeVoteInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct FinalizeVoteInstructionData { + discriminator: u8, +} + +impl FinalizeVoteInstructionData { + pub fn new() -> Self { + Self { discriminator: 14 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for FinalizeVoteInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `FinalizeVote`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[]` governing_token_mint +/// 5. `[]` realm_config +/// 6. `[optional]` max_voter_weight_record +#[derive(Clone, Debug)] +pub struct FinalizeVoteBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + realm_config: solana_address::Address, + max_voter_weight_record: Option, + __remaining_accounts: Vec, +} + +impl FinalizeVoteBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + realm_config: solana_address::Address, + ) -> Self { + Self { + realm_account, + governance_account, + proposal_account, + token_owner_record, + governing_token_mint, + realm_config, + max_voter_weight_record: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account]` + /// Optional Max Voter Weight Record + #[inline(always)] + pub fn max_voter_weight_record( + &mut self, + max_voter_weight_record: Option, + ) -> &mut Self { + self.max_voter_weight_record = max_voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governing_token_mint = self.governing_token_mint; + let realm_config = self.realm_config; + let max_voter_weight_record = self.max_voter_weight_record; + let accounts = FinalizeVote { + realm_account, + governance_account, + proposal_account, + token_owner_record, + governing_token_mint, + realm_config, + max_voter_weight_record, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `finalize_vote` CPI accounts. +pub struct FinalizeVoteCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `finalize_vote` CPI instruction. +pub struct FinalizeVoteCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. PDA seeds: ['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Max Voter Weight Record + pub max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +impl<'a, 'b> FinalizeVoteCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: FinalizeVoteCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governing_token_mint: accounts.governing_token_mint, + realm_config: accounts.realm_config, + max_voter_weight_record: accounts.max_voter_weight_record, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config.key, + false, + )); + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_voter_weight_record.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = FinalizeVoteInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(8 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(max_voter_weight_record) = self.max_voter_weight_record { + account_infos.push(max_voter_weight_record.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `FinalizeVote` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[]` governing_token_mint +/// 5. `[]` realm_config +/// 6. `[optional]` max_voter_weight_record +#[derive(Clone, Debug)] +pub struct FinalizeVoteCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> FinalizeVoteCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(FinalizeVoteCpiBuilderInstruction { + __program, + realm_account, + governance_account, + proposal_account, + token_owner_record, + governing_token_mint, + realm_config, + max_voter_weight_record: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Optional Max Voter Weight Record + #[inline(always)] + pub fn max_voter_weight_record( + &mut self, + max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.max_voter_weight_record = max_voter_weight_record; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = FinalizeVoteCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governing_token_mint: self.instruction.governing_token_mint, + realm_config: self.instruction.realm_config, + max_voter_weight_record: self.instruction.max_voter_weight_record, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct FinalizeVoteCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + max_voter_weight_record: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/flag_transaction_error.rs b/e2e/governance/src/generated/instructions/flag_transaction_error.rs new file mode 100644 index 0000000..3289f49 --- /dev/null +++ b/e2e/governance/src/generated/instructions/flag_transaction_error.rs @@ -0,0 +1,350 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const FLAG_TRANSACTION_ERROR_DISCRIMINATOR: u8 = 20; + +/// Accounts. +#[derive(Debug)] +pub struct FlagTransactionError { + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + /// ProposalTransaction account to flag + pub proposal_transaction_account: solana_address::Address, +} + +impl FlagTransactionError { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_transaction_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = FlagTransactionErrorInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct FlagTransactionErrorInstructionData { + discriminator: u8, +} + +impl FlagTransactionErrorInstructionData { + pub fn new() -> Self { + Self { discriminator: 20 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for FlagTransactionErrorInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `FlagTransactionError`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` proposal_transaction_account +#[derive(Clone, Debug)] +pub struct FlagTransactionErrorBuilder { + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + __remaining_accounts: Vec, +} + +impl FlagTransactionErrorBuilder { + pub fn new( + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + ) -> Self { + Self { + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governance_authority = self.governance_authority; + let proposal_transaction_account = self.proposal_transaction_account; + let accounts = FlagTransactionError { + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `flag_transaction_error` CPI accounts. +pub struct FlagTransactionErrorCpiAccounts<'a, 'b> { + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// ProposalTransaction account to flag + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `flag_transaction_error` CPI instruction. +pub struct FlagTransactionErrorCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// ProposalTransaction account to flag + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> FlagTransactionErrorCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: FlagTransactionErrorCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governance_authority: accounts.governance_authority, + proposal_transaction_account: accounts.proposal_transaction_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_transaction_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = FlagTransactionErrorInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.proposal_transaction_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `FlagTransactionError` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` proposal_transaction_account +#[derive(Clone, Debug)] +pub struct FlagTransactionErrorCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> FlagTransactionErrorCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(FlagTransactionErrorCpiBuilderInstruction { + __program, + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = FlagTransactionErrorCpi { + __program: self.instruction.__program, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governance_authority: self.instruction.governance_authority, + proposal_transaction_account: self.instruction.proposal_transaction_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct FlagTransactionErrorCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/insert_transaction.rs b/e2e/governance/src/generated/instructions/insert_transaction.rs new file mode 100644 index 0000000..6a6c777 --- /dev/null +++ b/e2e/governance/src/generated/instructions/insert_transaction.rs @@ -0,0 +1,534 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::InstructionData; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const INSERT_TRANSACTION_DISCRIMINATOR: u8 = 9; + +/// Accounts. +#[derive(Debug)] +pub struct InsertTransaction { + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + /// ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index] + pub proposal_transaction_account: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, + + pub rent: solana_address::Address, +} + +impl InsertTransaction { + pub fn instruction( + &self, + args: InsertTransactionInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: InsertTransactionInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_transaction_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.rent, false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = InsertTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InsertTransactionInstructionData { + discriminator: u8, +} + +impl InsertTransactionInstructionData { + pub fn new() -> Self { + Self { discriminator: 9 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for InsertTransactionInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InsertTransactionInstructionArgs { + pub option_index: u8, + pub index: u16, + pub hold_up_time: u32, + pub instructions: Vec, +} + +impl InsertTransactionInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `InsertTransaction`. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` proposal_account +/// 2. `[]` token_owner_record +/// 3. `[signer]` governance_authority +/// 4. `[writable]` proposal_transaction_account +/// 5. `[signer]` payer +/// 6. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 7. `[optional]` rent (default to `SysvarRent111111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct InsertTransactionBuilder { + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + rent: Option, + option_index: u8, + index: u16, + hold_up_time: u32, + instructions: Vec, + __remaining_accounts: Vec, +} + +impl InsertTransactionBuilder { + pub fn new( + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + payer: solana_address::Address, + option_index: u8, + index: u16, + hold_up_time: u32, + instructions: Vec, + ) -> Self { + Self { + governance_account, + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + payer, + system_program: None, + rent: None, + option_index, + index, + hold_up_time, + instructions, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account, default to 'SysvarRent111111111111111111111111111111111']` + #[inline(always)] + pub fn rent(&mut self, rent: solana_address::Address) -> &mut Self { + self.rent = Some(rent); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governance_authority = self.governance_authority; + let proposal_transaction_account = self.proposal_transaction_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let rent = self.rent.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let accounts = InsertTransaction { + governance_account, + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + payer, + system_program, + rent, + }; + let args = InsertTransactionInstructionArgs { + option_index: self.option_index.clone(), + index: self.index.clone(), + hold_up_time: self.hold_up_time.clone(), + instructions: self.instructions.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `insert_transaction` CPI accounts. +pub struct InsertTransactionCpiAccounts<'a, 'b> { + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index] + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub rent: &'b solana_account_info::AccountInfo<'a>, +} + +/// `insert_transaction` CPI instruction. +pub struct InsertTransactionCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + /// ProposalTransaction, account. PDA seeds: ['governance', proposal, option_index, index] + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + + pub rent: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InsertTransactionInstructionArgs, +} + +impl<'a, 'b> InsertTransactionCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: InsertTransactionCpiAccounts<'a, 'b>, + args: InsertTransactionInstructionArgs, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governance_authority: accounts.governance_authority, + proposal_transaction_account: accounts.proposal_transaction_account, + payer: accounts.payer, + system_program: accounts.system_program, + rent: accounts.rent, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_transaction_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.rent.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = InsertTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.proposal_transaction_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.rent.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `InsertTransaction` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` governance_account +/// 1. `[writable]` proposal_account +/// 2. `[]` token_owner_record +/// 3. `[signer]` governance_authority +/// 4. `[writable]` proposal_transaction_account +/// 5. `[signer]` payer +/// 6. `[]` system_program +/// 7. `[]` rent +#[derive(Clone, Debug)] +pub struct InsertTransactionCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InsertTransactionCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + option_index: u8, + index: u16, + hold_up_time: u32, + instructions: Vec, + ) -> Self { + let instruction = Box::new(InsertTransactionCpiBuilderInstruction { + __program, + governance_account, + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + payer, + system_program, + rent, + option_index, + index, + hold_up_time, + instructions, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = InsertTransactionInstructionArgs { + option_index: self.instruction.option_index.clone(), + index: self.instruction.index.clone(), + hold_up_time: self.instruction.hold_up_time.clone(), + instructions: self.instruction.instructions.clone(), + }; + let instruction = InsertTransactionCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governance_authority: self.instruction.governance_authority, + proposal_transaction_account: self.instruction.proposal_transaction_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + rent: self.instruction.rent, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InsertTransactionCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + option_index: u8, + index: u16, + hold_up_time: u32, + instructions: Vec, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/legacy1.rs b/e2e/governance/src/generated/instructions/legacy1.rs new file mode 100644 index 0000000..df1e65f --- /dev/null +++ b/e2e/governance/src/generated/instructions/legacy1.rs @@ -0,0 +1,224 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const LEGACY1_DISCRIMINATOR: u8 = 8; + +/// Accounts. +#[derive(Debug)] +pub struct Legacy1 {} + +impl Legacy1 { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(remaining_accounts.len()); + accounts.extend_from_slice(remaining_accounts); + let data = Legacy1InstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Legacy1InstructionData { + discriminator: u8, +} + +impl Legacy1InstructionData { + pub fn new() -> Self { + Self { discriminator: 8 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for Legacy1InstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Legacy1`. +/// +/// ### Accounts: +/// +#[derive(Clone, Debug, Default)] +pub struct Legacy1Builder { + __remaining_accounts: Vec, +} + +impl Legacy1Builder { + pub fn new() -> Self { + Self::default() + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let accounts = Legacy1 {}; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `legacy1` CPI instruction. +pub struct Legacy1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> Legacy1Cpi<'a, 'b> { + pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + Self { __program: program } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(remaining_accounts.len()); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = Legacy1InstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Legacy1` via CPI. +/// +/// ### Accounts: +/// +#[derive(Clone, Debug)] +pub struct Legacy1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> Legacy1CpiBuilder<'a, 'b> { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(Legacy1CpiBuilderInstruction { + __program, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = Legacy1Cpi { + __program: self.instruction.__program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct Legacy1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/mod.rs b/e2e/governance/src/generated/instructions/mod.rs new file mode 100644 index 0000000..6531b79 --- /dev/null +++ b/e2e/governance/src/generated/instructions/mod.rs @@ -0,0 +1,70 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#add_required_signatory; +pub(crate) mod r#add_signatory; +pub(crate) mod r#cancel_proposal; +pub(crate) mod r#cast_vote; +pub(crate) mod r#complete_proposal; +pub(crate) mod r#create_governance; +pub(crate) mod r#create_mint_governance; +pub(crate) mod r#create_native_treasury; +pub(crate) mod r#create_program_governance; +pub(crate) mod r#create_proposal; +pub(crate) mod r#create_realm; +pub(crate) mod r#create_token_governance; +pub(crate) mod r#create_token_owner_record; +pub(crate) mod r#deposit_governing_tokens; +pub(crate) mod r#execute_transaction; +pub(crate) mod r#finalize_vote; +pub(crate) mod r#flag_transaction_error; +pub(crate) mod r#insert_transaction; +pub(crate) mod r#legacy1; +pub(crate) mod r#refund_proposal_deposit; +pub(crate) mod r#relinquish_vote; +pub(crate) mod r#remove_required_signatory; +pub(crate) mod r#remove_transaction; +pub(crate) mod r#revoke_governing_tokens; +pub(crate) mod r#set_governance_config; +pub(crate) mod r#set_governance_delegate; +pub(crate) mod r#set_realm_authority; +pub(crate) mod r#set_realm_config; +pub(crate) mod r#sign_off_proposal; +pub(crate) mod r#update_program_metadata; +pub(crate) mod r#withdraw_governing_tokens; + +pub use self::r#add_required_signatory::*; +pub use self::r#add_signatory::*; +pub use self::r#cancel_proposal::*; +pub use self::r#cast_vote::*; +pub use self::r#complete_proposal::*; +pub use self::r#create_governance::*; +pub use self::r#create_mint_governance::*; +pub use self::r#create_native_treasury::*; +pub use self::r#create_program_governance::*; +pub use self::r#create_proposal::*; +pub use self::r#create_realm::*; +pub use self::r#create_token_governance::*; +pub use self::r#create_token_owner_record::*; +pub use self::r#deposit_governing_tokens::*; +pub use self::r#execute_transaction::*; +pub use self::r#finalize_vote::*; +pub use self::r#flag_transaction_error::*; +pub use self::r#insert_transaction::*; +pub use self::r#legacy1::*; +pub use self::r#refund_proposal_deposit::*; +pub use self::r#relinquish_vote::*; +pub use self::r#remove_required_signatory::*; +pub use self::r#remove_transaction::*; +pub use self::r#revoke_governing_tokens::*; +pub use self::r#set_governance_config::*; +pub use self::r#set_governance_delegate::*; +pub use self::r#set_realm_authority::*; +pub use self::r#set_realm_config::*; +pub use self::r#sign_off_proposal::*; +pub use self::r#update_program_metadata::*; +pub use self::r#withdraw_governing_tokens::*; diff --git a/e2e/governance/src/generated/instructions/refund_proposal_deposit.rs b/e2e/governance/src/generated/instructions/refund_proposal_deposit.rs new file mode 100644 index 0000000..cfc7b47 --- /dev/null +++ b/e2e/governance/src/generated/instructions/refund_proposal_deposit.rs @@ -0,0 +1,323 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const REFUND_PROPOSAL_DEPOSIT_DISCRIMINATOR: u8 = 27; + +/// Accounts. +#[derive(Debug)] +pub struct RefundProposalDeposit { + pub proposal_account: solana_address::Address, + /// PDA Seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: solana_address::Address, + /// Proposal Deposit Payer (beneficiary) account + pub proposal_deposit_payer: solana_address::Address, +} + +impl RefundProposalDeposit { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_deposit_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_deposit_payer, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = RefundProposalDepositInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RefundProposalDepositInstructionData { + discriminator: u8, +} + +impl RefundProposalDepositInstructionData { + pub fn new() -> Self { + Self { discriminator: 27 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for RefundProposalDepositInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `RefundProposalDeposit`. +/// +/// ### Accounts: +/// +/// 0. `[]` proposal_account +/// 1. `[writable]` proposal_deposit_account +/// 2. `[writable]` proposal_deposit_payer +#[derive(Clone, Debug)] +pub struct RefundProposalDepositBuilder { + proposal_account: solana_address::Address, + proposal_deposit_account: solana_address::Address, + proposal_deposit_payer: solana_address::Address, + __remaining_accounts: Vec, +} + +impl RefundProposalDepositBuilder { + pub fn new( + proposal_account: solana_address::Address, + proposal_deposit_account: solana_address::Address, + proposal_deposit_payer: solana_address::Address, + ) -> Self { + Self { + proposal_account, + proposal_deposit_account, + proposal_deposit_payer, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let proposal_account = self.proposal_account; + let proposal_deposit_account = self.proposal_deposit_account; + let proposal_deposit_payer = self.proposal_deposit_payer; + let accounts = RefundProposalDeposit { + proposal_account, + proposal_deposit_account, + proposal_deposit_payer, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `refund_proposal_deposit` CPI accounts. +pub struct RefundProposalDepositCpiAccounts<'a, 'b> { + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// PDA Seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: &'b solana_account_info::AccountInfo<'a>, + /// Proposal Deposit Payer (beneficiary) account + pub proposal_deposit_payer: &'b solana_account_info::AccountInfo<'a>, +} + +/// `refund_proposal_deposit` CPI instruction. +pub struct RefundProposalDepositCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// PDA Seeds: ['proposal-deposit', proposal, deposit payer] + pub proposal_deposit_account: &'b solana_account_info::AccountInfo<'a>, + /// Proposal Deposit Payer (beneficiary) account + pub proposal_deposit_payer: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> RefundProposalDepositCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: RefundProposalDepositCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + proposal_account: accounts.proposal_account, + proposal_deposit_account: accounts.proposal_deposit_account, + proposal_deposit_payer: accounts.proposal_deposit_payer, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_deposit_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_deposit_payer.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = RefundProposalDepositInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.proposal_deposit_account.clone()); + account_infos.push(self.proposal_deposit_payer.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RefundProposalDeposit` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` proposal_account +/// 1. `[writable]` proposal_deposit_account +/// 2. `[writable]` proposal_deposit_payer +#[derive(Clone, Debug)] +pub struct RefundProposalDepositCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RefundProposalDepositCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_deposit_account: &'b solana_account_info::AccountInfo<'a>, + proposal_deposit_payer: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(RefundProposalDepositCpiBuilderInstruction { + __program, + proposal_account, + proposal_deposit_account, + proposal_deposit_payer, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = RefundProposalDepositCpi { + __program: self.instruction.__program, + proposal_account: self.instruction.proposal_account, + proposal_deposit_account: self.instruction.proposal_deposit_account, + proposal_deposit_payer: self.instruction.proposal_deposit_payer, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RefundProposalDepositCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + proposal_deposit_account: &'b solana_account_info::AccountInfo<'a>, + proposal_deposit_payer: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/relinquish_vote.rs b/e2e/governance/src/generated/instructions/relinquish_vote.rs new file mode 100644 index 0000000..d326070 --- /dev/null +++ b/e2e/governance/src/generated/instructions/relinquish_vote.rs @@ -0,0 +1,525 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const RELINQUISH_VOTE_DISCRIMINATOR: u8 = 15; + +/// Accounts. +#[derive(Debug)] +pub struct RelinquishVote { + pub realm_account: solana_address::Address, + + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub token_owner_record: solana_address::Address, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record] + pub proposal_vote_record: solana_address::Address, + /// The Governing Token Mint which was used to cast the vote (vote_governing_token_mint) + pub governing_token_mint: solana_address::Address, + + pub governance_authority: Option, + /// Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed. + /// It's required only when Proposal is still being voted on + pub beneficiary_account: Option, +} + +impl RelinquishVote { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_vote_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint, + false, + )); + if let Some(governance_authority) = self.governance_authority { + accounts.push(solana_instruction::AccountMeta::new_readonly( + governance_authority, + true, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(beneficiary_account) = self.beneficiary_account { + accounts.push(solana_instruction::AccountMeta::new( + beneficiary_account, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let data = RelinquishVoteInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RelinquishVoteInstructionData { + discriminator: u8, +} + +impl RelinquishVoteInstructionData { + pub fn new() -> Self { + Self { discriminator: 15 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for RelinquishVoteInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `RelinquishVote`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[writable]` proposal_vote_record +/// 5. `[]` governing_token_mint +/// 6. `[signer, optional]` governance_authority +/// 7. `[writable, optional]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RelinquishVoteBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + proposal_vote_record: solana_address::Address, + governing_token_mint: solana_address::Address, + governance_authority: Option, + beneficiary_account: Option, + __remaining_accounts: Vec, +} + +impl RelinquishVoteBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + proposal_vote_record: solana_address::Address, + governing_token_mint: solana_address::Address, + ) -> Self { + Self { + realm_account, + governance_account, + proposal_account, + token_owner_record, + proposal_vote_record, + governing_token_mint, + governance_authority: None, + beneficiary_account: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account]` + #[inline(always)] + pub fn governance_authority( + &mut self, + governance_authority: Option, + ) -> &mut Self { + self.governance_authority = governance_authority; + self + } + /// `[optional account]` + /// Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed. + /// It's required only when Proposal is still being voted on + #[inline(always)] + pub fn beneficiary_account( + &mut self, + beneficiary_account: Option, + ) -> &mut Self { + self.beneficiary_account = beneficiary_account; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let proposal_vote_record = self.proposal_vote_record; + let governing_token_mint = self.governing_token_mint; + let governance_authority = self.governance_authority; + let beneficiary_account = self.beneficiary_account; + let accounts = RelinquishVote { + realm_account, + governance_account, + proposal_account, + token_owner_record, + proposal_vote_record, + governing_token_mint, + governance_authority, + beneficiary_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `relinquish_vote` CPI accounts. +pub struct RelinquishVoteCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record] + pub proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + /// The Governing Token Mint which was used to cast the vote (vote_governing_token_mint) + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed. + /// It's required only when Proposal is still being voted on + pub beneficiary_account: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `relinquish_vote` CPI instruction. +pub struct RelinquishVoteCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account. PDA seeds: ['governance',realm, vote_governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Proposal VoteRecord account. PDA seeds: ['governance',proposal, token_owner_record] + pub proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + /// The Governing Token Mint which was used to cast the vote (vote_governing_token_mint) + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + + pub governance_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed. + /// It's required only when Proposal is still being voted on + pub beneficiary_account: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +impl<'a, 'b> RelinquishVoteCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: RelinquishVoteCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + proposal_vote_record: accounts.proposal_vote_record, + governing_token_mint: accounts.governing_token_mint, + governance_authority: accounts.governance_authority, + beneficiary_account: accounts.beneficiary_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_vote_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint.key, + false, + )); + if let Some(governance_authority) = self.governance_authority { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *governance_authority.key, + true, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(beneficiary_account) = self.beneficiary_account { + accounts.push(solana_instruction::AccountMeta::new( + *beneficiary_account.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = RelinquishVoteInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.proposal_vote_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + if let Some(governance_authority) = self.governance_authority { + account_infos.push(governance_authority.clone()); + } + if let Some(beneficiary_account) = self.beneficiary_account { + account_infos.push(beneficiary_account.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RelinquishVote` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[writable]` token_owner_record +/// 4. `[writable]` proposal_vote_record +/// 5. `[]` governing_token_mint +/// 6. `[signer, optional]` governance_authority +/// 7. `[writable, optional]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RelinquishVoteCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RelinquishVoteCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(RelinquishVoteCpiBuilderInstruction { + __program, + realm_account, + governance_account, + proposal_account, + token_owner_record, + proposal_vote_record, + governing_token_mint, + governance_authority: None, + beneficiary_account: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + #[inline(always)] + pub fn governance_authority( + &mut self, + governance_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.governance_authority = governance_authority; + self + } + /// `[optional account]` + /// Optional Beneficiary account which would receive lamports when VoteRecord Account is disposed. + /// It's required only when Proposal is still being voted on + #[inline(always)] + pub fn beneficiary_account( + &mut self, + beneficiary_account: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.beneficiary_account = beneficiary_account; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = RelinquishVoteCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + proposal_vote_record: self.instruction.proposal_vote_record, + governing_token_mint: self.instruction.governing_token_mint, + governance_authority: self.instruction.governance_authority, + beneficiary_account: self.instruction.beneficiary_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RelinquishVoteCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + proposal_vote_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + governance_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + beneficiary_account: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/remove_required_signatory.rs b/e2e/governance/src/generated/instructions/remove_required_signatory.rs new file mode 100644 index 0000000..5a38470 --- /dev/null +++ b/e2e/governance/src/generated/instructions/remove_required_signatory.rs @@ -0,0 +1,323 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const REMOVE_REQUIRED_SIGNATORY_DISCRIMINATOR: u8 = 30; + +/// Accounts. +#[derive(Debug)] +pub struct RemoveRequiredSignatory { + pub governance_account: solana_address::Address, + + pub required_signatory_account: solana_address::Address, + /// Beneficiary Account which would receive lamports from the disposed RequiredSignatory Account + pub beneficiary_account: solana_address::Address, +} + +impl RemoveRequiredSignatory { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.required_signatory_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.beneficiary_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = RemoveRequiredSignatoryInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RemoveRequiredSignatoryInstructionData { + discriminator: u8, +} + +impl RemoveRequiredSignatoryInstructionData { + pub fn new() -> Self { + Self { discriminator: 30 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for RemoveRequiredSignatoryInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `RemoveRequiredSignatory`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +/// 1. `[writable]` required_signatory_account +/// 2. `[writable]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RemoveRequiredSignatoryBuilder { + governance_account: solana_address::Address, + required_signatory_account: solana_address::Address, + beneficiary_account: solana_address::Address, + __remaining_accounts: Vec, +} + +impl RemoveRequiredSignatoryBuilder { + pub fn new( + governance_account: solana_address::Address, + required_signatory_account: solana_address::Address, + beneficiary_account: solana_address::Address, + ) -> Self { + Self { + governance_account, + required_signatory_account, + beneficiary_account, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let required_signatory_account = self.required_signatory_account; + let beneficiary_account = self.beneficiary_account; + let accounts = RemoveRequiredSignatory { + governance_account, + required_signatory_account, + beneficiary_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `remove_required_signatory` CPI accounts. +pub struct RemoveRequiredSignatoryCpiAccounts<'a, 'b> { + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + /// Beneficiary Account which would receive lamports from the disposed RequiredSignatory Account + pub beneficiary_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `remove_required_signatory` CPI instruction. +pub struct RemoveRequiredSignatoryCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + /// Beneficiary Account which would receive lamports from the disposed RequiredSignatory Account + pub beneficiary_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> RemoveRequiredSignatoryCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: RemoveRequiredSignatoryCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + required_signatory_account: accounts.required_signatory_account, + beneficiary_account: accounts.beneficiary_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.required_signatory_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.beneficiary_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = RemoveRequiredSignatoryInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.required_signatory_account.clone()); + account_infos.push(self.beneficiary_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RemoveRequiredSignatory` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +/// 1. `[writable]` required_signatory_account +/// 2. `[writable]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RemoveRequiredSignatoryCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RemoveRequiredSignatoryCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + beneficiary_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(RemoveRequiredSignatoryCpiBuilderInstruction { + __program, + governance_account, + required_signatory_account, + beneficiary_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = RemoveRequiredSignatoryCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + required_signatory_account: self.instruction.required_signatory_account, + beneficiary_account: self.instruction.beneficiary_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RemoveRequiredSignatoryCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + required_signatory_account: &'b solana_account_info::AccountInfo<'a>, + beneficiary_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/remove_transaction.rs b/e2e/governance/src/generated/instructions/remove_transaction.rs new file mode 100644 index 0000000..f504e13 --- /dev/null +++ b/e2e/governance/src/generated/instructions/remove_transaction.rs @@ -0,0 +1,377 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const REMOVE_TRANSACTION_DISCRIMINATOR: u8 = 10; + +/// Accounts. +#[derive(Debug)] +pub struct RemoveTransaction { + pub proposal_account: solana_address::Address, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: solana_address::Address, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: solana_address::Address, + + pub proposal_transaction_account: solana_address::Address, + /// Beneficiary Account which would receive lamports from the disposed ProposalTransaction account + pub beneficiary_account: solana_address::Address, +} + +impl RemoveTransaction { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_transaction_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.beneficiary_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = RemoveTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RemoveTransactionInstructionData { + discriminator: u8, +} + +impl RemoveTransactionInstructionData { + pub fn new() -> Self { + Self { discriminator: 10 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for RemoveTransactionInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `RemoveTransaction`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` proposal_transaction_account +/// 4. `[writable]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RemoveTransactionBuilder { + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + beneficiary_account: solana_address::Address, + __remaining_accounts: Vec, +} + +impl RemoveTransactionBuilder { + pub fn new( + proposal_account: solana_address::Address, + token_owner_record: solana_address::Address, + governance_authority: solana_address::Address, + proposal_transaction_account: solana_address::Address, + beneficiary_account: solana_address::Address, + ) -> Self { + Self { + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + beneficiary_account, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let proposal_account = self.proposal_account; + let token_owner_record = self.token_owner_record; + let governance_authority = self.governance_authority; + let proposal_transaction_account = self.proposal_transaction_account; + let beneficiary_account = self.beneficiary_account; + let accounts = RemoveTransaction { + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + beneficiary_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `remove_transaction` CPI accounts. +pub struct RemoveTransactionCpiAccounts<'a, 'b> { + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + /// Beneficiary Account which would receive lamports from the disposed ProposalTransaction account + pub beneficiary_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `remove_transaction` CPI instruction. +pub struct RemoveTransactionCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord account of the Proposal owner + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Governance Authority (Token Owner or Governance Delegate) + pub governance_authority: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + /// Beneficiary Account which would receive lamports from the disposed ProposalTransaction account + pub beneficiary_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> RemoveTransactionCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: RemoveTransactionCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + proposal_account: accounts.proposal_account, + token_owner_record: accounts.token_owner_record, + governance_authority: accounts.governance_authority, + proposal_transaction_account: accounts.proposal_transaction_account, + beneficiary_account: accounts.beneficiary_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_transaction_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.beneficiary_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = RemoveTransactionInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governance_authority.clone()); + account_infos.push(self.proposal_transaction_account.clone()); + account_infos.push(self.beneficiary_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RemoveTransaction` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` proposal_account +/// 1. `[]` token_owner_record +/// 2. `[signer]` governance_authority +/// 3. `[writable]` proposal_transaction_account +/// 4. `[writable]` beneficiary_account +#[derive(Clone, Debug)] +pub struct RemoveTransactionCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RemoveTransactionCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + beneficiary_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(RemoveTransactionCpiBuilderInstruction { + __program, + proposal_account, + token_owner_record, + governance_authority, + proposal_transaction_account, + beneficiary_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = RemoveTransactionCpi { + __program: self.instruction.__program, + proposal_account: self.instruction.proposal_account, + token_owner_record: self.instruction.token_owner_record, + governance_authority: self.instruction.governance_authority, + proposal_transaction_account: self.instruction.proposal_transaction_account, + beneficiary_account: self.instruction.beneficiary_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RemoveTransactionCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governance_authority: &'b solana_account_info::AccountInfo<'a>, + proposal_transaction_account: &'b solana_account_info::AccountInfo<'a>, + beneficiary_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/revoke_governing_tokens.rs b/e2e/governance/src/generated/instructions/revoke_governing_tokens.rs new file mode 100644 index 0000000..c7efa2f --- /dev/null +++ b/e2e/governance/src/generated/instructions/revoke_governing_tokens.rs @@ -0,0 +1,478 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const REVOKE_GOVERNING_TOKENS_DISCRIMINATOR: u8 = 26; + +/// Accounts. +#[derive(Debug)] +pub struct RevokeGoverningTokens { + pub realm_account: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: solana_address::Address, + + pub governing_token_mint: solana_address::Address, + /// GoverningTokenMint mint_authority + pub governing_token_mint_authority_or_token_owner: solana_address::Address, + /// seeds=['realm-config', realm] + pub realm_config_account: solana_address::Address, + + pub token_program: solana_address::Address, +} + +impl RevokeGoverningTokens { + pub fn instruction( + &self, + args: RevokeGoverningTokensInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: RevokeGoverningTokensInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_holding_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_mint_authority_or_token_owner, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = RevokeGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RevokeGoverningTokensInstructionData { + discriminator: u8, +} + +impl RevokeGoverningTokensInstructionData { + pub fn new() -> Self { + Self { discriminator: 26 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for RevokeGoverningTokensInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RevokeGoverningTokensInstructionArgs { + pub amount: u64, +} + +impl RevokeGoverningTokensInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `RevokeGoverningTokens`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` token_owner_record +/// 3. `[writable]` governing_token_mint +/// 4. `[signer]` governing_token_mint_authority_or_token_owner +/// 5. `[]` realm_config_account +/// 6. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +#[derive(Clone, Debug)] +pub struct RevokeGoverningTokensBuilder { + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + governing_token_mint_authority_or_token_owner: solana_address::Address, + realm_config_account: solana_address::Address, + token_program: Option, + amount: u64, + __remaining_accounts: Vec, +} + +impl RevokeGoverningTokensBuilder { + pub fn new( + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + token_owner_record: solana_address::Address, + governing_token_mint: solana_address::Address, + governing_token_mint_authority_or_token_owner: solana_address::Address, + realm_config_account: solana_address::Address, + amount: u64, + ) -> Self { + Self { + realm_account, + governing_token_holding_account, + token_owner_record, + governing_token_mint, + governing_token_mint_authority_or_token_owner, + realm_config_account, + token_program: None, + amount, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governing_token_holding_account = self.governing_token_holding_account; + let token_owner_record = self.token_owner_record; + let governing_token_mint = self.governing_token_mint; + let governing_token_mint_authority_or_token_owner = + self.governing_token_mint_authority_or_token_owner; + let realm_config_account = self.realm_config_account; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let accounts = RevokeGoverningTokens { + realm_account, + governing_token_holding_account, + token_owner_record, + governing_token_mint, + governing_token_mint_authority_or_token_owner, + realm_config_account, + token_program, + }; + let args = RevokeGoverningTokensInstructionArgs { + amount: self.amount.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `revoke_governing_tokens` CPI accounts. +pub struct RevokeGoverningTokensCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// GoverningTokenMint mint_authority + pub governing_token_mint_authority_or_token_owner: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `revoke_governing_tokens` CPI instruction. +pub struct RevokeGoverningTokensCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// GoverningTokenMint mint_authority + pub governing_token_mint_authority_or_token_owner: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: RevokeGoverningTokensInstructionArgs, +} + +impl<'a, 'b> RevokeGoverningTokensCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: RevokeGoverningTokensCpiAccounts<'a, 'b>, + args: RevokeGoverningTokensInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governing_token_holding_account: accounts.governing_token_holding_account, + token_owner_record: accounts.token_owner_record, + governing_token_mint: accounts.governing_token_mint, + governing_token_mint_authority_or_token_owner: accounts + .governing_token_mint_authority_or_token_owner, + realm_config_account: accounts.realm_config_account, + token_program: accounts.token_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_holding_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_mint_authority_or_token_owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = RevokeGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(8 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governing_token_holding_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.governing_token_mint.clone()); + account_infos.push(self.governing_token_mint_authority_or_token_owner.clone()); + account_infos.push(self.realm_config_account.clone()); + account_infos.push(self.token_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RevokeGoverningTokens` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` token_owner_record +/// 3. `[writable]` governing_token_mint +/// 4. `[signer]` governing_token_mint_authority_or_token_owner +/// 5. `[]` realm_config_account +/// 6. `[]` token_program +#[derive(Clone, Debug)] +pub struct RevokeGoverningTokensCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RevokeGoverningTokensCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint_authority_or_token_owner: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + ) -> Self { + let instruction = Box::new(RevokeGoverningTokensCpiBuilderInstruction { + __program, + realm_account, + governing_token_holding_account, + token_owner_record, + governing_token_mint, + governing_token_mint_authority_or_token_owner, + realm_config_account, + token_program, + amount, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = RevokeGoverningTokensInstructionArgs { + amount: self.instruction.amount.clone(), + }; + let instruction = RevokeGoverningTokensCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governing_token_holding_account: self.instruction.governing_token_holding_account, + token_owner_record: self.instruction.token_owner_record, + governing_token_mint: self.instruction.governing_token_mint, + governing_token_mint_authority_or_token_owner: self + .instruction + .governing_token_mint_authority_or_token_owner, + realm_config_account: self.instruction.realm_config_account, + token_program: self.instruction.token_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RevokeGoverningTokensCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint: &'b solana_account_info::AccountInfo<'a>, + governing_token_mint_authority_or_token_owner: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/set_governance_config.rs b/e2e/governance/src/generated/instructions/set_governance_config.rs new file mode 100644 index 0000000..9238d3b --- /dev/null +++ b/e2e/governance/src/generated/instructions/set_governance_config.rs @@ -0,0 +1,303 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GovernanceConfig; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const SET_GOVERNANCE_CONFIG_DISCRIMINATOR: u8 = 19; + +/// Accounts. +#[derive(Debug)] +pub struct SetGovernanceConfig { + /// The governance account the config is for + pub governance_account: solana_address::Address, +} + +impl SetGovernanceConfig { + pub fn instruction( + &self, + args: SetGovernanceConfigInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: SetGovernanceConfigInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(1 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.governance_account, + true, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SetGovernanceConfigInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetGovernanceConfigInstructionData { + discriminator: u8, +} + +impl SetGovernanceConfigInstructionData { + pub fn new() -> Self { + Self { discriminator: 19 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SetGovernanceConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetGovernanceConfigInstructionArgs { + pub config: GovernanceConfig, +} + +impl SetGovernanceConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SetGovernanceConfig`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +#[derive(Clone, Debug)] +pub struct SetGovernanceConfigBuilder { + governance_account: solana_address::Address, + config: GovernanceConfig, + __remaining_accounts: Vec, +} + +impl SetGovernanceConfigBuilder { + pub fn new(governance_account: solana_address::Address, config: GovernanceConfig) -> Self { + Self { + governance_account, + config, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let governance_account = self.governance_account; + let accounts = SetGovernanceConfig { governance_account }; + let args = SetGovernanceConfigInstructionArgs { + config: self.config.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `set_governance_config` CPI accounts. +pub struct SetGovernanceConfigCpiAccounts<'a, 'b> { + /// The governance account the config is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `set_governance_config` CPI instruction. +pub struct SetGovernanceConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The governance account the config is for + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SetGovernanceConfigInstructionArgs, +} + +impl<'a, 'b> SetGovernanceConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SetGovernanceConfigCpiAccounts<'a, 'b>, + args: SetGovernanceConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + governance_account: accounts.governance_account, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(1 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.governance_account.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = SetGovernanceConfigInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(2 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.governance_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetGovernanceConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` governance_account +#[derive(Clone, Debug)] +pub struct SetGovernanceConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetGovernanceConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + ) -> Self { + let instruction = Box::new(SetGovernanceConfigCpiBuilderInstruction { + __program, + governance_account, + config, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = SetGovernanceConfigInstructionArgs { + config: self.instruction.config.clone(), + }; + let instruction = SetGovernanceConfigCpi { + __program: self.instruction.__program, + governance_account: self.instruction.governance_account, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetGovernanceConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + config: GovernanceConfig, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/set_governance_delegate.rs b/e2e/governance/src/generated/instructions/set_governance_delegate.rs new file mode 100644 index 0000000..4bf5d9d --- /dev/null +++ b/e2e/governance/src/generated/instructions/set_governance_delegate.rs @@ -0,0 +1,345 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +pub const SET_GOVERNANCE_DELEGATE_DISCRIMINATOR: u8 = 3; + +/// Accounts. +#[derive(Debug)] +pub struct SetGovernanceDelegate { + /// Current governance delegate or governing token owner + pub current_delegate_or_owner: solana_address::Address, + + pub token_owner_record: solana_address::Address, +} + +impl SetGovernanceDelegate { + pub fn instruction( + &self, + args: SetGovernanceDelegateInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: SetGovernanceDelegateInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.current_delegate_or_owner, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SetGovernanceDelegateInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetGovernanceDelegateInstructionData { + discriminator: u8, +} + +impl SetGovernanceDelegateInstructionData { + pub fn new() -> Self { + Self { discriminator: 3 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SetGovernanceDelegateInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetGovernanceDelegateInstructionArgs { + pub new_governance_delegate: Option
, +} + +impl SetGovernanceDelegateInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SetGovernanceDelegate`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` current_delegate_or_owner +/// 1. `[writable]` token_owner_record +#[derive(Clone, Debug)] +pub struct SetGovernanceDelegateBuilder { + current_delegate_or_owner: solana_address::Address, + token_owner_record: solana_address::Address, + new_governance_delegate: Option
, + __remaining_accounts: Vec, +} + +impl SetGovernanceDelegateBuilder { + pub fn new( + current_delegate_or_owner: solana_address::Address, + token_owner_record: solana_address::Address, + ) -> Self { + Self { + current_delegate_or_owner, + token_owner_record, + new_governance_delegate: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional argument]` + #[inline(always)] + pub fn new_governance_delegate(&mut self, new_governance_delegate: Address) -> &mut Self { + self.new_governance_delegate = Some(new_governance_delegate); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let current_delegate_or_owner = self.current_delegate_or_owner; + let token_owner_record = self.token_owner_record; + let accounts = SetGovernanceDelegate { + current_delegate_or_owner, + token_owner_record, + }; + let args = SetGovernanceDelegateInstructionArgs { + new_governance_delegate: self.new_governance_delegate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `set_governance_delegate` CPI accounts. +pub struct SetGovernanceDelegateCpiAccounts<'a, 'b> { + /// Current governance delegate or governing token owner + pub current_delegate_or_owner: &'b solana_account_info::AccountInfo<'a>, + + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, +} + +/// `set_governance_delegate` CPI instruction. +pub struct SetGovernanceDelegateCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Current governance delegate or governing token owner + pub current_delegate_or_owner: &'b solana_account_info::AccountInfo<'a>, + + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SetGovernanceDelegateInstructionArgs, +} + +impl<'a, 'b> SetGovernanceDelegateCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SetGovernanceDelegateCpiAccounts<'a, 'b>, + args: SetGovernanceDelegateInstructionArgs, + ) -> Self { + Self { + __program: program, + current_delegate_or_owner: accounts.current_delegate_or_owner, + token_owner_record: accounts.token_owner_record, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.current_delegate_or_owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = SetGovernanceDelegateInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(3 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.current_delegate_or_owner.clone()); + account_infos.push(self.token_owner_record.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetGovernanceDelegate` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` current_delegate_or_owner +/// 1. `[writable]` token_owner_record +#[derive(Clone, Debug)] +pub struct SetGovernanceDelegateCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetGovernanceDelegateCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + current_delegate_or_owner: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(SetGovernanceDelegateCpiBuilderInstruction { + __program, + current_delegate_or_owner, + token_owner_record, + new_governance_delegate: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional argument]` + #[inline(always)] + pub fn new_governance_delegate(&mut self, new_governance_delegate: Address) -> &mut Self { + self.instruction.new_governance_delegate = Some(new_governance_delegate); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = SetGovernanceDelegateInstructionArgs { + new_governance_delegate: self.instruction.new_governance_delegate.clone(), + }; + let instruction = SetGovernanceDelegateCpi { + __program: self.instruction.__program, + current_delegate_or_owner: self.instruction.current_delegate_or_owner, + token_owner_record: self.instruction.token_owner_record, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetGovernanceDelegateCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + current_delegate_or_owner: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + new_governance_delegate: Option
, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/set_realm_authority.rs b/e2e/governance/src/generated/instructions/set_realm_authority.rs new file mode 100644 index 0000000..7c5bece --- /dev/null +++ b/e2e/governance/src/generated/instructions/set_realm_authority.rs @@ -0,0 +1,394 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::SetRealmAuthorityAction; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const SET_REALM_AUTHORITY_DISCRIMINATOR: u8 = 21; + +/// Accounts. +#[derive(Debug)] +pub struct SetRealmAuthority { + pub realm_account: solana_address::Address, + + pub realm_authority: solana_address::Address, + /// Must be one of the realm governances when set + pub new_realm_authority: Option, +} + +impl SetRealmAuthority { + pub fn instruction( + &self, + args: SetRealmAuthorityInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: SetRealmAuthorityInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_authority, + true, + )); + if let Some(new_realm_authority) = self.new_realm_authority { + accounts.push(solana_instruction::AccountMeta::new_readonly( + new_realm_authority, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = SetRealmAuthorityInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetRealmAuthorityInstructionData { + discriminator: u8, +} + +impl SetRealmAuthorityInstructionData { + pub fn new() -> Self { + Self { discriminator: 21 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SetRealmAuthorityInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetRealmAuthorityInstructionArgs { + pub action: SetRealmAuthorityAction, +} + +impl SetRealmAuthorityInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SetRealmAuthority`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[signer]` realm_authority +/// 2. `[optional]` new_realm_authority +#[derive(Clone, Debug)] +pub struct SetRealmAuthorityBuilder { + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + new_realm_authority: Option, + action: SetRealmAuthorityAction, + __remaining_accounts: Vec, +} + +impl SetRealmAuthorityBuilder { + pub fn new( + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + action: SetRealmAuthorityAction, + ) -> Self { + Self { + realm_account, + realm_authority, + new_realm_authority: None, + action, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account]` + /// Must be one of the realm governances when set + #[inline(always)] + pub fn new_realm_authority( + &mut self, + new_realm_authority: Option, + ) -> &mut Self { + self.new_realm_authority = new_realm_authority; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let realm_authority = self.realm_authority; + let new_realm_authority = self.new_realm_authority; + let accounts = SetRealmAuthority { + realm_account, + realm_authority, + new_realm_authority, + }; + let args = SetRealmAuthorityInstructionArgs { + action: self.action.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `set_realm_authority` CPI accounts. +pub struct SetRealmAuthorityCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// Must be one of the realm governances when set + pub new_realm_authority: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `set_realm_authority` CPI instruction. +pub struct SetRealmAuthorityCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// Must be one of the realm governances when set + pub new_realm_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: SetRealmAuthorityInstructionArgs, +} + +impl<'a, 'b> SetRealmAuthorityCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SetRealmAuthorityCpiAccounts<'a, 'b>, + args: SetRealmAuthorityInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + realm_authority: accounts.realm_authority, + new_realm_authority: accounts.new_realm_authority, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_authority.key, + true, + )); + if let Some(new_realm_authority) = self.new_realm_authority { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *new_realm_authority.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = SetRealmAuthorityInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.realm_authority.clone()); + if let Some(new_realm_authority) = self.new_realm_authority { + account_infos.push(new_realm_authority.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetRealmAuthority` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[signer]` realm_authority +/// 2. `[optional]` new_realm_authority +#[derive(Clone, Debug)] +pub struct SetRealmAuthorityCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetRealmAuthorityCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + action: SetRealmAuthorityAction, + ) -> Self { + let instruction = Box::new(SetRealmAuthorityCpiBuilderInstruction { + __program, + realm_account, + realm_authority, + new_realm_authority: None, + action, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Must be one of the realm governances when set + #[inline(always)] + pub fn new_realm_authority( + &mut self, + new_realm_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.new_realm_authority = new_realm_authority; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = SetRealmAuthorityInstructionArgs { + action: self.instruction.action.clone(), + }; + let instruction = SetRealmAuthorityCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + realm_authority: self.instruction.realm_authority, + new_realm_authority: self.instruction.new_realm_authority, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetRealmAuthorityCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + new_realm_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + action: SetRealmAuthorityAction, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/set_realm_config.rs b/e2e/governance/src/generated/instructions/set_realm_config.rs new file mode 100644 index 0000000..7b559a3 --- /dev/null +++ b/e2e/governance/src/generated/instructions/set_realm_config.rs @@ -0,0 +1,868 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::RealmConfigParams; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const SET_REALM_CONFIG_DISCRIMINATOR: u8 = 22; + +/// Accounts. +#[derive(Debug)] +pub struct SetRealmConfig { + pub realm_account: solana_address::Address, + + pub realm_authority: solana_address::Address, + /// Council Token Mint - optional. + /// Note: In the current version it's only possible to remove council mint (set it to None) + /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. + /// If that's required then it must be done before executing this instruction + pub council_token_mint: Option, + /// Optional unless council is used. seeds=['governance', realm, council_mint] + pub council_token_holding_account: Option, + + pub system_program: solana_address::Address, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: solana_address::Address, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin_program_id: Option, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin_program_id: Option, + /// Optional Council Voter Weight Adding Program Id + pub council_voter_weight_addin_program_id: Option, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin_program_id: Option, + /// Optional Payer. Required if RealmConfig doesn't exist and needs to be created + pub payer: Option, +} + +impl SetRealmConfig { + pub fn instruction( + &self, + args: SetRealmConfigInstructionArgs, + ) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: SetRealmConfigInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_authority, + true, + )); + if let Some(council_token_mint) = self.council_token_mint { + accounts.push(solana_instruction::AccountMeta::new_readonly( + council_token_mint, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + accounts.push(solana_instruction::AccountMeta::new( + council_token_holding_account, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.realm_config, + false, + )); + if let Some(community_voter_weight_addin_program_id) = + self.community_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + community_voter_weight_addin_program_id, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_community_voter_weight_addin_program_id) = + self.max_community_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_community_voter_weight_addin_program_id, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_voter_weight_addin_program_id) = + self.council_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + council_voter_weight_addin_program_id, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_council_voter_weight_addin_program_id) = + self.max_council_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + max_council_voter_weight_addin_program_id, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(payer) = self.payer { + accounts.push(solana_instruction::AccountMeta::new_readonly(payer, true)); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = SetRealmConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetRealmConfigInstructionData { + discriminator: u8, +} + +impl SetRealmConfigInstructionData { + pub fn new() -> Self { + Self { discriminator: 22 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SetRealmConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SetRealmConfigInstructionArgs { + pub config_args: RealmConfigParams, +} + +impl SetRealmConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SetRealmConfig`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[signer]` realm_authority +/// 2. `[optional]` council_token_mint +/// 3. `[writable, optional]` council_token_holding_account +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 5. `[writable]` realm_config +/// 6. `[optional]` community_voter_weight_addin_program_id +/// 7. `[optional]` max_community_voter_weight_addin_program_id +/// 8. `[optional]` council_voter_weight_addin_program_id +/// 9. `[optional]` max_council_voter_weight_addin_program_id +/// 10. `[signer, optional]` payer +#[derive(Clone, Debug)] +pub struct SetRealmConfigBuilder { + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + council_token_mint: Option, + council_token_holding_account: Option, + system_program: Option, + realm_config: solana_address::Address, + community_voter_weight_addin_program_id: Option, + max_community_voter_weight_addin_program_id: Option, + council_voter_weight_addin_program_id: Option, + max_council_voter_weight_addin_program_id: Option, + payer: Option, + config_args: RealmConfigParams, + __remaining_accounts: Vec, +} + +impl SetRealmConfigBuilder { + pub fn new( + realm_account: solana_address::Address, + realm_authority: solana_address::Address, + realm_config: solana_address::Address, + config_args: RealmConfigParams, + ) -> Self { + Self { + realm_account, + realm_authority, + council_token_mint: None, + council_token_holding_account: None, + system_program: None, + realm_config, + community_voter_weight_addin_program_id: None, + max_community_voter_weight_addin_program_id: None, + council_voter_weight_addin_program_id: None, + max_council_voter_weight_addin_program_id: None, + payer: None, + config_args, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account]` + /// Council Token Mint - optional. + /// Note: In the current version it's only possible to remove council mint (set it to None) + /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. + /// If that's required then it must be done before executing this instruction + #[inline(always)] + pub fn council_token_mint( + &mut self, + council_token_mint: Option, + ) -> &mut Self { + self.council_token_mint = council_token_mint; + self + } + /// `[optional account]` + /// Optional unless council is used. seeds=['governance', realm, council_mint] + #[inline(always)] + pub fn council_token_holding_account( + &mut self, + council_token_holding_account: Option, + ) -> &mut Self { + self.council_token_holding_account = council_token_holding_account; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// Optional Community Voter Weight Addin Program Id + #[inline(always)] + pub fn community_voter_weight_addin_program_id( + &mut self, + community_voter_weight_addin_program_id: Option, + ) -> &mut Self { + self.community_voter_weight_addin_program_id = community_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Max Community Voter Weight Addin Program Id + #[inline(always)] + pub fn max_community_voter_weight_addin_program_id( + &mut self, + max_community_voter_weight_addin_program_id: Option, + ) -> &mut Self { + self.max_community_voter_weight_addin_program_id = + max_community_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Council Voter Weight Adding Program Id + #[inline(always)] + pub fn council_voter_weight_addin_program_id( + &mut self, + council_voter_weight_addin_program_id: Option, + ) -> &mut Self { + self.council_voter_weight_addin_program_id = council_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Max Council Voter Weight Addin Program Id + #[inline(always)] + pub fn max_council_voter_weight_addin_program_id( + &mut self, + max_council_voter_weight_addin_program_id: Option, + ) -> &mut Self { + self.max_council_voter_weight_addin_program_id = max_council_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Payer. Required if RealmConfig doesn't exist and needs to be created + #[inline(always)] + pub fn payer(&mut self, payer: Option) -> &mut Self { + self.payer = payer; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let realm_authority = self.realm_authority; + let council_token_mint = self.council_token_mint; + let council_token_holding_account = self.council_token_holding_account; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let realm_config = self.realm_config; + let community_voter_weight_addin_program_id = self.community_voter_weight_addin_program_id; + let max_community_voter_weight_addin_program_id = + self.max_community_voter_weight_addin_program_id; + let council_voter_weight_addin_program_id = self.council_voter_weight_addin_program_id; + let max_council_voter_weight_addin_program_id = + self.max_council_voter_weight_addin_program_id; + let payer = self.payer; + let accounts = SetRealmConfig { + realm_account, + realm_authority, + council_token_mint, + council_token_holding_account, + system_program, + realm_config, + community_voter_weight_addin_program_id, + max_community_voter_weight_addin_program_id, + council_voter_weight_addin_program_id, + max_council_voter_weight_addin_program_id, + payer, + }; + let args = SetRealmConfigInstructionArgs { + config_args: self.config_args.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `set_realm_config` CPI accounts. +pub struct SetRealmConfigCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// Council Token Mint - optional. + /// Note: In the current version it's only possible to remove council mint (set it to None) + /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. + /// If that's required then it must be done before executing this instruction + pub council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional unless council is used. seeds=['governance', realm, council_mint] + pub council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin_program_id: + Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Council Voter Weight Adding Program Id + pub council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Payer. Required if RealmConfig doesn't exist and needs to be created + pub payer: Option<&'b solana_account_info::AccountInfo<'a>>, +} + +/// `set_realm_config` CPI instruction. +pub struct SetRealmConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub realm_authority: &'b solana_account_info::AccountInfo<'a>, + /// Council Token Mint - optional. + /// Note: In the current version it's only possible to remove council mint (set it to None) + /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. + /// If that's required then it must be done before executing this instruction + pub council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional unless council is used. seeds=['governance', realm, council_mint] + pub council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// RealmConfig account. seeds=['realm-config', realm] + pub realm_config: &'b solana_account_info::AccountInfo<'a>, + /// Optional Community Voter Weight Addin Program Id + pub community_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Community Voter Weight Addin Program Id + pub max_community_voter_weight_addin_program_id: + Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Council Voter Weight Adding Program Id + pub council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Max Council Voter Weight Addin Program Id + pub max_council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + /// Optional Payer. Required if RealmConfig doesn't exist and needs to be created + pub payer: Option<&'b solana_account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: SetRealmConfigInstructionArgs, +} + +impl<'a, 'b> SetRealmConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SetRealmConfigCpiAccounts<'a, 'b>, + args: SetRealmConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + realm_authority: accounts.realm_authority, + council_token_mint: accounts.council_token_mint, + council_token_holding_account: accounts.council_token_holding_account, + system_program: accounts.system_program, + realm_config: accounts.realm_config, + community_voter_weight_addin_program_id: accounts + .community_voter_weight_addin_program_id, + max_community_voter_weight_addin_program_id: accounts + .max_community_voter_weight_addin_program_id, + council_voter_weight_addin_program_id: accounts.council_voter_weight_addin_program_id, + max_council_voter_weight_addin_program_id: accounts + .max_council_voter_weight_addin_program_id, + payer: accounts.payer, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(11 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_authority.key, + true, + )); + if let Some(council_token_mint) = self.council_token_mint { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *council_token_mint.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + accounts.push(solana_instruction::AccountMeta::new( + *council_token_holding_account.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.realm_config.key, + false, + )); + if let Some(community_voter_weight_addin_program_id) = + self.community_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *community_voter_weight_addin_program_id.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_community_voter_weight_addin_program_id) = + self.max_community_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_community_voter_weight_addin_program_id.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(council_voter_weight_addin_program_id) = + self.council_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *council_voter_weight_addin_program_id.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(max_council_voter_weight_addin_program_id) = + self.max_council_voter_weight_addin_program_id + { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *max_council_voter_weight_addin_program_id.key, + false, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + if let Some(payer) = self.payer { + accounts.push(solana_instruction::AccountMeta::new_readonly( + *payer.key, true, + )); + } else { + accounts.push(solana_instruction::AccountMeta::new_readonly( + crate::SPL_GOVERNANCE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = SetRealmConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(12 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.realm_authority.clone()); + if let Some(council_token_mint) = self.council_token_mint { + account_infos.push(council_token_mint.clone()); + } + if let Some(council_token_holding_account) = self.council_token_holding_account { + account_infos.push(council_token_holding_account.clone()); + } + account_infos.push(self.system_program.clone()); + account_infos.push(self.realm_config.clone()); + if let Some(community_voter_weight_addin_program_id) = + self.community_voter_weight_addin_program_id + { + account_infos.push(community_voter_weight_addin_program_id.clone()); + } + if let Some(max_community_voter_weight_addin_program_id) = + self.max_community_voter_weight_addin_program_id + { + account_infos.push(max_community_voter_weight_addin_program_id.clone()); + } + if let Some(council_voter_weight_addin_program_id) = + self.council_voter_weight_addin_program_id + { + account_infos.push(council_voter_weight_addin_program_id.clone()); + } + if let Some(max_council_voter_weight_addin_program_id) = + self.max_council_voter_weight_addin_program_id + { + account_infos.push(max_council_voter_weight_addin_program_id.clone()); + } + if let Some(payer) = self.payer { + account_infos.push(payer.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetRealmConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` realm_account +/// 1. `[signer]` realm_authority +/// 2. `[optional]` council_token_mint +/// 3. `[writable, optional]` council_token_holding_account +/// 4. `[]` system_program +/// 5. `[writable]` realm_config +/// 6. `[optional]` community_voter_weight_addin_program_id +/// 7. `[optional]` max_community_voter_weight_addin_program_id +/// 8. `[optional]` council_voter_weight_addin_program_id +/// 9. `[optional]` max_council_voter_weight_addin_program_id +/// 10. `[signer, optional]` payer +#[derive(Clone, Debug)] +pub struct SetRealmConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetRealmConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + config_args: RealmConfigParams, + ) -> Self { + let instruction = Box::new(SetRealmConfigCpiBuilderInstruction { + __program, + realm_account, + realm_authority, + council_token_mint: None, + council_token_holding_account: None, + system_program, + realm_config, + community_voter_weight_addin_program_id: None, + max_community_voter_weight_addin_program_id: None, + council_voter_weight_addin_program_id: None, + max_council_voter_weight_addin_program_id: None, + payer: None, + config_args, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// `[optional account]` + /// Council Token Mint - optional. + /// Note: In the current version it's only possible to remove council mint (set it to None) + /// After setting council to None it won't be possible to withdraw the tokens from the Realm any longer. + /// If that's required then it must be done before executing this instruction + #[inline(always)] + pub fn council_token_mint( + &mut self, + council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_token_mint = council_token_mint; + self + } + /// `[optional account]` + /// Optional unless council is used. seeds=['governance', realm, council_mint] + #[inline(always)] + pub fn council_token_holding_account( + &mut self, + council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_token_holding_account = council_token_holding_account; + self + } + /// `[optional account]` + /// Optional Community Voter Weight Addin Program Id + #[inline(always)] + pub fn community_voter_weight_addin_program_id( + &mut self, + community_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.community_voter_weight_addin_program_id = + community_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Max Community Voter Weight Addin Program Id + #[inline(always)] + pub fn max_community_voter_weight_addin_program_id( + &mut self, + max_community_voter_weight_addin_program_id: Option< + &'b solana_account_info::AccountInfo<'a>, + >, + ) -> &mut Self { + self.instruction.max_community_voter_weight_addin_program_id = + max_community_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Council Voter Weight Adding Program Id + #[inline(always)] + pub fn council_voter_weight_addin_program_id( + &mut self, + council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.council_voter_weight_addin_program_id = + council_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Max Council Voter Weight Addin Program Id + #[inline(always)] + pub fn max_council_voter_weight_addin_program_id( + &mut self, + max_council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.max_council_voter_weight_addin_program_id = + max_council_voter_weight_addin_program_id; + self + } + /// `[optional account]` + /// Optional Payer. Required if RealmConfig doesn't exist and needs to be created + #[inline(always)] + pub fn payer(&mut self, payer: Option<&'b solana_account_info::AccountInfo<'a>>) -> &mut Self { + self.instruction.payer = payer; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let args = SetRealmConfigInstructionArgs { + config_args: self.instruction.config_args.clone(), + }; + let instruction = SetRealmConfigCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + realm_authority: self.instruction.realm_authority, + council_token_mint: self.instruction.council_token_mint, + council_token_holding_account: self.instruction.council_token_holding_account, + system_program: self.instruction.system_program, + realm_config: self.instruction.realm_config, + community_voter_weight_addin_program_id: self + .instruction + .community_voter_weight_addin_program_id, + max_community_voter_weight_addin_program_id: self + .instruction + .max_community_voter_weight_addin_program_id, + council_voter_weight_addin_program_id: self + .instruction + .council_voter_weight_addin_program_id, + max_council_voter_weight_addin_program_id: self + .instruction + .max_council_voter_weight_addin_program_id, + payer: self.instruction.payer, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetRealmConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + realm_authority: &'b solana_account_info::AccountInfo<'a>, + council_token_mint: Option<&'b solana_account_info::AccountInfo<'a>>, + council_token_holding_account: Option<&'b solana_account_info::AccountInfo<'a>>, + system_program: &'b solana_account_info::AccountInfo<'a>, + realm_config: &'b solana_account_info::AccountInfo<'a>, + community_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + max_community_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + max_council_voter_weight_addin_program_id: Option<&'b solana_account_info::AccountInfo<'a>>, + payer: Option<&'b solana_account_info::AccountInfo<'a>>, + config_args: RealmConfigParams, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/sign_off_proposal.rs b/e2e/governance/src/generated/instructions/sign_off_proposal.rs new file mode 100644 index 0000000..b2eec5d --- /dev/null +++ b/e2e/governance/src/generated/instructions/sign_off_proposal.rs @@ -0,0 +1,379 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const SIGN_OFF_PROPOSAL_DISCRIMINATOR: u8 = 12; + +/// Accounts. +#[derive(Debug)] +pub struct SignOffProposal { + pub realm_account: solana_address::Address, + + pub governance_account: solana_address::Address, + + pub proposal_account: solana_address::Address, + /// Signatory account signing off the Proposal. + /// Or Proposal owner if the owner hasn't appointed any signatories + pub signatory_account: solana_address::Address, + /// TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal. + /// Or `[writable]` SignatoryRecord account, required when non owner signs off the Proposal + pub token_owner_record: solana_address::Address, +} + +impl SignOffProposal { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governance_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.proposal_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.signatory_account, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = SignOffProposalInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SignOffProposalInstructionData { + discriminator: u8, +} + +impl SignOffProposalInstructionData { + pub fn new() -> Self { + Self { discriminator: 12 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SignOffProposalInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `SignOffProposal`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[signer]` signatory_account +/// 4. `[writable]` token_owner_record +#[derive(Clone, Debug)] +pub struct SignOffProposalBuilder { + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + signatory_account: solana_address::Address, + token_owner_record: solana_address::Address, + __remaining_accounts: Vec, +} + +impl SignOffProposalBuilder { + pub fn new( + realm_account: solana_address::Address, + governance_account: solana_address::Address, + proposal_account: solana_address::Address, + signatory_account: solana_address::Address, + token_owner_record: solana_address::Address, + ) -> Self { + Self { + realm_account, + governance_account, + proposal_account, + signatory_account, + token_owner_record, + __remaining_accounts: Vec::new(), + } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governance_account = self.governance_account; + let proposal_account = self.proposal_account; + let signatory_account = self.signatory_account; + let token_owner_record = self.token_owner_record; + let accounts = SignOffProposal { + realm_account, + governance_account, + proposal_account, + signatory_account, + token_owner_record, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `sign_off_proposal` CPI accounts. +pub struct SignOffProposalCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// Signatory account signing off the Proposal. + /// Or Proposal owner if the owner hasn't appointed any signatories + pub signatory_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal. + /// Or `[writable]` SignatoryRecord account, required when non owner signs off the Proposal + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, +} + +/// `sign_off_proposal` CPI instruction. +pub struct SignOffProposalCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + + pub governance_account: &'b solana_account_info::AccountInfo<'a>, + + pub proposal_account: &'b solana_account_info::AccountInfo<'a>, + /// Signatory account signing off the Proposal. + /// Or Proposal owner if the owner hasn't appointed any signatories + pub signatory_account: &'b solana_account_info::AccountInfo<'a>, + /// TokenOwnerRecord for the Proposal owner, required when the owner signs off the Proposal. + /// Or `[writable]` SignatoryRecord account, required when non owner signs off the Proposal + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> SignOffProposalCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SignOffProposalCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governance_account: accounts.governance_account, + proposal_account: accounts.proposal_account, + signatory_account: accounts.signatory_account, + token_owner_record: accounts.token_owner_record, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governance_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.proposal_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.signatory_account.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = SignOffProposalInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governance_account.clone()); + account_infos.push(self.proposal_account.clone()); + account_infos.push(self.signatory_account.clone()); + account_infos.push(self.token_owner_record.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SignOffProposal` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[]` governance_account +/// 2. `[writable]` proposal_account +/// 3. `[signer]` signatory_account +/// 4. `[writable]` token_owner_record +#[derive(Clone, Debug)] +pub struct SignOffProposalCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SignOffProposalCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + signatory_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(SignOffProposalCpiBuilderInstruction { + __program, + realm_account, + governance_account, + proposal_account, + signatory_account, + token_owner_record, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = SignOffProposalCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governance_account: self.instruction.governance_account, + proposal_account: self.instruction.proposal_account, + signatory_account: self.instruction.signatory_account, + token_owner_record: self.instruction.token_owner_record, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SignOffProposalCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governance_account: &'b solana_account_info::AccountInfo<'a>, + proposal_account: &'b solana_account_info::AccountInfo<'a>, + signatory_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/update_program_metadata.rs b/e2e/governance/src/generated/instructions/update_program_metadata.rs new file mode 100644 index 0000000..9b342d9 --- /dev/null +++ b/e2e/governance/src/generated/instructions/update_program_metadata.rs @@ -0,0 +1,331 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const UPDATE_PROGRAM_METADATA_DISCRIMINATOR: u8 = 24; + +/// Accounts. +#[derive(Debug)] +pub struct UpdateProgramMetadata { + /// seeds=['metadata'] + pub program_metadata_account: solana_address::Address, + + pub payer: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl UpdateProgramMetadata { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.program_metadata_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = UpdateProgramMetadataInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdateProgramMetadataInstructionData { + discriminator: u8, +} + +impl UpdateProgramMetadataInstructionData { + pub fn new() -> Self { + Self { discriminator: 24 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for UpdateProgramMetadataInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `UpdateProgramMetadata`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` program_metadata_account +/// 1. `[signer]` payer +/// 2. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct UpdateProgramMetadataBuilder { + program_metadata_account: solana_address::Address, + payer: solana_address::Address, + system_program: Option, + __remaining_accounts: Vec, +} + +impl UpdateProgramMetadataBuilder { + pub fn new( + program_metadata_account: solana_address::Address, + payer: solana_address::Address, + ) -> Self { + Self { + program_metadata_account, + payer, + system_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_address::Address) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let program_metadata_account = self.program_metadata_account; + let payer = self.payer; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = UpdateProgramMetadata { + program_metadata_account, + payer, + system_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `update_program_metadata` CPI accounts. +pub struct UpdateProgramMetadataCpiAccounts<'a, 'b> { + /// seeds=['metadata'] + pub program_metadata_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `update_program_metadata` CPI instruction. +pub struct UpdateProgramMetadataCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['metadata'] + pub program_metadata_account: &'b solana_account_info::AccountInfo<'a>, + + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> UpdateProgramMetadataCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: UpdateProgramMetadataCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + program_metadata_account: accounts.program_metadata_account, + payer: accounts.payer, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.program_metadata_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = UpdateProgramMetadataInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.program_metadata_account.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `UpdateProgramMetadata` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` program_metadata_account +/// 1. `[signer]` payer +/// 2. `[]` system_program +#[derive(Clone, Debug)] +pub struct UpdateProgramMetadataCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateProgramMetadataCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + program_metadata_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(UpdateProgramMetadataCpiBuilderInstruction { + __program, + program_metadata_account, + payer, + system_program, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = UpdateProgramMetadataCpi { + __program: self.instruction.__program, + program_metadata_account: self.instruction.program_metadata_account, + payer: self.instruction.payer, + system_program: self.instruction.system_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct UpdateProgramMetadataCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + program_metadata_account: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/instructions/withdraw_governing_tokens.rs b/e2e/governance/src/generated/instructions/withdraw_governing_tokens.rs new file mode 100644 index 0000000..38e7ea3 --- /dev/null +++ b/e2e/governance/src/generated/instructions/withdraw_governing_tokens.rs @@ -0,0 +1,440 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const WITHDRAW_GOVERNING_TOKENS_DISCRIMINATOR: u8 = 2; + +/// Accounts. +#[derive(Debug)] +pub struct WithdrawGoverningTokens { + pub realm_account: solana_address::Address, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: solana_address::Address, + /// All tokens will be transferred to this account + pub governing_token_destination_account: solana_address::Address, + + pub governing_token_owner_account: solana_address::Address, + /// seeds=['governance',realm, governing_token_mint, governing_token_owner] + pub token_owner_record: solana_address::Address, + + pub token_program: solana_address::Address, + /// seeds=['realm-config', realm] + pub realm_config_account: solana_address::Address, +} + +impl WithdrawGoverningTokens { + pub fn instruction(&self) -> solana_instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_holding_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.governing_token_destination_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.governing_token_owner_account, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token_owner_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.realm_config_account, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = WithdrawGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct WithdrawGoverningTokensInstructionData { + discriminator: u8, +} + +impl WithdrawGoverningTokensInstructionData { + pub fn new() -> Self { + Self { discriminator: 2 } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for WithdrawGoverningTokensInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `WithdrawGoverningTokens`. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` governing_token_destination_account +/// 3. `[signer]` governing_token_owner_account +/// 4. `[writable]` token_owner_record +/// 5. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 6. `[]` realm_config_account +#[derive(Clone, Debug)] +pub struct WithdrawGoverningTokensBuilder { + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + governing_token_destination_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + token_owner_record: solana_address::Address, + token_program: Option, + realm_config_account: solana_address::Address, + __remaining_accounts: Vec, +} + +impl WithdrawGoverningTokensBuilder { + pub fn new( + realm_account: solana_address::Address, + governing_token_holding_account: solana_address::Address, + governing_token_destination_account: solana_address::Address, + governing_token_owner_account: solana_address::Address, + token_owner_record: solana_address::Address, + realm_config_account: solana_address::Address, + ) -> Self { + Self { + realm_account, + governing_token_holding_account, + governing_token_destination_account, + governing_token_owner_account, + token_owner_record, + token_program: None, + realm_config_account, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + #[inline(always)] + pub fn token_program(&mut self, token_program: solana_address::Address) -> &mut Self { + self.token_program = Some(token_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_instruction::Instruction { + let realm_account = self.realm_account; + let governing_token_holding_account = self.governing_token_holding_account; + let governing_token_destination_account = self.governing_token_destination_account; + let governing_token_owner_account = self.governing_token_owner_account; + let token_owner_record = self.token_owner_record; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let realm_config_account = self.realm_config_account; + let accounts = WithdrawGoverningTokens { + realm_account, + governing_token_holding_account, + governing_token_destination_account, + governing_token_owner_account, + token_owner_record, + token_program, + realm_config_account, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `withdraw_governing_tokens` CPI accounts. +pub struct WithdrawGoverningTokensCpiAccounts<'a, 'b> { + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// All tokens will be transferred to this account + pub governing_token_destination_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance',realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, +} + +/// `withdraw_governing_tokens` CPI instruction. +pub struct WithdrawGoverningTokensCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub realm_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance', realm, governing_token_mint] + pub governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + /// All tokens will be transferred to this account + pub governing_token_destination_account: &'b solana_account_info::AccountInfo<'a>, + + pub governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['governance',realm, governing_token_mint, governing_token_owner] + pub token_owner_record: &'b solana_account_info::AccountInfo<'a>, + + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// seeds=['realm-config', realm] + pub realm_config_account: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> WithdrawGoverningTokensCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: WithdrawGoverningTokensCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + realm_account: accounts.realm_account, + governing_token_holding_account: accounts.governing_token_holding_account, + governing_token_destination_account: accounts.governing_token_destination_account, + governing_token_owner_account: accounts.governing_token_owner_account, + token_owner_record: accounts.token_owner_record, + token_program: accounts.token_program, + realm_config_account: accounts.realm_config_account, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::arithmetic_side_effects)] + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> solana_program_error::ProgramResult { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_holding_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.governing_token_destination_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.governing_token_owner_account.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token_owner_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.realm_config_account.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = WithdrawGoverningTokensInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::SPL_GOVERNANCE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(8 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.realm_account.clone()); + account_infos.push(self.governing_token_holding_account.clone()); + account_infos.push(self.governing_token_destination_account.clone()); + account_infos.push(self.governing_token_owner_account.clone()); + account_infos.push(self.token_owner_record.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.realm_config_account.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_cpi::invoke(&instruction, &account_infos) + } else { + solana_cpi::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `WithdrawGoverningTokens` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` realm_account +/// 1. `[writable]` governing_token_holding_account +/// 2. `[writable]` governing_token_destination_account +/// 3. `[signer]` governing_token_owner_account +/// 4. `[writable]` token_owner_record +/// 5. `[]` token_program +/// 6. `[]` realm_config_account +#[derive(Clone, Debug)] +pub struct WithdrawGoverningTokensCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> WithdrawGoverningTokensCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_destination_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(WithdrawGoverningTokensCpiBuilderInstruction { + __program, + realm_account, + governing_token_holding_account, + governing_token_destination_account, + governing_token_owner_account, + token_owner_record, + token_program, + realm_config_account, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[(&'b solana_account_info::AccountInfo<'a>, bool, bool)], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program_error::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { + let instruction = WithdrawGoverningTokensCpi { + __program: self.instruction.__program, + realm_account: self.instruction.realm_account, + governing_token_holding_account: self.instruction.governing_token_holding_account, + governing_token_destination_account: self + .instruction + .governing_token_destination_account, + governing_token_owner_account: self.instruction.governing_token_owner_account, + token_owner_record: self.instruction.token_owner_record, + token_program: self.instruction.token_program, + realm_config_account: self.instruction.realm_config_account, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct WithdrawGoverningTokensCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + realm_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_holding_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_destination_account: &'b solana_account_info::AccountInfo<'a>, + governing_token_owner_account: &'b solana_account_info::AccountInfo<'a>, + token_owner_record: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + realm_config_account: &'b solana_account_info::AccountInfo<'a>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/governance/src/generated/mod.rs b/e2e/governance/src/generated/mod.rs new file mode 100644 index 0000000..d37d822 --- /dev/null +++ b/e2e/governance/src/generated/mod.rs @@ -0,0 +1,16 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod accounts; +pub mod errors; +pub mod instructions; +pub mod pdas; +pub mod programs; +pub mod shared; +pub mod types; + +pub(crate) use programs::*; diff --git a/e2e/governance/src/generated/pdas/community_token_holding.rs b/e2e/governance/src/generated/pdas/community_token_holding.rs new file mode 100644 index 0000000..b5a3d5f --- /dev/null +++ b/e2e/governance/src/generated/pdas/community_token_holding.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const COMMUNITY_TOKEN_HOLDING_SEED: &'static [u8] = b"governance"; +/// Community token holding account of a realm +pub fn create_community_token_holding_pda( + realm: Address, + community_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + COMMUNITY_TOKEN_HOLDING_SEED, + realm.as_ref(), + community_mint.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Community token holding account of a realm +pub fn find_community_token_holding_pda( + realm: &Address, + community_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + COMMUNITY_TOKEN_HOLDING_SEED, + realm.as_ref(), + community_mint.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/council_token_holding.rs b/e2e/governance/src/generated/pdas/council_token_holding.rs new file mode 100644 index 0000000..c23caf4 --- /dev/null +++ b/e2e/governance/src/generated/pdas/council_token_holding.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const COUNCIL_TOKEN_HOLDING_SEED: &'static [u8] = b"governance"; +/// Council token holding account of a realm +pub fn create_council_token_holding_pda( + realm: Address, + council_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + COUNCIL_TOKEN_HOLDING_SEED, + realm.as_ref(), + council_mint.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Council token holding account of a realm +pub fn find_council_token_holding_pda( + realm: &Address, + council_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + COUNCIL_TOKEN_HOLDING_SEED, + realm.as_ref(), + council_mint.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/governance.rs b/e2e/governance/src/generated/pdas/governance.rs new file mode 100644 index 0000000..4e71153 --- /dev/null +++ b/e2e/governance/src/generated/pdas/governance.rs @@ -0,0 +1,30 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const GOVERNANCE_SEED: &'static [u8] = b"account-governance"; +/// Governance account within a realm +pub fn create_governance_pda( + realm: Address, + seed: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[GOVERNANCE_SEED, realm.as_ref(), seed.as_ref(), &[bump]], + &SPL_GOVERNANCE_ID, + ) +} +/// Governance account within a realm +pub fn find_governance_pda(realm: &Address, seed: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[GOVERNANCE_SEED, realm.as_ref(), seed.as_ref()], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/governing_token_holding.rs b/e2e/governance/src/generated/pdas/governing_token_holding.rs new file mode 100644 index 0000000..6cfdda1 --- /dev/null +++ b/e2e/governance/src/generated/pdas/governing_token_holding.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const GOVERNING_TOKEN_HOLDING_SEED: &'static [u8] = b"governance"; +/// Governing token holding account +pub fn create_governing_token_holding_pda( + realm: Address, + governing_token_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + GOVERNING_TOKEN_HOLDING_SEED, + realm.as_ref(), + governing_token_mint.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Governing token holding account +pub fn find_governing_token_holding_pda( + realm: &Address, + governing_token_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + GOVERNING_TOKEN_HOLDING_SEED, + realm.as_ref(), + governing_token_mint.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/mod.rs b/e2e/governance/src/generated/pdas/mod.rs new file mode 100644 index 0000000..b9faaa2 --- /dev/null +++ b/e2e/governance/src/generated/pdas/mod.rs @@ -0,0 +1,36 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod community_token_holding; +pub mod council_token_holding; +pub mod governance; +pub mod governing_token_holding; +pub mod native_treasury; +pub mod proposal; +pub mod proposal_deposit; +pub mod proposal_transaction; +pub mod realm; +pub mod realm_config; +pub mod required_signatory; +pub mod signatory_record; +pub mod token_owner_record; +pub mod vote_record; + +pub use self::community_token_holding::*; +pub use self::council_token_holding::*; +pub use self::governance::*; +pub use self::governing_token_holding::*; +pub use self::native_treasury::*; +pub use self::proposal::*; +pub use self::proposal_deposit::*; +pub use self::proposal_transaction::*; +pub use self::realm::*; +pub use self::realm_config::*; +pub use self::required_signatory::*; +pub use self::signatory_record::*; +pub use self::token_owner_record::*; +pub use self::vote_record::*; diff --git a/e2e/governance/src/generated/pdas/native_treasury.rs b/e2e/governance/src/generated/pdas/native_treasury.rs new file mode 100644 index 0000000..4a545ae --- /dev/null +++ b/e2e/governance/src/generated/pdas/native_treasury.rs @@ -0,0 +1,29 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const NATIVE_TREASURY_SEED: &'static [u8] = b"native-treasury"; +/// Governance's native SOL treasury account +pub fn create_native_treasury_pda( + governance: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[NATIVE_TREASURY_SEED, governance.as_ref(), &[bump]], + &SPL_GOVERNANCE_ID, + ) +} +/// Governance's native SOL treasury account +pub fn find_native_treasury_pda(governance: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[NATIVE_TREASURY_SEED, governance.as_ref()], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/proposal.rs b/e2e/governance/src/generated/pdas/proposal.rs new file mode 100644 index 0000000..a11f0d1 --- /dev/null +++ b/e2e/governance/src/generated/pdas/proposal.rs @@ -0,0 +1,46 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const PROPOSAL_SEED: &'static [u8] = b"governance"; +/// Governance proposal +pub fn create_proposal_pda( + governance: Address, + governing_token_mint: Address, + proposal_seed: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + PROPOSAL_SEED, + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Governance proposal +pub fn find_proposal_pda( + governance: &Address, + governing_token_mint: &Address, + proposal_seed: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + PROPOSAL_SEED, + governance.as_ref(), + governing_token_mint.as_ref(), + proposal_seed.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/proposal_deposit.rs b/e2e/governance/src/generated/pdas/proposal_deposit.rs new file mode 100644 index 0000000..182132b --- /dev/null +++ b/e2e/governance/src/generated/pdas/proposal_deposit.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const PROPOSAL_DEPOSIT_SEED: &'static [u8] = b"proposal-deposit"; +/// Proposal deposit made by a specific payer +pub fn create_proposal_deposit_pda( + proposal: Address, + deposit_payer: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + PROPOSAL_DEPOSIT_SEED, + proposal.as_ref(), + deposit_payer.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Proposal deposit made by a specific payer +pub fn find_proposal_deposit_pda( + proposal: &Address, + deposit_payer: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + PROPOSAL_DEPOSIT_SEED, + proposal.as_ref(), + deposit_payer.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/proposal_transaction.rs b/e2e/governance/src/generated/pdas/proposal_transaction.rs new file mode 100644 index 0000000..c13bf94 --- /dev/null +++ b/e2e/governance/src/generated/pdas/proposal_transaction.rs @@ -0,0 +1,46 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const PROPOSAL_TRANSACTION_SEED: &'static [u8] = b"governance"; +/// Transaction within a proposal option +pub fn create_proposal_transaction_pda( + proposal: Address, + option_index: u8, + index: u16, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + PROPOSAL_TRANSACTION_SEED, + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Transaction within a proposal option +pub fn find_proposal_transaction_pda( + proposal: &Address, + option_index: u8, + index: u16, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + PROPOSAL_TRANSACTION_SEED, + proposal.as_ref(), + option_index.to_string().as_ref(), + index.to_string().as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/realm.rs b/e2e/governance/src/generated/pdas/realm.rs new file mode 100644 index 0000000..33890e6 --- /dev/null +++ b/e2e/governance/src/generated/pdas/realm.rs @@ -0,0 +1,29 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use spl_collections::TrailingStr; + +use crate::SPL_GOVERNANCE_ID; + +pub const REALM_SEED: &'static [u8] = b"governance"; +/// Realm account identified by its name +pub fn create_realm_pda( + name: TrailingStr, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[REALM_SEED, name.to_string().as_ref(), &[bump]], + &SPL_GOVERNANCE_ID, + ) +} +/// Realm account identified by its name +pub fn find_realm_pda(name: TrailingStr) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[REALM_SEED, name.to_string().as_ref()], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/realm_config.rs b/e2e/governance/src/generated/pdas/realm_config.rs new file mode 100644 index 0000000..28c3bbc --- /dev/null +++ b/e2e/governance/src/generated/pdas/realm_config.rs @@ -0,0 +1,29 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const REALM_CONFIG_SEED: &'static [u8] = b"realm-config"; +/// Configuration of a realm +pub fn create_realm_config_pda( + realm: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[REALM_CONFIG_SEED, realm.as_ref(), &[bump]], + &SPL_GOVERNANCE_ID, + ) +} +/// Configuration of a realm +pub fn find_realm_config_pda(realm: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[REALM_CONFIG_SEED, realm.as_ref()], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/required_signatory.rs b/e2e/governance/src/generated/pdas/required_signatory.rs new file mode 100644 index 0000000..a168f3c --- /dev/null +++ b/e2e/governance/src/generated/pdas/required_signatory.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const REQUIRED_SIGNATORY_SEED: &'static [u8] = b"required-signatory"; +/// Required signatory on a governance +pub fn create_required_signatory_pda( + governance: Address, + signatory: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + REQUIRED_SIGNATORY_SEED, + governance.as_ref(), + signatory.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Required signatory on a governance +pub fn find_required_signatory_pda( + governance: &Address, + signatory: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + REQUIRED_SIGNATORY_SEED, + governance.as_ref(), + signatory.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/signatory_record.rs b/e2e/governance/src/generated/pdas/signatory_record.rs new file mode 100644 index 0000000..b38f225 --- /dev/null +++ b/e2e/governance/src/generated/pdas/signatory_record.rs @@ -0,0 +1,38 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const SIGNATORY_RECORD_SEED: &'static [u8] = b"governance"; +/// Signatory's record on a proposal +pub fn create_signatory_record_pda( + proposal: Address, + signatory: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + SIGNATORY_RECORD_SEED, + proposal.as_ref(), + signatory.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Signatory's record on a proposal +pub fn find_signatory_record_pda( + proposal: &Address, + signatory: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[SIGNATORY_RECORD_SEED, proposal.as_ref(), signatory.as_ref()], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/token_owner_record.rs b/e2e/governance/src/generated/pdas/token_owner_record.rs new file mode 100644 index 0000000..3482cf6 --- /dev/null +++ b/e2e/governance/src/generated/pdas/token_owner_record.rs @@ -0,0 +1,46 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const TOKEN_OWNER_RECORD_SEED: &'static [u8] = b"governance"; +/// Token owner's record within a realm +pub fn create_token_owner_record_pda( + realm: Address, + governing_token_mint: Address, + governing_token_owner: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + TOKEN_OWNER_RECORD_SEED, + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Token owner's record within a realm +pub fn find_token_owner_record_pda( + realm: &Address, + governing_token_mint: &Address, + governing_token_owner: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + TOKEN_OWNER_RECORD_SEED, + realm.as_ref(), + governing_token_mint.as_ref(), + governing_token_owner.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/pdas/vote_record.rs b/e2e/governance/src/generated/pdas/vote_record.rs new file mode 100644 index 0000000..9b648a9 --- /dev/null +++ b/e2e/governance/src/generated/pdas/vote_record.rs @@ -0,0 +1,42 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::Address; + +use crate::SPL_GOVERNANCE_ID; + +pub const VOTE_RECORD_SEED: &'static [u8] = b"governance"; +/// Vote record on a proposal +pub fn create_vote_record_pda( + proposal: Address, + token_owner_record: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + VOTE_RECORD_SEED, + proposal.as_ref(), + token_owner_record.as_ref(), + &[bump], + ], + &SPL_GOVERNANCE_ID, + ) +} +/// Vote record on a proposal +pub fn find_vote_record_pda( + proposal: &Address, + token_owner_record: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + VOTE_RECORD_SEED, + proposal.as_ref(), + token_owner_record.as_ref(), + ], + &SPL_GOVERNANCE_ID, + ) +} diff --git a/e2e/governance/src/generated/programs.rs b/e2e/governance/src/generated/programs.rs new file mode 100644 index 0000000..77fa696 --- /dev/null +++ b/e2e/governance/src/generated/programs.rs @@ -0,0 +1,11 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_address::{address, Address}; + +/// `spl_governance` program ID. +pub const SPL_GOVERNANCE_ID: Address = address!("GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw"); diff --git a/e2e/governance/src/generated/shared.rs b/e2e/governance/src/generated/shared.rs new file mode 100644 index 0000000..42eae7f --- /dev/null +++ b/e2e/governance/src/generated/shared.rs @@ -0,0 +1,21 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +#[cfg(feature = "fetch")] +#[derive(Debug, Clone)] +pub struct DecodedAccount { + pub address: solana_address::Address, + pub account: solana_account::Account, + pub data: T, +} + +#[cfg(feature = "fetch")] +#[derive(Debug, Clone)] +pub enum MaybeAccount { + Exists(DecodedAccount), + NotFound(solana_address::Address), +} diff --git a/e2e/governance/src/generated/types/account_meta_data.rs b/e2e/governance/src/generated/types/account_meta_data.rs new file mode 100644 index 0000000..71c8886 --- /dev/null +++ b/e2e/governance/src/generated/types/account_meta_data.rs @@ -0,0 +1,17 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct AccountMetaData { + pub pubkey: Address, + pub is_signer: bool, + pub is_writable: bool, +} diff --git a/e2e/governance/src/generated/types/governance_account_type.rs b/e2e/governance/src/generated/types/governance_account_type.rs new file mode 100644 index 0000000..aaba23a --- /dev/null +++ b/e2e/governance/src/generated/types/governance_account_type.rs @@ -0,0 +1,50 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum GovernanceAccountType { + Uninitialized, + RealmV1, + TokenOwnerRecordV1, + GovernanceV1, + ProgramGovernanceV1, + ProposalV1, + SignatoryRecordV1, + VoteRecordV1, + ProposalInstructionV1, + MintGovernanceV1, + TokenGovernanceV1, + RealmConfig, + VoteRecordV2, + ProposalTransactionV2, + ProposalV2, + ProgramMetadata, + RealmV2, + TokenOwnerRecordV2, + GovernanceV2, + ProgramGovernanceV2, + MintGovernanceV2, + TokenGovernanceV2, + SignatoryRecordV2, + ProposalDeposit, + RequiredSignatory, +} diff --git a/e2e/governance/src/generated/types/governance_config.rs b/e2e/governance/src/generated/types/governance_config.rs new file mode 100644 index 0000000..d7ac461 --- /dev/null +++ b/e2e/governance/src/generated/types/governance_config.rs @@ -0,0 +1,27 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::VoteThreshold; +use crate::generated::types::VoteTipping; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GovernanceConfig { + pub community_vote_threshold: VoteThreshold, + pub min_community_weight_to_create_proposal: u64, + pub min_transaction_hold_up_time: u32, + pub voting_base_time: u32, + pub community_vote_tipping: VoteTipping, + pub council_vote_threshold: VoteThreshold, + pub council_veto_vote_threshold: VoteThreshold, + pub min_council_weight_to_create_proposal: u64, + pub council_vote_tipping: VoteTipping, + pub community_veto_vote_threshold: VoteThreshold, + pub voting_cool_off_time: u32, + pub deposit_exempt_proposal_count: u8, +} diff --git a/e2e/governance/src/generated/types/governance_instruction_v1.rs b/e2e/governance/src/generated/types/governance_instruction_v1.rs new file mode 100644 index 0000000..787bb2b --- /dev/null +++ b/e2e/governance/src/generated/types/governance_instruction_v1.rs @@ -0,0 +1,21 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::RealmConfigParamsV1; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum GovernanceInstructionV1 { + CreateRealm { + name: String, + config_args: RealmConfigParamsV1, + }, + DepositGoverningTokens { + amount: u64, + }, +} diff --git a/e2e/governance/src/generated/types/governing_token_config.rs b/e2e/governance/src/generated/types/governing_token_config.rs new file mode 100644 index 0000000..dfbe0d8 --- /dev/null +++ b/e2e/governance/src/generated/types/governing_token_config.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GoverningTokenType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GoverningTokenConfig { + pub voter_weight_addin: Option
, + pub max_voter_weight_addin: Option
, + pub token_type: GoverningTokenType, + pub reserved: [u8; 8], +} diff --git a/e2e/governance/src/generated/types/governing_token_config_account_args.rs b/e2e/governance/src/generated/types/governing_token_config_account_args.rs new file mode 100644 index 0000000..396788c --- /dev/null +++ b/e2e/governance/src/generated/types/governing_token_config_account_args.rs @@ -0,0 +1,18 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GoverningTokenType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GoverningTokenConfigAccountArgs { + pub voter_weight_addin: Option
, + pub max_voter_weight_addin: Option
, + pub token_type: GoverningTokenType, +} diff --git a/e2e/governance/src/generated/types/governing_token_config_params.rs b/e2e/governance/src/generated/types/governing_token_config_params.rs new file mode 100644 index 0000000..5ceee6e --- /dev/null +++ b/e2e/governance/src/generated/types/governing_token_config_params.rs @@ -0,0 +1,17 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GoverningTokenType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GoverningTokenConfigParams { + pub use_voter_weight_addin: bool, + pub use_max_voter_weight_addin: bool, + pub token_type: GoverningTokenType, +} diff --git a/e2e/governance/src/generated/types/governing_token_type.rs b/e2e/governance/src/generated/types/governing_token_type.rs new file mode 100644 index 0000000..5f0557c --- /dev/null +++ b/e2e/governance/src/generated/types/governing_token_type.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum GoverningTokenType { + Liquid, + Membership, + Dormant, +} diff --git a/e2e/governance/src/generated/types/instruction_data.rs b/e2e/governance/src/generated/types/instruction_data.rs new file mode 100644 index 0000000..8ef15a8 --- /dev/null +++ b/e2e/governance/src/generated/types/instruction_data.rs @@ -0,0 +1,18 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::AccountMetaData; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InstructionData { + pub program_id: Address, + pub accounts: Vec, + pub data: Vec, +} diff --git a/e2e/governance/src/generated/types/instruction_execution_flags.rs b/e2e/governance/src/generated/types/instruction_execution_flags.rs new file mode 100644 index 0000000..5667518 --- /dev/null +++ b/e2e/governance/src/generated/types/instruction_execution_flags.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum InstructionExecutionFlags { + None, + Ordered, + UseTransaction, +} diff --git a/e2e/governance/src/generated/types/mint_max_voter_weight_source.rs b/e2e/governance/src/generated/types/mint_max_voter_weight_source.rs new file mode 100644 index 0000000..4e3fa26 --- /dev/null +++ b/e2e/governance/src/generated/types/mint_max_voter_weight_source.rs @@ -0,0 +1,15 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum MintMaxVoterWeightSource { + SupplyFraction(u64), + Absolute(u64), +} diff --git a/e2e/governance/src/generated/types/mod.rs b/e2e/governance/src/generated/types/mod.rs new file mode 100644 index 0000000..b5b6bae --- /dev/null +++ b/e2e/governance/src/generated/types/mod.rs @@ -0,0 +1,72 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#account_meta_data; +pub(crate) mod r#governance_account_type; +pub(crate) mod r#governance_config; +pub(crate) mod r#governance_instruction_v1; +pub(crate) mod r#governing_token_config; +pub(crate) mod r#governing_token_config_account_args; +pub(crate) mod r#governing_token_config_params; +pub(crate) mod r#governing_token_type; +pub(crate) mod r#instruction_data; +pub(crate) mod r#instruction_execution_flags; +pub(crate) mod r#mint_max_voter_weight_source; +pub(crate) mod r#multi_choice_type; +pub(crate) mod r#native_treasury; +pub(crate) mod r#option_vote_result; +pub(crate) mod r#proposal_option; +pub(crate) mod r#proposal_state; +pub(crate) mod r#realm_config; +pub(crate) mod r#realm_config_params; +pub(crate) mod r#realm_config_params_v1; +pub(crate) mod r#reserved110; +pub(crate) mod r#reserved119; +pub(crate) mod r#set_realm_authority_action; +pub(crate) mod r#slot; +pub(crate) mod r#transaction_execution_status; +pub(crate) mod r#unix_timestamp; +pub(crate) mod r#vote; +pub(crate) mod r#vote_choice; +pub(crate) mod r#vote_kind; +pub(crate) mod r#vote_threshold; +pub(crate) mod r#vote_tipping; +pub(crate) mod r#vote_type; +pub(crate) mod r#vote_weight_v1; + +pub use self::r#account_meta_data::*; +pub use self::r#governance_account_type::*; +pub use self::r#governance_config::*; +pub use self::r#governance_instruction_v1::*; +pub use self::r#governing_token_config::*; +pub use self::r#governing_token_config_account_args::*; +pub use self::r#governing_token_config_params::*; +pub use self::r#governing_token_type::*; +pub use self::r#instruction_data::*; +pub use self::r#instruction_execution_flags::*; +pub use self::r#mint_max_voter_weight_source::*; +pub use self::r#multi_choice_type::*; +pub use self::r#native_treasury::*; +pub use self::r#option_vote_result::*; +pub use self::r#proposal_option::*; +pub use self::r#proposal_state::*; +pub use self::r#realm_config::*; +pub use self::r#realm_config_params::*; +pub use self::r#realm_config_params_v1::*; +pub use self::r#reserved110::*; +pub use self::r#reserved119::*; +pub use self::r#set_realm_authority_action::*; +pub use self::r#slot::*; +pub use self::r#transaction_execution_status::*; +pub use self::r#unix_timestamp::*; +pub use self::r#vote::*; +pub use self::r#vote_choice::*; +pub use self::r#vote_kind::*; +pub use self::r#vote_threshold::*; +pub use self::r#vote_tipping::*; +pub use self::r#vote_type::*; +pub use self::r#vote_weight_v1::*; diff --git a/e2e/governance/src/generated/types/multi_choice_type.rs b/e2e/governance/src/generated/types/multi_choice_type.rs new file mode 100644 index 0000000..17cd933 --- /dev/null +++ b/e2e/governance/src/generated/types/multi_choice_type.rs @@ -0,0 +1,27 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum MultiChoiceType { + FullWeight, + Weighted, +} diff --git a/e2e/governance/src/generated/types/native_treasury.rs b/e2e/governance/src/generated/types/native_treasury.rs new file mode 100644 index 0000000..3ccef96 --- /dev/null +++ b/e2e/governance/src/generated/types/native_treasury.rs @@ -0,0 +1,12 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct NativeTreasury {} diff --git a/e2e/governance/src/generated/types/option_vote_result.rs b/e2e/governance/src/generated/types/option_vote_result.rs new file mode 100644 index 0000000..cef847c --- /dev/null +++ b/e2e/governance/src/generated/types/option_vote_result.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum OptionVoteResult { + None, + Succeeded, + Defeated, +} diff --git a/e2e/governance/src/generated/types/proposal_option.rs b/e2e/governance/src/generated/types/proposal_option.rs new file mode 100644 index 0000000..208e536 --- /dev/null +++ b/e2e/governance/src/generated/types/proposal_option.rs @@ -0,0 +1,20 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::OptionVoteResult; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ProposalOption { + pub label: String, + pub vote_weight: u64, + pub vote_result: OptionVoteResult, + pub transactions_executed_count: u16, + pub transactions_count: u16, + pub transactions_next_index: u16, +} diff --git a/e2e/governance/src/generated/types/proposal_state.rs b/e2e/governance/src/generated/types/proposal_state.rs new file mode 100644 index 0000000..7bd605b --- /dev/null +++ b/e2e/governance/src/generated/types/proposal_state.rs @@ -0,0 +1,35 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum ProposalState { + Draft, + SigningOff, + Voting, + Succeeded, + Executing, + Completed, + Cancelled, + Defeated, + ExecutingWithErrors, + Vetoed, +} diff --git a/e2e/governance/src/generated/types/realm_config.rs b/e2e/governance/src/generated/types/realm_config.rs new file mode 100644 index 0000000..ad92b81 --- /dev/null +++ b/e2e/governance/src/generated/types/realm_config.rs @@ -0,0 +1,21 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::MintMaxVoterWeightSource; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmConfig { + pub legacy1: u8, + pub legacy2: u8, + pub reserved: [u8; 6], + pub min_community_weight_to_create_governance: u64, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, + pub council_mint: Option
, +} diff --git a/e2e/governance/src/generated/types/realm_config_params.rs b/e2e/governance/src/generated/types/realm_config_params.rs new file mode 100644 index 0000000..8bd42b4 --- /dev/null +++ b/e2e/governance/src/generated/types/realm_config_params.rs @@ -0,0 +1,20 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::GoverningTokenConfigParams; +use crate::generated::types::MintMaxVoterWeightSource; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmConfigParams { + pub use_council_mint: bool, + pub min_community_weight_to_create_governance: u64, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, + pub community_token_config_args: GoverningTokenConfigParams, + pub council_token_config_args: GoverningTokenConfigParams, +} diff --git a/e2e/governance/src/generated/types/realm_config_params_v1.rs b/e2e/governance/src/generated/types/realm_config_params_v1.rs new file mode 100644 index 0000000..9b52b1c --- /dev/null +++ b/e2e/governance/src/generated/types/realm_config_params_v1.rs @@ -0,0 +1,17 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::MintMaxVoterWeightSource; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct RealmConfigParamsV1 { + pub use_council_mint: bool, + pub min_community_weight_to_create_governance: u64, + pub community_mint_max_voter_weight_source: MintMaxVoterWeightSource, +} diff --git a/e2e/governance/src/generated/types/reserved110.rs b/e2e/governance/src/generated/types/reserved110.rs new file mode 100644 index 0000000..a0d3def --- /dev/null +++ b/e2e/governance/src/generated/types/reserved110.rs @@ -0,0 +1,16 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Reserved110 { + pub reserved64: [u8; 64], + pub reserved32: [u8; 32], + pub reserved14: [u8; 14], +} diff --git a/e2e/governance/src/generated/types/reserved119.rs b/e2e/governance/src/generated/types/reserved119.rs new file mode 100644 index 0000000..c904c4c --- /dev/null +++ b/e2e/governance/src/generated/types/reserved119.rs @@ -0,0 +1,16 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Reserved119 { + pub reserved64: [u8; 64], + pub reserved32: [u8; 32], + pub reserved23: [u8; 23], +} diff --git a/e2e/governance/src/generated/types/set_realm_authority_action.rs b/e2e/governance/src/generated/types/set_realm_authority_action.rs new file mode 100644 index 0000000..b03caf8 --- /dev/null +++ b/e2e/governance/src/generated/types/set_realm_authority_action.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum SetRealmAuthorityAction { + SetUnchecked, + SetChecked, + Remove, +} diff --git a/e2e/governance/src/generated/types/slot.rs b/e2e/governance/src/generated/types/slot.rs new file mode 100644 index 0000000..f804032 --- /dev/null +++ b/e2e/governance/src/generated/types/slot.rs @@ -0,0 +1,8 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub type Slot = u64; diff --git a/e2e/governance/src/generated/types/transaction_execution_status.rs b/e2e/governance/src/generated/types/transaction_execution_status.rs new file mode 100644 index 0000000..4ac3ddb --- /dev/null +++ b/e2e/governance/src/generated/types/transaction_execution_status.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum TransactionExecutionStatus { + None, + Success, + Error, +} diff --git a/e2e/governance/src/generated/types/unix_timestamp.rs b/e2e/governance/src/generated/types/unix_timestamp.rs new file mode 100644 index 0000000..62d0860 --- /dev/null +++ b/e2e/governance/src/generated/types/unix_timestamp.rs @@ -0,0 +1,8 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub type UnixTimestamp = i64; diff --git a/e2e/governance/src/generated/types/vote.rs b/e2e/governance/src/generated/types/vote.rs new file mode 100644 index 0000000..95903bd --- /dev/null +++ b/e2e/governance/src/generated/types/vote.rs @@ -0,0 +1,18 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::VoteChoice; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum Vote { + Approve(Vec), + Deny, + Abstain, + Veto, +} diff --git a/e2e/governance/src/generated/types/vote_choice.rs b/e2e/governance/src/generated/types/vote_choice.rs new file mode 100644 index 0000000..d5fbaa6 --- /dev/null +++ b/e2e/governance/src/generated/types/vote_choice.rs @@ -0,0 +1,15 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct VoteChoice { + pub rank: u8, + pub weight_percentage: u8, +} diff --git a/e2e/governance/src/generated/types/vote_kind.rs b/e2e/governance/src/generated/types/vote_kind.rs new file mode 100644 index 0000000..5aae726 --- /dev/null +++ b/e2e/governance/src/generated/types/vote_kind.rs @@ -0,0 +1,27 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum VoteKind { + Electorate, + Veto, +} diff --git a/e2e/governance/src/generated/types/vote_threshold.rs b/e2e/governance/src/generated/types/vote_threshold.rs new file mode 100644 index 0000000..71bb356 --- /dev/null +++ b/e2e/governance/src/generated/types/vote_threshold.rs @@ -0,0 +1,16 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum VoteThreshold { + YesVotePercentage(u8), + QuorumPercentage(u8), + Disabled, +} diff --git a/e2e/governance/src/generated/types/vote_tipping.rs b/e2e/governance/src/generated/types/vote_tipping.rs new file mode 100644 index 0000000..f15f308 --- /dev/null +++ b/e2e/governance/src/generated/types/vote_tipping.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum VoteTipping { + Strict, + Early, + Disabled, +} diff --git a/e2e/governance/src/generated/types/vote_type.rs b/e2e/governance/src/generated/types/vote_type.rs new file mode 100644 index 0000000..865ddde --- /dev/null +++ b/e2e/governance/src/generated/types/vote_type.rs @@ -0,0 +1,21 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::MultiChoiceType; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum VoteType { + SingleChoice, + MultiChoice { + choice_type: MultiChoiceType, + min_voter_options: u8, + max_voter_options: u8, + max_winning_options: u8, + }, +} diff --git a/e2e/governance/src/generated/types/vote_weight_v1.rs b/e2e/governance/src/generated/types/vote_weight_v1.rs new file mode 100644 index 0000000..184b2b7 --- /dev/null +++ b/e2e/governance/src/generated/types/vote_weight_v1.rs @@ -0,0 +1,15 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum VoteWeightV1 { + Yes(u64), + No(u64), +} diff --git a/e2e/governance/src/lib.rs b/e2e/governance/src/lib.rs new file mode 100644 index 0000000..19f9287 --- /dev/null +++ b/e2e/governance/src/lib.rs @@ -0,0 +1,4 @@ +mod generated; + +pub use generated::programs::SPL_GOVERNANCE_ID as ID; +pub use generated::*; diff --git a/e2e/memo/src/generated/instructions/add_memo.rs b/e2e/memo/src/generated/instructions/add_memo.rs index ab0460e..e9a31c5 100644 --- a/e2e/memo/src/generated/instructions/add_memo.rs +++ b/e2e/memo/src/generated/instructions/add_memo.rs @@ -72,20 +72,18 @@ impl AddMemoInstructionArgs { /// /// ### Accounts: /// -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AddMemoBuilder { - memo: Option, + memo: TrailingStr, __remaining_accounts: Vec, } impl AddMemoBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn memo(&mut self, memo: TrailingStr) -> &mut Self { - self.memo = Some(memo); - self + pub fn new(memo: TrailingStr) -> Self { + Self { + memo, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -106,7 +104,7 @@ impl AddMemoBuilder { pub fn instruction(&self) -> solana_instruction::Instruction { let accounts = AddMemo {}; let args = AddMemoInstructionArgs { - memo: self.memo.clone().expect("memo is not set"), + memo: self.memo.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -195,19 +193,14 @@ pub struct AddMemoCpiBuilder<'a, 'b> { } impl<'a, 'b> AddMemoCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new(__program: &'b solana_account_info::AccountInfo<'a>, memo: TrailingStr) -> Self { let instruction = Box::new(AddMemoCpiBuilderInstruction { - __program: program, - memo: None, + __program, + memo, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn memo(&mut self, memo: TrailingStr) -> &mut Self { - self.instruction.memo = Some(memo); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -243,7 +236,7 @@ impl<'a, 'b> AddMemoCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AddMemoInstructionArgs { - memo: self.instruction.memo.clone().expect("memo is not set"), + memo: self.instruction.memo.clone(), }; let instruction = AddMemoCpi { __program: self.instruction.__program, @@ -259,7 +252,7 @@ impl<'a, 'b> AddMemoCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AddMemoCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - memo: Option, + memo: TrailingStr, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/accounts/nonce.rs b/e2e/system/src/generated/accounts/nonce.rs index c46f6d1..7500411 100644 --- a/e2e/system/src/generated/accounts/nonce.rs +++ b/e2e/system/src/generated/accounts/nonce.rs @@ -34,8 +34,14 @@ impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for Nonce { type Error = std::io::Error; fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { - let mut data: &[u8] = &(*account_info.data).borrow(); - Self::deserialize(&mut data) + if account_info.owner != &crate::SYSTEM_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) } } @@ -62,6 +68,11 @@ pub fn fetch_all_nonce( let account = accounts[i].as_ref().ok_or(std::io::Error::other(format!( "Account not found: {address}" )))?; + if account.owner != crate::SYSTEM_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } let data = Nonce::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::DecodedAccount { address, @@ -93,6 +104,11 @@ pub fn fetch_all_maybe_nonce( for i in 0..addresses.len() { let address = addresses[i]; if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::SYSTEM_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } let data = Nonce::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::MaybeAccount::Exists( crate::shared::DecodedAccount { diff --git a/e2e/system/src/generated/instructions/advance_nonce_account.rs b/e2e/system/src/generated/instructions/advance_nonce_account.rs index 4858fa9..d2e6417 100644 --- a/e2e/system/src/generated/instructions/advance_nonce_account.rs +++ b/e2e/system/src/generated/instructions/advance_nonce_account.rs @@ -84,22 +84,25 @@ impl Default for AdvanceNonceAccountInstructionData { /// 0. `[writable]` nonce_account /// 1. `[optional]` recent_blockhashes_sysvar (default to `SysvarRecentB1ockHashes11111111111111111111`) /// 2. `[signer]` nonce_authority -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AdvanceNonceAccountBuilder { - nonce_account: Option, + nonce_account: solana_address::Address, recent_blockhashes_sysvar: Option, - nonce_authority: Option, + nonce_authority: solana_address::Address, __remaining_accounts: Vec, } impl AdvanceNonceAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn nonce_account(&mut self, nonce_account: solana_address::Address) -> &mut Self { - self.nonce_account = Some(nonce_account); - self + pub fn new( + nonce_account: solana_address::Address, + nonce_authority: solana_address::Address, + ) -> Self { + Self { + nonce_account, + recent_blockhashes_sysvar: None, + nonce_authority, + __remaining_accounts: Vec::new(), + } } /// `[optional account, default to 'SysvarRecentB1ockHashes11111111111111111111']` #[inline(always)] @@ -110,11 +113,6 @@ impl AdvanceNonceAccountBuilder { self.recent_blockhashes_sysvar = Some(recent_blockhashes_sysvar); self } - #[inline(always)] - pub fn nonce_authority(&mut self, nonce_authority: solana_address::Address) -> &mut Self { - self.nonce_authority = Some(nonce_authority); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -132,12 +130,17 @@ impl AdvanceNonceAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let nonce_account = self.nonce_account; + let recent_blockhashes_sysvar = + self.recent_blockhashes_sysvar + .unwrap_or(solana_address::address!( + "SysvarRecentB1ockHashes11111111111111111111" + )); + let nonce_authority = self.nonce_authority; let accounts = AdvanceNonceAccount { - nonce_account: self.nonce_account.expect("nonce_account is not set"), - recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.unwrap_or( - solana_address::address!("SysvarRecentB1ockHashes11111111111111111111"), - ), - nonce_authority: self.nonce_authority.expect("nonce_authority is not set"), + nonce_account, + recent_blockhashes_sysvar, + nonce_authority, }; accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) @@ -259,40 +262,21 @@ pub struct AdvanceNonceAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> AdvanceNonceAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { let instruction = Box::new(AdvanceNonceAccountCpiBuilderInstruction { - __program: program, - nonce_account: None, - recent_blockhashes_sysvar: None, - nonce_authority: None, + __program, + nonce_account, + recent_blockhashes_sysvar, + nonce_authority, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn nonce_account( - &mut self, - nonce_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn recent_blockhashes_sysvar( - &mut self, - recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.recent_blockhashes_sysvar = Some(recent_blockhashes_sysvar); - self - } - #[inline(always)] - pub fn nonce_authority( - &mut self, - nonce_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_authority = Some(nonce_authority); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -329,21 +313,9 @@ impl<'a, 'b> AdvanceNonceAccountCpiBuilder<'a, 'b> { pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let instruction = AdvanceNonceAccountCpi { __program: self.instruction.__program, - - nonce_account: self - .instruction - .nonce_account - .expect("nonce_account is not set"), - - recent_blockhashes_sysvar: self - .instruction - .recent_blockhashes_sysvar - .expect("recent_blockhashes_sysvar is not set"), - - nonce_authority: self - .instruction - .nonce_authority - .expect("nonce_authority is not set"), + nonce_account: self.instruction.nonce_account, + recent_blockhashes_sysvar: self.instruction.recent_blockhashes_sysvar, + nonce_authority: self.instruction.nonce_authority, }; instruction.invoke_signed_with_remaining_accounts( signers_seeds, @@ -355,9 +327,9 @@ impl<'a, 'b> AdvanceNonceAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AdvanceNonceAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - nonce_account: Option<&'b solana_account_info::AccountInfo<'a>>, - recent_blockhashes_sysvar: Option<&'b solana_account_info::AccountInfo<'a>>, - nonce_authority: Option<&'b solana_account_info::AccountInfo<'a>>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: &'b solana_account_info::AccountInfo<'a>, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/allocate.rs b/e2e/system/src/generated/instructions/allocate.rs index ef7989f..9f95141 100644 --- a/e2e/system/src/generated/instructions/allocate.rs +++ b/e2e/system/src/generated/instructions/allocate.rs @@ -79,26 +79,20 @@ impl AllocateInstructionArgs { /// ### Accounts: /// /// 0. `[writable, signer]` new_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AllocateBuilder { - new_account: Option, - space: Option, + new_account: solana_address::Address, + space: u64, __remaining_accounts: Vec, } impl AllocateBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn new_account(&mut self, new_account: solana_address::Address) -> &mut Self { - self.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.space = Some(space); - self + pub fn new(new_account: solana_address::Address, space: u64) -> Self { + Self { + new_account, + space, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -117,11 +111,10 @@ impl AllocateBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = Allocate { - new_account: self.new_account.expect("new_account is not set"), - }; + let new_account = self.new_account; + let accounts = Allocate { new_account }; let args = AllocateInstructionArgs { - space: self.space.clone().expect("space is not set"), + space: self.space.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -225,28 +218,19 @@ pub struct AllocateCpiBuilder<'a, 'b> { } impl<'a, 'b> AllocateCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + space: u64, + ) -> Self { let instruction = Box::new(AllocateCpiBuilderInstruction { - __program: program, - new_account: None, - space: None, + __program, + new_account, + space, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn new_account( - &mut self, - new_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.instruction.space = Some(space); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -282,15 +266,11 @@ impl<'a, 'b> AllocateCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AllocateInstructionArgs { - space: self.instruction.space.clone().expect("space is not set"), + space: self.instruction.space.clone(), }; let instruction = AllocateCpi { __program: self.instruction.__program, - - new_account: self - .instruction - .new_account - .expect("new_account is not set"), + new_account: self.instruction.new_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -303,8 +283,8 @@ impl<'a, 'b> AllocateCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AllocateCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - new_account: Option<&'b solana_account_info::AccountInfo<'a>>, - space: Option, + new_account: &'b solana_account_info::AccountInfo<'a>, + space: u64, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/allocate_with_seed.rs b/e2e/system/src/generated/instructions/allocate_with_seed.rs index 0064540..48a3208 100644 --- a/e2e/system/src/generated/instructions/allocate_with_seed.rs +++ b/e2e/system/src/generated/instructions/allocate_with_seed.rs @@ -96,50 +96,35 @@ impl AllocateWithSeedInstructionArgs { /// /// 0. `[writable]` new_account /// 1. `[signer]` base_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AllocateWithSeedBuilder { - new_account: Option, - base_account: Option, - base: Option
, - seed: Option, - space: Option, - program_address: Option
, + new_account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + space: u64, + program_address: Address, __remaining_accounts: Vec, } impl AllocateWithSeedBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn new_account(&mut self, new_account: solana_address::Address) -> &mut Self { - self.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn base_account(&mut self, base_account: solana_address::Address) -> &mut Self { - self.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.seed = Some(seed); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.program_address = Some(program_address); - self + pub fn new( + new_account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + space: u64, + program_address: Address, + ) -> Self { + Self { + new_account, + base_account, + base, + seed, + space, + program_address, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -158,18 +143,17 @@ impl AllocateWithSeedBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let new_account = self.new_account; + let base_account = self.base_account; let accounts = AllocateWithSeed { - new_account: self.new_account.expect("new_account is not set"), - base_account: self.base_account.expect("base_account is not set"), + new_account, + base_account, }; let args = AllocateWithSeedInstructionArgs { - base: self.base.clone().expect("base is not set"), - seed: self.seed.clone().expect("seed is not set"), - space: self.space.clone().expect("space is not set"), - program_address: self - .program_address - .clone() - .expect("program_address is not set"), + base: self.base.clone(), + seed: self.seed.clone(), + space: self.space.clone(), + program_address: self.program_address.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -284,55 +268,27 @@ pub struct AllocateWithSeedCpiBuilder<'a, 'b> { } impl<'a, 'b> AllocateWithSeedCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + space: u64, + program_address: Address, + ) -> Self { let instruction = Box::new(AllocateWithSeedCpiBuilderInstruction { - __program: program, - new_account: None, - base_account: None, - base: None, - seed: None, - space: None, - program_address: None, + __program, + new_account, + base_account, + base, + seed, + space, + program_address, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn new_account( - &mut self, - new_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn base_account( - &mut self, - base_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.instruction.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.instruction.seed = Some(seed); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.instruction.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.instruction.program_address = Some(program_address); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -368,27 +324,15 @@ impl<'a, 'b> AllocateWithSeedCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AllocateWithSeedInstructionArgs { - base: self.instruction.base.clone().expect("base is not set"), - seed: self.instruction.seed.clone().expect("seed is not set"), - space: self.instruction.space.clone().expect("space is not set"), - program_address: self - .instruction - .program_address - .clone() - .expect("program_address is not set"), + base: self.instruction.base.clone(), + seed: self.instruction.seed.clone(), + space: self.instruction.space.clone(), + program_address: self.instruction.program_address.clone(), }; let instruction = AllocateWithSeedCpi { __program: self.instruction.__program, - - new_account: self - .instruction - .new_account - .expect("new_account is not set"), - - base_account: self - .instruction - .base_account - .expect("base_account is not set"), + new_account: self.instruction.new_account, + base_account: self.instruction.base_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -401,12 +345,12 @@ impl<'a, 'b> AllocateWithSeedCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AllocateWithSeedCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - new_account: Option<&'b solana_account_info::AccountInfo<'a>>, - base_account: Option<&'b solana_account_info::AccountInfo<'a>>, - base: Option
, - seed: Option, - space: Option, - program_address: Option
, + new_account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + space: u64, + program_address: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/assign.rs b/e2e/system/src/generated/instructions/assign.rs index 4ccc263..14ada32 100644 --- a/e2e/system/src/generated/instructions/assign.rs +++ b/e2e/system/src/generated/instructions/assign.rs @@ -80,26 +80,20 @@ impl AssignInstructionArgs { /// ### Accounts: /// /// 0. `[writable, signer]` account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AssignBuilder { - account: Option, - program_address: Option
, + account: solana_address::Address, + program_address: Address, __remaining_accounts: Vec, } impl AssignBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn account(&mut self, account: solana_address::Address) -> &mut Self { - self.account = Some(account); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.program_address = Some(program_address); - self + pub fn new(account: solana_address::Address, program_address: Address) -> Self { + Self { + account, + program_address, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -118,14 +112,10 @@ impl AssignBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = Assign { - account: self.account.expect("account is not set"), - }; + let account = self.account; + let accounts = Assign { account }; let args = AssignInstructionArgs { - program_address: self - .program_address - .clone() - .expect("program_address is not set"), + program_address: self.program_address.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -229,25 +219,19 @@ pub struct AssignCpiBuilder<'a, 'b> { } impl<'a, 'b> AssignCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + account: &'b solana_account_info::AccountInfo<'a>, + program_address: Address, + ) -> Self { let instruction = Box::new(AssignCpiBuilderInstruction { - __program: program, - account: None, - program_address: None, + __program, + account, + program_address, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn account(&mut self, account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.account = Some(account); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.instruction.program_address = Some(program_address); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -283,16 +267,11 @@ impl<'a, 'b> AssignCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AssignInstructionArgs { - program_address: self - .instruction - .program_address - .clone() - .expect("program_address is not set"), + program_address: self.instruction.program_address.clone(), }; let instruction = AssignCpi { __program: self.instruction.__program, - - account: self.instruction.account.expect("account is not set"), + account: self.instruction.account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -305,8 +284,8 @@ impl<'a, 'b> AssignCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AssignCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - account: Option<&'b solana_account_info::AccountInfo<'a>>, - program_address: Option
, + account: &'b solana_account_info::AccountInfo<'a>, + program_address: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/assign_with_seed.rs b/e2e/system/src/generated/instructions/assign_with_seed.rs index bd88c2f..e0f55f2 100644 --- a/e2e/system/src/generated/instructions/assign_with_seed.rs +++ b/e2e/system/src/generated/instructions/assign_with_seed.rs @@ -92,44 +92,32 @@ impl AssignWithSeedInstructionArgs { /// /// 0. `[writable]` account /// 1. `[signer]` base_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AssignWithSeedBuilder { - account: Option, - base_account: Option, - base: Option
, - seed: Option, - program_address: Option
, + account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + program_address: Address, __remaining_accounts: Vec, } impl AssignWithSeedBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn account(&mut self, account: solana_address::Address) -> &mut Self { - self.account = Some(account); - self - } - #[inline(always)] - pub fn base_account(&mut self, base_account: solana_address::Address) -> &mut Self { - self.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.seed = Some(seed); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.program_address = Some(program_address); - self + pub fn new( + account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + program_address: Address, + ) -> Self { + Self { + account, + base_account, + base, + seed, + program_address, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -148,17 +136,16 @@ impl AssignWithSeedBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let account = self.account; + let base_account = self.base_account; let accounts = AssignWithSeed { - account: self.account.expect("account is not set"), - base_account: self.base_account.expect("base_account is not set"), + account, + base_account, }; let args = AssignWithSeedInstructionArgs { - base: self.base.clone().expect("base is not set"), - seed: self.seed.clone().expect("seed is not set"), - program_address: self - .program_address - .clone() - .expect("program_address is not set"), + base: self.base.clone(), + seed: self.seed.clone(), + program_address: self.program_address.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -273,46 +260,25 @@ pub struct AssignWithSeedCpiBuilder<'a, 'b> { } impl<'a, 'b> AssignWithSeedCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + program_address: Address, + ) -> Self { let instruction = Box::new(AssignWithSeedCpiBuilderInstruction { - __program: program, - account: None, - base_account: None, - base: None, - seed: None, - program_address: None, + __program, + account, + base_account, + base, + seed, + program_address, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn account(&mut self, account: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.account = Some(account); - self - } - #[inline(always)] - pub fn base_account( - &mut self, - base_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.instruction.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.instruction.seed = Some(seed); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.instruction.program_address = Some(program_address); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -348,23 +314,14 @@ impl<'a, 'b> AssignWithSeedCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AssignWithSeedInstructionArgs { - base: self.instruction.base.clone().expect("base is not set"), - seed: self.instruction.seed.clone().expect("seed is not set"), - program_address: self - .instruction - .program_address - .clone() - .expect("program_address is not set"), + base: self.instruction.base.clone(), + seed: self.instruction.seed.clone(), + program_address: self.instruction.program_address.clone(), }; let instruction = AssignWithSeedCpi { __program: self.instruction.__program, - - account: self.instruction.account.expect("account is not set"), - - base_account: self - .instruction - .base_account - .expect("base_account is not set"), + account: self.instruction.account, + base_account: self.instruction.base_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -377,11 +334,11 @@ impl<'a, 'b> AssignWithSeedCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AssignWithSeedCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - account: Option<&'b solana_account_info::AccountInfo<'a>>, - base_account: Option<&'b solana_account_info::AccountInfo<'a>>, - base: Option
, - seed: Option, - program_address: Option
, + account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + program_address: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/authorize_nonce_account.rs b/e2e/system/src/generated/instructions/authorize_nonce_account.rs index e881144..4c77ac3 100644 --- a/e2e/system/src/generated/instructions/authorize_nonce_account.rs +++ b/e2e/system/src/generated/instructions/authorize_nonce_account.rs @@ -95,32 +95,26 @@ impl AuthorizeNonceAccountInstructionArgs { /// /// 0. `[writable]` nonce_account /// 1. `[signer]` nonce_authority -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct AuthorizeNonceAccountBuilder { - nonce_account: Option, - nonce_authority: Option, - new_nonce_authority: Option
, + nonce_account: solana_address::Address, + nonce_authority: solana_address::Address, + new_nonce_authority: Address, __remaining_accounts: Vec, } impl AuthorizeNonceAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn nonce_account(&mut self, nonce_account: solana_address::Address) -> &mut Self { - self.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn nonce_authority(&mut self, nonce_authority: solana_address::Address) -> &mut Self { - self.nonce_authority = Some(nonce_authority); - self - } - #[inline(always)] - pub fn new_nonce_authority(&mut self, new_nonce_authority: Address) -> &mut Self { - self.new_nonce_authority = Some(new_nonce_authority); - self + pub fn new( + nonce_account: solana_address::Address, + nonce_authority: solana_address::Address, + new_nonce_authority: Address, + ) -> Self { + Self { + nonce_account, + nonce_authority, + new_nonce_authority, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -139,15 +133,14 @@ impl AuthorizeNonceAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let nonce_account = self.nonce_account; + let nonce_authority = self.nonce_authority; let accounts = AuthorizeNonceAccount { - nonce_account: self.nonce_account.expect("nonce_account is not set"), - nonce_authority: self.nonce_authority.expect("nonce_authority is not set"), + nonce_account, + nonce_authority, }; let args = AuthorizeNonceAccountInstructionArgs { - new_nonce_authority: self - .new_nonce_authority - .clone() - .expect("new_nonce_authority is not set"), + new_nonce_authority: self.new_nonce_authority.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -264,37 +257,21 @@ pub struct AuthorizeNonceAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> AuthorizeNonceAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: &'b solana_account_info::AccountInfo<'a>, + new_nonce_authority: Address, + ) -> Self { let instruction = Box::new(AuthorizeNonceAccountCpiBuilderInstruction { - __program: program, - nonce_account: None, - nonce_authority: None, - new_nonce_authority: None, + __program, + nonce_account, + nonce_authority, + new_nonce_authority, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn nonce_account( - &mut self, - nonce_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn nonce_authority( - &mut self, - nonce_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_authority = Some(nonce_authority); - self - } - #[inline(always)] - pub fn new_nonce_authority(&mut self, new_nonce_authority: Address) -> &mut Self { - self.instruction.new_nonce_authority = Some(new_nonce_authority); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -330,24 +307,12 @@ impl<'a, 'b> AuthorizeNonceAccountCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = AuthorizeNonceAccountInstructionArgs { - new_nonce_authority: self - .instruction - .new_nonce_authority - .clone() - .expect("new_nonce_authority is not set"), + new_nonce_authority: self.instruction.new_nonce_authority.clone(), }; let instruction = AuthorizeNonceAccountCpi { __program: self.instruction.__program, - - nonce_account: self - .instruction - .nonce_account - .expect("nonce_account is not set"), - - nonce_authority: self - .instruction - .nonce_authority - .expect("nonce_authority is not set"), + nonce_account: self.instruction.nonce_account, + nonce_authority: self.instruction.nonce_authority, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -360,9 +325,9 @@ impl<'a, 'b> AuthorizeNonceAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct AuthorizeNonceAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - nonce_account: Option<&'b solana_account_info::AccountInfo<'a>>, - nonce_authority: Option<&'b solana_account_info::AccountInfo<'a>>, - new_nonce_authority: Option
, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: &'b solana_account_info::AccountInfo<'a>, + new_nonce_authority: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/create_account.rs b/e2e/system/src/generated/instructions/create_account.rs index b455e4c..8422404 100644 --- a/e2e/system/src/generated/instructions/create_account.rs +++ b/e2e/system/src/generated/instructions/create_account.rs @@ -89,44 +89,32 @@ impl CreateAccountInstructionArgs { /// /// 0. `[writable, signer]` payer /// 1. `[writable, signer]` new_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct CreateAccountBuilder { - payer: Option, - new_account: Option, - lamports: Option, - space: Option, - program_address: Option
, + payer: solana_address::Address, + new_account: solana_address::Address, + lamports: u64, + space: u64, + program_address: Address, __remaining_accounts: Vec, } impl CreateAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn payer(&mut self, payer: solana_address::Address) -> &mut Self { - self.payer = Some(payer); - self - } - #[inline(always)] - pub fn new_account(&mut self, new_account: solana_address::Address) -> &mut Self { - self.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn lamports(&mut self, lamports: u64) -> &mut Self { - self.lamports = Some(lamports); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.program_address = Some(program_address); - self + pub fn new( + payer: solana_address::Address, + new_account: solana_address::Address, + lamports: u64, + space: u64, + program_address: Address, + ) -> Self { + Self { + payer, + new_account, + lamports, + space, + program_address, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -145,17 +133,13 @@ impl CreateAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = CreateAccount { - payer: self.payer.expect("payer is not set"), - new_account: self.new_account.expect("new_account is not set"), - }; + let payer = self.payer; + let new_account = self.new_account; + let accounts = CreateAccount { payer, new_account }; let args = CreateAccountInstructionArgs { - lamports: self.lamports.clone().expect("lamports is not set"), - space: self.space.clone().expect("space is not set"), - program_address: self - .program_address - .clone() - .expect("program_address is not set"), + lamports: self.lamports.clone(), + space: self.space.clone(), + program_address: self.program_address.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -267,46 +251,25 @@ pub struct CreateAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> CreateAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + lamports: u64, + space: u64, + program_address: Address, + ) -> Self { let instruction = Box::new(CreateAccountCpiBuilderInstruction { - __program: program, - payer: None, - new_account: None, - lamports: None, - space: None, - program_address: None, + __program, + payer, + new_account, + lamports, + space, + program_address, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); - self - } - #[inline(always)] - pub fn new_account( - &mut self, - new_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn lamports(&mut self, lamports: u64) -> &mut Self { - self.instruction.lamports = Some(lamports); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.instruction.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.instruction.program_address = Some(program_address); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -342,27 +305,14 @@ impl<'a, 'b> CreateAccountCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = CreateAccountInstructionArgs { - lamports: self - .instruction - .lamports - .clone() - .expect("lamports is not set"), - space: self.instruction.space.clone().expect("space is not set"), - program_address: self - .instruction - .program_address - .clone() - .expect("program_address is not set"), + lamports: self.instruction.lamports.clone(), + space: self.instruction.space.clone(), + program_address: self.instruction.program_address.clone(), }; let instruction = CreateAccountCpi { __program: self.instruction.__program, - - payer: self.instruction.payer.expect("payer is not set"), - - new_account: self - .instruction - .new_account - .expect("new_account is not set"), + payer: self.instruction.payer, + new_account: self.instruction.new_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -375,11 +325,11 @@ impl<'a, 'b> CreateAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct CreateAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - payer: Option<&'b solana_account_info::AccountInfo<'a>>, - new_account: Option<&'b solana_account_info::AccountInfo<'a>>, - lamports: Option, - space: Option, - program_address: Option
, + payer: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + lamports: u64, + space: u64, + program_address: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/create_account_with_seed.rs b/e2e/system/src/generated/instructions/create_account_with_seed.rs index 97676e7..6483130 100644 --- a/e2e/system/src/generated/instructions/create_account_with_seed.rs +++ b/e2e/system/src/generated/instructions/create_account_with_seed.rs @@ -103,62 +103,41 @@ impl CreateAccountWithSeedInstructionArgs { /// 0. `[writable, signer]` payer /// 1. `[writable]` new_account /// 2. `[signer]` base_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct CreateAccountWithSeedBuilder { - payer: Option, - new_account: Option, - base_account: Option, - base: Option
, - seed: Option, - amount: Option, - space: Option, - program_address: Option
, + payer: solana_address::Address, + new_account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + amount: u64, + space: u64, + program_address: Address, __remaining_accounts: Vec, } impl CreateAccountWithSeedBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn payer(&mut self, payer: solana_address::Address) -> &mut Self { - self.payer = Some(payer); - self - } - #[inline(always)] - pub fn new_account(&mut self, new_account: solana_address::Address) -> &mut Self { - self.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn base_account(&mut self, base_account: solana_address::Address) -> &mut Self { - self.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.seed = Some(seed); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.amount = Some(amount); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.program_address = Some(program_address); - self + pub fn new( + payer: solana_address::Address, + new_account: solana_address::Address, + base_account: solana_address::Address, + base: Address, + seed: String, + amount: u64, + space: u64, + program_address: Address, + ) -> Self { + Self { + payer, + new_account, + base_account, + base, + seed, + amount, + space, + program_address, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -177,20 +156,20 @@ impl CreateAccountWithSeedBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let payer = self.payer; + let new_account = self.new_account; + let base_account = self.base_account; let accounts = CreateAccountWithSeed { - payer: self.payer.expect("payer is not set"), - new_account: self.new_account.expect("new_account is not set"), - base_account: self.base_account.expect("base_account is not set"), + payer, + new_account, + base_account, }; let args = CreateAccountWithSeedInstructionArgs { - base: self.base.clone().expect("base is not set"), - seed: self.seed.clone().expect("seed is not set"), - amount: self.amount.clone().expect("amount is not set"), - space: self.space.clone().expect("space is not set"), - program_address: self - .program_address - .clone() - .expect("program_address is not set"), + base: self.base.clone(), + seed: self.seed.clone(), + amount: self.amount.clone(), + space: self.space.clone(), + program_address: self.program_address.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -315,67 +294,31 @@ pub struct CreateAccountWithSeedCpiBuilder<'a, 'b> { } impl<'a, 'b> CreateAccountWithSeedCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + amount: u64, + space: u64, + program_address: Address, + ) -> Self { let instruction = Box::new(CreateAccountWithSeedCpiBuilderInstruction { - __program: program, - payer: None, - new_account: None, - base_account: None, - base: None, - seed: None, - amount: None, - space: None, - program_address: None, + __program, + payer, + new_account, + base_account, + base, + seed, + amount, + space, + program_address, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); - self - } - #[inline(always)] - pub fn new_account( - &mut self, - new_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.new_account = Some(new_account); - self - } - #[inline(always)] - pub fn base_account( - &mut self, - base_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn base(&mut self, base: Address) -> &mut Self { - self.instruction.base = Some(base); - self - } - #[inline(always)] - pub fn seed(&mut self, seed: String) -> &mut Self { - self.instruction.seed = Some(seed); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.instruction.amount = Some(amount); - self - } - #[inline(always)] - pub fn space(&mut self, space: u64) -> &mut Self { - self.instruction.space = Some(space); - self - } - #[inline(always)] - pub fn program_address(&mut self, program_address: Address) -> &mut Self { - self.instruction.program_address = Some(program_address); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -411,30 +354,17 @@ impl<'a, 'b> CreateAccountWithSeedCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = CreateAccountWithSeedInstructionArgs { - base: self.instruction.base.clone().expect("base is not set"), - seed: self.instruction.seed.clone().expect("seed is not set"), - amount: self.instruction.amount.clone().expect("amount is not set"), - space: self.instruction.space.clone().expect("space is not set"), - program_address: self - .instruction - .program_address - .clone() - .expect("program_address is not set"), + base: self.instruction.base.clone(), + seed: self.instruction.seed.clone(), + amount: self.instruction.amount.clone(), + space: self.instruction.space.clone(), + program_address: self.instruction.program_address.clone(), }; let instruction = CreateAccountWithSeedCpi { __program: self.instruction.__program, - - payer: self.instruction.payer.expect("payer is not set"), - - new_account: self - .instruction - .new_account - .expect("new_account is not set"), - - base_account: self - .instruction - .base_account - .expect("base_account is not set"), + payer: self.instruction.payer, + new_account: self.instruction.new_account, + base_account: self.instruction.base_account, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -447,14 +377,14 @@ impl<'a, 'b> CreateAccountWithSeedCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct CreateAccountWithSeedCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - payer: Option<&'b solana_account_info::AccountInfo<'a>>, - new_account: Option<&'b solana_account_info::AccountInfo<'a>>, - base_account: Option<&'b solana_account_info::AccountInfo<'a>>, - base: Option
, - seed: Option, - amount: Option, - space: Option, - program_address: Option
, + payer: &'b solana_account_info::AccountInfo<'a>, + new_account: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + base: Address, + seed: String, + amount: u64, + space: u64, + program_address: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/initialize_nonce_account.rs b/e2e/system/src/generated/instructions/initialize_nonce_account.rs index f453f48..ad9ba5b 100644 --- a/e2e/system/src/generated/instructions/initialize_nonce_account.rs +++ b/e2e/system/src/generated/instructions/initialize_nonce_account.rs @@ -102,23 +102,24 @@ impl InitializeNonceAccountInstructionArgs { /// 0. `[writable]` nonce_account /// 1. `[optional]` recent_blockhashes_sysvar (default to `SysvarRecentB1ockHashes11111111111111111111`) /// 2. `[optional]` rent_sysvar (default to `SysvarRent111111111111111111111111111111111`) -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct InitializeNonceAccountBuilder { - nonce_account: Option, + nonce_account: solana_address::Address, recent_blockhashes_sysvar: Option, rent_sysvar: Option, - nonce_authority: Option
, + nonce_authority: Address, __remaining_accounts: Vec, } impl InitializeNonceAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn nonce_account(&mut self, nonce_account: solana_address::Address) -> &mut Self { - self.nonce_account = Some(nonce_account); - self + pub fn new(nonce_account: solana_address::Address, nonce_authority: Address) -> Self { + Self { + nonce_account, + recent_blockhashes_sysvar: None, + rent_sysvar: None, + nonce_authority, + __remaining_accounts: Vec::new(), + } } /// `[optional account, default to 'SysvarRecentB1ockHashes11111111111111111111']` #[inline(always)] @@ -135,11 +136,6 @@ impl InitializeNonceAccountBuilder { self.rent_sysvar = Some(rent_sysvar); self } - #[inline(always)] - pub fn nonce_authority(&mut self, nonce_authority: Address) -> &mut Self { - self.nonce_authority = Some(nonce_authority); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -157,20 +153,22 @@ impl InitializeNonceAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let nonce_account = self.nonce_account; + let recent_blockhashes_sysvar = + self.recent_blockhashes_sysvar + .unwrap_or(solana_address::address!( + "SysvarRecentB1ockHashes11111111111111111111" + )); + let rent_sysvar = self.rent_sysvar.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); let accounts = InitializeNonceAccount { - nonce_account: self.nonce_account.expect("nonce_account is not set"), - recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.unwrap_or( - solana_address::address!("SysvarRecentB1ockHashes11111111111111111111"), - ), - rent_sysvar: self.rent_sysvar.unwrap_or(solana_address::address!( - "SysvarRent111111111111111111111111111111111" - )), + nonce_account, + recent_blockhashes_sysvar, + rent_sysvar, }; let args = InitializeNonceAccountInstructionArgs { - nonce_authority: self - .nonce_authority - .clone() - .expect("nonce_authority is not set"), + nonce_authority: self.nonce_authority.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -298,46 +296,23 @@ pub struct InitializeNonceAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> InitializeNonceAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, + rent_sysvar: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: Address, + ) -> Self { let instruction = Box::new(InitializeNonceAccountCpiBuilderInstruction { - __program: program, - nonce_account: None, - recent_blockhashes_sysvar: None, - rent_sysvar: None, - nonce_authority: None, + __program, + nonce_account, + recent_blockhashes_sysvar, + rent_sysvar, + nonce_authority, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn nonce_account( - &mut self, - nonce_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn recent_blockhashes_sysvar( - &mut self, - recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.recent_blockhashes_sysvar = Some(recent_blockhashes_sysvar); - self - } - #[inline(always)] - pub fn rent_sysvar( - &mut self, - rent_sysvar: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.rent_sysvar = Some(rent_sysvar); - self - } - #[inline(always)] - pub fn nonce_authority(&mut self, nonce_authority: Address) -> &mut Self { - self.instruction.nonce_authority = Some(nonce_authority); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -373,29 +348,13 @@ impl<'a, 'b> InitializeNonceAccountCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = InitializeNonceAccountInstructionArgs { - nonce_authority: self - .instruction - .nonce_authority - .clone() - .expect("nonce_authority is not set"), + nonce_authority: self.instruction.nonce_authority.clone(), }; let instruction = InitializeNonceAccountCpi { __program: self.instruction.__program, - - nonce_account: self - .instruction - .nonce_account - .expect("nonce_account is not set"), - - recent_blockhashes_sysvar: self - .instruction - .recent_blockhashes_sysvar - .expect("recent_blockhashes_sysvar is not set"), - - rent_sysvar: self - .instruction - .rent_sysvar - .expect("rent_sysvar is not set"), + nonce_account: self.instruction.nonce_account, + recent_blockhashes_sysvar: self.instruction.recent_blockhashes_sysvar, + rent_sysvar: self.instruction.rent_sysvar, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -408,10 +367,10 @@ impl<'a, 'b> InitializeNonceAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct InitializeNonceAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - nonce_account: Option<&'b solana_account_info::AccountInfo<'a>>, - recent_blockhashes_sysvar: Option<&'b solana_account_info::AccountInfo<'a>>, - rent_sysvar: Option<&'b solana_account_info::AccountInfo<'a>>, - nonce_authority: Option
, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, + rent_sysvar: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/transfer_sol.rs b/e2e/system/src/generated/instructions/transfer_sol.rs index 6403821..dfa13c9 100644 --- a/e2e/system/src/generated/instructions/transfer_sol.rs +++ b/e2e/system/src/generated/instructions/transfer_sol.rs @@ -86,32 +86,26 @@ impl TransferSolInstructionArgs { /// /// 0. `[writable, signer]` source /// 1. `[writable]` destination -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct TransferSolBuilder { - source: Option, - destination: Option, - amount: Option, + source: solana_address::Address, + destination: solana_address::Address, + amount: u64, __remaining_accounts: Vec, } impl TransferSolBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn source(&mut self, source: solana_address::Address) -> &mut Self { - self.source = Some(source); - self - } - #[inline(always)] - pub fn destination(&mut self, destination: solana_address::Address) -> &mut Self { - self.destination = Some(destination); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.amount = Some(amount); - self + pub fn new( + source: solana_address::Address, + destination: solana_address::Address, + amount: u64, + ) -> Self { + Self { + source, + destination, + amount, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -130,12 +124,14 @@ impl TransferSolBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let source = self.source; + let destination = self.destination; let accounts = TransferSol { - source: self.source.expect("source is not set"), - destination: self.destination.expect("destination is not set"), + source, + destination, }; let args = TransferSolInstructionArgs { - amount: self.amount.clone().expect("amount is not set"), + amount: self.amount.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -247,34 +243,21 @@ pub struct TransferSolCpiBuilder<'a, 'b> { } impl<'a, 'b> TransferSolCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + source: &'b solana_account_info::AccountInfo<'a>, + destination: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + ) -> Self { let instruction = Box::new(TransferSolCpiBuilderInstruction { - __program: program, - source: None, - destination: None, - amount: None, + __program, + source, + destination, + amount, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn source(&mut self, source: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.source = Some(source); - self - } - #[inline(always)] - pub fn destination( - &mut self, - destination: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.destination = Some(destination); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.instruction.amount = Some(amount); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -310,17 +293,12 @@ impl<'a, 'b> TransferSolCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = TransferSolInstructionArgs { - amount: self.instruction.amount.clone().expect("amount is not set"), + amount: self.instruction.amount.clone(), }; let instruction = TransferSolCpi { __program: self.instruction.__program, - - source: self.instruction.source.expect("source is not set"), - - destination: self - .instruction - .destination - .expect("destination is not set"), + source: self.instruction.source, + destination: self.instruction.destination, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -333,9 +311,9 @@ impl<'a, 'b> TransferSolCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct TransferSolCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - source: Option<&'b solana_account_info::AccountInfo<'a>>, - destination: Option<&'b solana_account_info::AccountInfo<'a>>, - amount: Option, + source: &'b solana_account_info::AccountInfo<'a>, + destination: &'b solana_account_info::AccountInfo<'a>, + amount: u64, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs b/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs index 3fd3668..37c4681 100644 --- a/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs +++ b/e2e/system/src/generated/instructions/transfer_sol_with_seed.rs @@ -101,50 +101,35 @@ impl TransferSolWithSeedInstructionArgs { /// 0. `[writable]` source /// 1. `[signer]` base_account /// 2. `[writable]` destination -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct TransferSolWithSeedBuilder { - source: Option, - base_account: Option, - destination: Option, - amount: Option, - from_seed: Option, - from_owner: Option
, + source: solana_address::Address, + base_account: solana_address::Address, + destination: solana_address::Address, + amount: u64, + from_seed: String, + from_owner: Address, __remaining_accounts: Vec, } impl TransferSolWithSeedBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn source(&mut self, source: solana_address::Address) -> &mut Self { - self.source = Some(source); - self - } - #[inline(always)] - pub fn base_account(&mut self, base_account: solana_address::Address) -> &mut Self { - self.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn destination(&mut self, destination: solana_address::Address) -> &mut Self { - self.destination = Some(destination); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.amount = Some(amount); - self - } - #[inline(always)] - pub fn from_seed(&mut self, from_seed: String) -> &mut Self { - self.from_seed = Some(from_seed); - self - } - #[inline(always)] - pub fn from_owner(&mut self, from_owner: Address) -> &mut Self { - self.from_owner = Some(from_owner); - self + pub fn new( + source: solana_address::Address, + base_account: solana_address::Address, + destination: solana_address::Address, + amount: u64, + from_seed: String, + from_owner: Address, + ) -> Self { + Self { + source, + base_account, + destination, + amount, + from_seed, + from_owner, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -163,15 +148,18 @@ impl TransferSolWithSeedBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let source = self.source; + let base_account = self.base_account; + let destination = self.destination; let accounts = TransferSolWithSeed { - source: self.source.expect("source is not set"), - base_account: self.base_account.expect("base_account is not set"), - destination: self.destination.expect("destination is not set"), + source, + base_account, + destination, }; let args = TransferSolWithSeedInstructionArgs { - amount: self.amount.clone().expect("amount is not set"), - from_seed: self.from_seed.clone().expect("from_seed is not set"), - from_owner: self.from_owner.clone().expect("from_owner is not set"), + amount: self.amount.clone(), + from_seed: self.from_seed.clone(), + from_owner: self.from_owner.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -299,55 +287,27 @@ pub struct TransferSolWithSeedCpiBuilder<'a, 'b> { } impl<'a, 'b> TransferSolWithSeedCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + source: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + destination: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + from_seed: String, + from_owner: Address, + ) -> Self { let instruction = Box::new(TransferSolWithSeedCpiBuilderInstruction { - __program: program, - source: None, - base_account: None, - destination: None, - amount: None, - from_seed: None, - from_owner: None, + __program, + source, + base_account, + destination, + amount, + from_seed, + from_owner, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn source(&mut self, source: &'b solana_account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.source = Some(source); - self - } - #[inline(always)] - pub fn base_account( - &mut self, - base_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.base_account = Some(base_account); - self - } - #[inline(always)] - pub fn destination( - &mut self, - destination: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.destination = Some(destination); - self - } - #[inline(always)] - pub fn amount(&mut self, amount: u64) -> &mut Self { - self.instruction.amount = Some(amount); - self - } - #[inline(always)] - pub fn from_seed(&mut self, from_seed: String) -> &mut Self { - self.instruction.from_seed = Some(from_seed); - self - } - #[inline(always)] - pub fn from_owner(&mut self, from_owner: Address) -> &mut Self { - self.instruction.from_owner = Some(from_owner); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -383,32 +343,15 @@ impl<'a, 'b> TransferSolWithSeedCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = TransferSolWithSeedInstructionArgs { - amount: self.instruction.amount.clone().expect("amount is not set"), - from_seed: self - .instruction - .from_seed - .clone() - .expect("from_seed is not set"), - from_owner: self - .instruction - .from_owner - .clone() - .expect("from_owner is not set"), + amount: self.instruction.amount.clone(), + from_seed: self.instruction.from_seed.clone(), + from_owner: self.instruction.from_owner.clone(), }; let instruction = TransferSolWithSeedCpi { __program: self.instruction.__program, - - source: self.instruction.source.expect("source is not set"), - - base_account: self - .instruction - .base_account - .expect("base_account is not set"), - - destination: self - .instruction - .destination - .expect("destination is not set"), + source: self.instruction.source, + base_account: self.instruction.base_account, + destination: self.instruction.destination, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -421,12 +364,12 @@ impl<'a, 'b> TransferSolWithSeedCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct TransferSolWithSeedCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - source: Option<&'b solana_account_info::AccountInfo<'a>>, - base_account: Option<&'b solana_account_info::AccountInfo<'a>>, - destination: Option<&'b solana_account_info::AccountInfo<'a>>, - amount: Option, - from_seed: Option, - from_owner: Option
, + source: &'b solana_account_info::AccountInfo<'a>, + base_account: &'b solana_account_info::AccountInfo<'a>, + destination: &'b solana_account_info::AccountInfo<'a>, + amount: u64, + from_seed: String, + from_owner: Address, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/upgrade_nonce_account.rs b/e2e/system/src/generated/instructions/upgrade_nonce_account.rs index 7de98bc..653123b 100644 --- a/e2e/system/src/generated/instructions/upgrade_nonce_account.rs +++ b/e2e/system/src/generated/instructions/upgrade_nonce_account.rs @@ -70,20 +70,18 @@ impl Default for UpgradeNonceAccountInstructionData { /// ### Accounts: /// /// 0. `[writable]` nonce_account -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct UpgradeNonceAccountBuilder { - nonce_account: Option, + nonce_account: solana_address::Address, __remaining_accounts: Vec, } impl UpgradeNonceAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn nonce_account(&mut self, nonce_account: solana_address::Address) -> &mut Self { - self.nonce_account = Some(nonce_account); - self + pub fn new(nonce_account: solana_address::Address) -> Self { + Self { + nonce_account, + __remaining_accounts: Vec::new(), + } } /// Add an additional account to the instruction. #[inline(always)] @@ -102,9 +100,8 @@ impl UpgradeNonceAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = UpgradeNonceAccount { - nonce_account: self.nonce_account.expect("nonce_account is not set"), - }; + let nonce_account = self.nonce_account; + let accounts = UpgradeNonceAccount { nonce_account }; accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) } @@ -203,22 +200,17 @@ pub struct UpgradeNonceAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> UpgradeNonceAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { let instruction = Box::new(UpgradeNonceAccountCpiBuilderInstruction { - __program: program, - nonce_account: None, + __program, + nonce_account, __remaining_accounts: Vec::new(), }); Self { instruction } } - #[inline(always)] - pub fn nonce_account( - &mut self, - nonce_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_account = Some(nonce_account); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account( @@ -255,11 +247,7 @@ impl<'a, 'b> UpgradeNonceAccountCpiBuilder<'a, 'b> { pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let instruction = UpgradeNonceAccountCpi { __program: self.instruction.__program, - - nonce_account: self - .instruction - .nonce_account - .expect("nonce_account is not set"), + nonce_account: self.instruction.nonce_account, }; instruction.invoke_signed_with_remaining_accounts( signers_seeds, @@ -271,7 +259,7 @@ impl<'a, 'b> UpgradeNonceAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct UpgradeNonceAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - nonce_account: Option<&'b solana_account_info::AccountInfo<'a>>, + nonce_account: &'b solana_account_info::AccountInfo<'a>, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/system/src/generated/instructions/withdraw_nonce_account.rs b/e2e/system/src/generated/instructions/withdraw_nonce_account.rs index da43d7d..8f33967 100644 --- a/e2e/system/src/generated/instructions/withdraw_nonce_account.rs +++ b/e2e/system/src/generated/instructions/withdraw_nonce_account.rs @@ -115,30 +115,33 @@ impl WithdrawNonceAccountInstructionArgs { /// 2. `[optional]` recent_blockhashes_sysvar (default to `SysvarRecentB1ockHashes11111111111111111111`) /// 3. `[optional]` rent_sysvar (default to `SysvarRent111111111111111111111111111111111`) /// 4. `[signer]` nonce_authority -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct WithdrawNonceAccountBuilder { - nonce_account: Option, - recipient_account: Option, + nonce_account: solana_address::Address, + recipient_account: solana_address::Address, recent_blockhashes_sysvar: Option, rent_sysvar: Option, - nonce_authority: Option, - withdraw_amount: Option, + nonce_authority: solana_address::Address, + withdraw_amount: u64, __remaining_accounts: Vec, } impl WithdrawNonceAccountBuilder { - pub fn new() -> Self { - Self::default() - } - #[inline(always)] - pub fn nonce_account(&mut self, nonce_account: solana_address::Address) -> &mut Self { - self.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn recipient_account(&mut self, recipient_account: solana_address::Address) -> &mut Self { - self.recipient_account = Some(recipient_account); - self + pub fn new( + nonce_account: solana_address::Address, + recipient_account: solana_address::Address, + nonce_authority: solana_address::Address, + withdraw_amount: u64, + ) -> Self { + Self { + nonce_account, + recipient_account, + recent_blockhashes_sysvar: None, + rent_sysvar: None, + nonce_authority, + withdraw_amount, + __remaining_accounts: Vec::new(), + } } /// `[optional account, default to 'SysvarRecentB1ockHashes11111111111111111111']` #[inline(always)] @@ -155,16 +158,6 @@ impl WithdrawNonceAccountBuilder { self.rent_sysvar = Some(rent_sysvar); self } - #[inline(always)] - pub fn nonce_authority(&mut self, nonce_authority: solana_address::Address) -> &mut Self { - self.nonce_authority = Some(nonce_authority); - self - } - #[inline(always)] - pub fn withdraw_amount(&mut self, withdraw_amount: u64) -> &mut Self { - self.withdraw_amount = Some(withdraw_amount); - self - } /// Add an additional account to the instruction. #[inline(always)] pub fn add_remaining_account(&mut self, account: solana_instruction::AccountMeta) -> &mut Self { @@ -182,24 +175,26 @@ impl WithdrawNonceAccountBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let nonce_account = self.nonce_account; + let recipient_account = self.recipient_account; + let recent_blockhashes_sysvar = + self.recent_blockhashes_sysvar + .unwrap_or(solana_address::address!( + "SysvarRecentB1ockHashes11111111111111111111" + )); + let rent_sysvar = self.rent_sysvar.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let nonce_authority = self.nonce_authority; let accounts = WithdrawNonceAccount { - nonce_account: self.nonce_account.expect("nonce_account is not set"), - recipient_account: self - .recipient_account - .expect("recipient_account is not set"), - recent_blockhashes_sysvar: self.recent_blockhashes_sysvar.unwrap_or( - solana_address::address!("SysvarRecentB1ockHashes11111111111111111111"), - ), - rent_sysvar: self.rent_sysvar.unwrap_or(solana_address::address!( - "SysvarRent111111111111111111111111111111111" - )), - nonce_authority: self.nonce_authority.expect("nonce_authority is not set"), + nonce_account, + recipient_account, + recent_blockhashes_sysvar, + rent_sysvar, + nonce_authority, }; let args = WithdrawNonceAccountInstructionArgs { - withdraw_amount: self - .withdraw_amount - .clone() - .expect("withdraw_amount is not set"), + withdraw_amount: self.withdraw_amount.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -349,63 +344,26 @@ pub struct WithdrawNonceAccountCpiBuilder<'a, 'b> { } impl<'a, 'b> WithdrawNonceAccountCpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { - let instruction = Box::new(WithdrawNonceAccountCpiBuilderInstruction { - __program: program, - nonce_account: None, - recipient_account: None, - recent_blockhashes_sysvar: None, - rent_sysvar: None, - nonce_authority: None, - withdraw_amount: None, - __remaining_accounts: Vec::new(), - }); - Self { instruction } - } - #[inline(always)] - pub fn nonce_account( - &mut self, + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, nonce_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_account = Some(nonce_account); - self - } - #[inline(always)] - pub fn recipient_account( - &mut self, recipient_account: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.recipient_account = Some(recipient_account); - self - } - #[inline(always)] - pub fn recent_blockhashes_sysvar( - &mut self, recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.recent_blockhashes_sysvar = Some(recent_blockhashes_sysvar); - self - } - #[inline(always)] - pub fn rent_sysvar( - &mut self, rent_sysvar: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.rent_sysvar = Some(rent_sysvar); - self - } - #[inline(always)] - pub fn nonce_authority( - &mut self, nonce_authority: &'b solana_account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.nonce_authority = Some(nonce_authority); - self - } - #[inline(always)] - pub fn withdraw_amount(&mut self, withdraw_amount: u64) -> &mut Self { - self.instruction.withdraw_amount = Some(withdraw_amount); - self + withdraw_amount: u64, + ) -> Self { + let instruction = Box::new(WithdrawNonceAccountCpiBuilderInstruction { + __program, + nonce_account, + recipient_account, + recent_blockhashes_sysvar, + rent_sysvar, + nonce_authority, + withdraw_amount, + __remaining_accounts: Vec::new(), + }); + Self { instruction } } /// Add an additional account to the instruction. #[inline(always)] @@ -442,39 +400,15 @@ impl<'a, 'b> WithdrawNonceAccountCpiBuilder<'a, 'b> { #[allow(clippy::vec_init_then_push)] pub fn invoke_signed(&self, signers_seeds: &[&[&[u8]]]) -> solana_program_error::ProgramResult { let args = WithdrawNonceAccountInstructionArgs { - withdraw_amount: self - .instruction - .withdraw_amount - .clone() - .expect("withdraw_amount is not set"), + withdraw_amount: self.instruction.withdraw_amount.clone(), }; let instruction = WithdrawNonceAccountCpi { __program: self.instruction.__program, - - nonce_account: self - .instruction - .nonce_account - .expect("nonce_account is not set"), - - recipient_account: self - .instruction - .recipient_account - .expect("recipient_account is not set"), - - recent_blockhashes_sysvar: self - .instruction - .recent_blockhashes_sysvar - .expect("recent_blockhashes_sysvar is not set"), - - rent_sysvar: self - .instruction - .rent_sysvar - .expect("rent_sysvar is not set"), - - nonce_authority: self - .instruction - .nonce_authority - .expect("nonce_authority is not set"), + nonce_account: self.instruction.nonce_account, + recipient_account: self.instruction.recipient_account, + recent_blockhashes_sysvar: self.instruction.recent_blockhashes_sysvar, + rent_sysvar: self.instruction.rent_sysvar, + nonce_authority: self.instruction.nonce_authority, __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -487,12 +421,12 @@ impl<'a, 'b> WithdrawNonceAccountCpiBuilder<'a, 'b> { #[derive(Clone, Debug)] struct WithdrawNonceAccountCpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, - nonce_account: Option<&'b solana_account_info::AccountInfo<'a>>, - recipient_account: Option<&'b solana_account_info::AccountInfo<'a>>, - recent_blockhashes_sysvar: Option<&'b solana_account_info::AccountInfo<'a>>, - rent_sysvar: Option<&'b solana_account_info::AccountInfo<'a>>, - nonce_authority: Option<&'b solana_account_info::AccountInfo<'a>>, - withdraw_amount: Option, + nonce_account: &'b solana_account_info::AccountInfo<'a>, + recipient_account: &'b solana_account_info::AccountInfo<'a>, + recent_blockhashes_sysvar: &'b solana_account_info::AccountInfo<'a>, + rent_sysvar: &'b solana_account_info::AccountInfo<'a>, + nonce_authority: &'b solana_account_info::AccountInfo<'a>, + withdraw_amount: u64, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, } diff --git a/e2e/test.sh b/e2e/test.sh index 498b7a4..8274c91 100755 --- a/e2e/test.sh +++ b/e2e/test.sh @@ -18,5 +18,6 @@ function test_anchor_project() { test_project dummy test_project system test_project memo +test_project governance # test_project meteora # TODO: uncomment after some internal fixes test_anchor_project anchor \ No newline at end of file diff --git a/package.json b/package.json index 4e9bca1..3fd22de 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@codama/renderers-core": "^1.3.5", "@codama/visitors-core": "^1.5.0", "@iarna/toml": "^2.2.5", + "@noble/curves": "^2.0.1", "@solana/codecs-strings": "^6.0.0", "nunjucks": "^3.2.4", "semver": "^7.7.3" @@ -53,7 +54,7 @@ "devDependencies": { "@changesets/changelog-github": "^0.5.1", "@changesets/cli": "^2.29.7", - "@codama/nodes-from-anchor": "^1.3.6", + "@codama/nodes-from-anchor": "^1.4.0", "@solana/eslint-config-solana": "^5.0.0", "@solana/prettier-config-solana": "0.0.5", "@types/node": "^25", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0146059..823f696 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,22 +10,25 @@ importers: dependencies: '@codama/errors': specifier: ^1.5.0 - version: 1.5.0 + version: 1.5.1 '@codama/nodes': specifier: ^1.5.0 - version: 1.5.0 + version: 1.5.1 '@codama/renderers-core': specifier: ^1.3.5 - version: 1.3.5 + version: 1.3.6 '@codama/visitors-core': specifier: ^1.5.0 - version: 1.5.0 + version: 1.5.1 '@iarna/toml': specifier: ^2.2.5 version: 2.2.5 + '@noble/curves': + specifier: ^2.0.1 + version: 2.0.1 '@solana/codecs-strings': specifier: ^6.0.0 - version: 6.0.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + version: 6.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) nunjucks: specifier: ^3.2.4 version: 3.2.4 @@ -40,8 +43,8 @@ importers: specifier: ^2.29.7 version: 2.29.8(@types/node@25.2.3) '@codama/nodes-from-anchor': - specifier: ^1.3.6 - version: 1.3.6(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + specifier: ^1.4.0 + version: 1.4.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) '@solana/eslint-config-solana': specifier: ^5.0.0 version: 5.0.0(@eslint/js@9.39.1)(@types/eslint__js@8.42.3)(eslint-plugin-jest@29.0.1(@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(jest@30.1.3(@types/node@25.2.3))(typescript@5.9.3))(eslint-plugin-react-hooks@5.2.0(eslint@9.39.1))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.1))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.43.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(globals@14.0.0)(jest@30.1.3(@types/node@25.2.3))(typescript-eslint@8.43.0(eslint@9.39.1)(typescript@5.9.3))(typescript@5.9.3) @@ -84,42 +87,42 @@ importers: packages: - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': @@ -134,12 +137,12 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true @@ -164,8 +167,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -180,8 +183,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -228,8 +231,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -238,16 +241,16 @@ packages: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@0.2.3': @@ -314,49 +317,36 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@codama/errors@1.4.4': - resolution: {integrity: sha512-XC86H5X+zGTi0cSRKLc+wFkeXNsvnh+ttOgVnVHIljmXOJWbUt9wXhKding3UftipLWwlHPuoswERJ0vS0mO2A==} + '@codama/errors@1.5.1': + resolution: {integrity: sha512-kdLk/OSLBt03DoViRU1Xr0M7NZ7J/CSqaXV8fooF9qMRGPRJdgUeW2VkCGlLXDQSaIALrls3HkHmKRKbqqjSOA==} hasBin: true - '@codama/errors@1.5.0': - resolution: {integrity: sha512-i4cS+S7JaZXhofQHFY3cwzt8rqxUVPNaeJND5VOyKUbtcOi933YXJXk52gDG4mc+CpGqHJijsJjfSpr1lJGxzg==} - hasBin: true - - '@codama/node-types@1.4.4': - resolution: {integrity: sha512-uUeIz34Id/TTAMi4k5OVl9FByM/PawnlNIIVqgpooH9AS0UlniICZ+KJ/mdHZidJs/AGo6bSRoOPS1BLtMajyw==} - - '@codama/node-types@1.5.0': - resolution: {integrity: sha512-Ebz2vOUukmNaFXWdkni1ZihXkAIUnPYtqIMXYxKXOxjMP+TGz2q0lGtRo7sqw1pc2ksFBIkfBp5pZsl5p6gwXA==} + '@codama/node-types@1.5.1': + resolution: {integrity: sha512-jMGz93MSszb1iXAAyWWa0i7RQbLxGihLKRZ+zr9aBsjaFFmhXhONfTFeSXzbEfc05cajpd/gW2QI7xmQHlUDKQ==} - '@codama/nodes-from-anchor@1.3.6': - resolution: {integrity: sha512-614DZS9H5gW16Rkeu0ES8BHnDvbd8M9FLqPWnp9QUE0b+wCvWB36yZiRylJ4fw8gRDSc+FR7C2i3NXKycpvBEg==} + '@codama/nodes-from-anchor@1.4.0': + resolution: {integrity: sha512-RAn2I1SI8LPvFOFFOeG5AK4wtXc/olcGa7tebHH30zeY3t0cYbi2Y86hDck4pFC57KQWmKQFAOwvdCj5zAVaEA==} - '@codama/nodes@1.4.4': - resolution: {integrity: sha512-JzlY5qLk3rhsnu0nerC/Vkc9/2HjdsLtEpBtST0dxC1j9kpfHvIc2uyIj+5hlB1YIBRJIDNo+UOHGla8hidkaA==} + '@codama/nodes@1.5.1': + resolution: {integrity: sha512-6fIoH5Cfa5dFUE1fRxymZloeNg02klOT4fHsWwQavkkRWkoySgiti//w0j1itiZj6j5O+usujrwsZUJqSFjnhQ==} - '@codama/nodes@1.5.0': - resolution: {integrity: sha512-yg+xmorWiMNjS3n19CGIt/FZ/ZCuDIu+HEY45bq6gHu1MN3RtJZY+Q3v0ErnBPA60D8mNWkvkKoeSZXfzcAvfw==} + '@codama/renderers-core@1.3.6': + resolution: {integrity: sha512-m3yAmhrObnagyC7d8g9bZxyLC5YMpttLagRE0aAKD4zlDDh23o3zV7TxSYCh2nRCg5ObceflgvXdauIHUm/6Xg==} - '@codama/renderers-core@1.3.5': - resolution: {integrity: sha512-MuZLU+3LZPQb1HuZffwZl+v5JHQDe5LYHGhA1wTMNlwRedYIysSxBjogHNciNIHsKP3JjmqyYmLO5LCEp3hjaQ==} + '@codama/visitors-core@1.5.1': + resolution: {integrity: sha512-JotrDJLI7OfPNHulu4KtPfUDF/FYMC3RgEnv9lu47Fiiy0upbGAw1NorgBuoreyJ9Uj0GZyHt7Q5rjrCoa1U0g==} - '@codama/visitors-core@1.4.4': - resolution: {integrity: sha512-vk/4tczViAUHa7c8PF7FxN+JWbuTcDB0pIdrDbbO6eBPKDPQGZCUCEp6rXIYBVxfO129jWrNf2+CuyYre/c/vA==} + '@codama/visitors@1.5.1': + resolution: {integrity: sha512-8WcGP1tJKtqBfZ4mJsBRPjZ/H6+SPLWmiUoDTXRrVePQE4X4Yb04o6BoX2Uc3heZbfEc0rXdM1w8HTFvXBX4/A==} - '@codama/visitors-core@1.5.0': - resolution: {integrity: sha512-3PIAlBX0a06hIxzyPtQMfQcqWGFBgfbwysSwcXBbvHUYbemwhD6xwlBKJuqTwm9DyFj3faStp5fpvcp03Rjxtw==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@codama/visitors@1.4.4': - resolution: {integrity: sha512-3w2aRNvGV6/rXTfRDynXR82zoAqX0P4tlfQ/zT4I4Bby4xTobKgDZLyAstodmA0D878eKW7sMg4Gb1m1R5dOig==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} @@ -676,6 +666,12 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -863,6 +859,10 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@noble/curves@2.0.1': + resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} + engines: {node: '>= 20.19.0'} + '@noble/hashes@2.0.1': resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} engines: {node: '>= 20.19.0'} @@ -1116,8 +1116,8 @@ packages: cpu: [x64] os: [win32] - '@sinclair/typebox@0.34.41': - resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} + '@sinclair/typebox@0.34.48': + resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} '@sinonjs/commons@3.0.1': resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} @@ -1125,14 +1125,17 @@ packages: '@sinonjs/fake-timers@13.0.5': resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} - '@solana/codecs-core@5.0.0': - resolution: {integrity: sha512-rCG2d8OaamVF2/J//YyCgDqNJpUytVVltw9C8mJtEz5c6Se/LR6BFuG8g4xeJswq/ab4RFk5/HFdgbvNjKgQjA==} + '@solana/codecs-core@5.5.1': + resolution: {integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@solana/codecs-core@6.0.1': - resolution: {integrity: sha512-OnUQk94qfvfE0nVveZ638aNUL3tyRJoorUFiAG0ICTGUo3c6fkYb8vH23o/5O2qmuSmYND1sn+UCaldNMVkFpg==} + '@solana/codecs-core@6.5.0': + resolution: {integrity: sha512-Wb+YUj7vUKz5CxqZkrkugtQjxOP2fkMKnffySRlAmVAkpRnQvBY/2eP3VJAKTgDD4ru9xHSIQSpDu09hC/cQZg==} engines: {node: '>=20.18.0'} peerDependencies: typescript: ^5.0.0 @@ -1140,20 +1143,26 @@ packages: typescript: optional: true - '@solana/codecs-data-structures@5.0.0': - resolution: {integrity: sha512-y503Pqmv0LHcfcf0vQJGaxDvydQJbyCo8nK3nxn56EhFj5lBQ1NWb3WvTd83epigwuZurW2MhJARrpikfhQglQ==} + '@solana/codecs-data-structures@5.5.1': + resolution: {integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@solana/codecs-numbers@5.0.0': - resolution: {integrity: sha512-a2+skRLuUK02f/XFe4L0e1+wHCyfK25PkyseFps1v1l4pvevukFwth/EhSyrs6w5CsTJRVoR7MuE3E00PM4egw==} + '@solana/codecs-numbers@5.5.1': + resolution: {integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@solana/codecs-numbers@6.0.1': - resolution: {integrity: sha512-ZrI1NjUsf4I+Klue/2rlQbZLcGRom/G2E4VB/8x4IEHGOeFLQhXcxmnib8kdgomQRYOzF1BjVDmCYxvZr+6AWA==} + '@solana/codecs-numbers@6.5.0': + resolution: {integrity: sha512-gU/7eYqD+zl2Kwzo7ctt7YHaxF+c3RX164F+iU4X02dwq8DGVcypp+kmEF1QaO6OiShtdryTxhL+JJmEBjhdfA==} engines: {node: '>=20.18.0'} peerDependencies: typescript: ^5.0.0 @@ -1161,15 +1170,20 @@ packages: typescript: optional: true - '@solana/codecs-strings@5.0.0': - resolution: {integrity: sha512-ALkRwpV8bGR6qjAYw0YXZwp2YI4wzvKOJGmx04Ut8gMdbaUx7qOcJkhEQKI6ZVC3lAWSIS1N1wGccUZDwvfKxw==} + '@solana/codecs-strings@5.5.1': + resolution: {integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true - '@solana/codecs-strings@6.0.1': - resolution: {integrity: sha512-OmMIfMFbbJVIxveBeATKCj9DsmZ8l4vJPnOLHUop0hLWRiYHTQ1qokMqfk/X8PCmUjXmbXnlp63BikGtdKN3/g==} + '@solana/codecs-strings@6.5.0': + resolution: {integrity: sha512-9TuQQxumA9gWJeJzbv1GUg0+o0nZp204EijX3efR+lgBOKbkU7W0UWp33ygAZ+RvWE+kTs48ePoYoJ7UHpyxkQ==} engines: {node: '>=20.18.0'} peerDependencies: fastestsmallesttextencoderdecoder: ^1.0.22 @@ -1180,21 +1194,27 @@ packages: typescript: optional: true - '@solana/codecs@5.0.0': - resolution: {integrity: sha512-KOw0gFUSBxIMDWLJ3AkVFkEci91dw0Rpx3C6y83Our7fSW+SEP8vRZklCElieYR85LHVB1QIEhoeHR7rc+Ifkw==} + '@solana/codecs@5.5.1': + resolution: {integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@solana/errors@5.0.0': - resolution: {integrity: sha512-gTuhzO6E+ydfAAzqmqdPcvFyJwAzFKKIrqtnZPpgAuomcPYu+HSo0tuwSM/cTX0djmHt+GoOsf/julph+nvs2w==} + '@solana/errors@5.5.1': + resolution: {integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - '@solana/errors@6.0.1': - resolution: {integrity: sha512-sMe5GCsXto8F1KDeq9GbZR0+m841SqEYep3NAcYlC0lqF2RG4giaaPQHgrWI5DJR/L7yc8FzUIQfTxnaN7bwOQ==} + '@solana/errors@6.5.0': + resolution: {integrity: sha512-XPc0I8Ck6vgx8Uu+LVLewx/1RWDkXkY3lU+1aN1kmbrPAQWbX4Txk7GPmuIIFpyys8o5aKocYfNxJOPKvfaQhg==} engines: {node: '>=20.18.0'} hasBin: true peerDependencies: @@ -1219,11 +1239,14 @@ packages: typescript: ^5.6 typescript-eslint: ^8.11.0 - '@solana/options@5.0.0': - resolution: {integrity: sha512-ezHVBFb9FXVSn8LUVRD2tLb6fejU0x8KtGEYyCYh0J0pQuXSITV0IQCjcEopvu/ZxWdXOJyzjvmymnhz90on5A==} + '@solana/options@5.5.1': + resolution: {integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==} engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=5.3.3' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true '@solana/prettier-config-solana@0.0.5': resolution: {integrity: sha512-igtLH1QaX5xzSLlqteexRIg9X1QKA03xKYQc2qY1TrMDDhxKXoRZOStQPWdita2FVJzxTGz/tdMGC1vS0biRcg==} @@ -1284,6 +1307,9 @@ packages: '@types/node@25.2.3': resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + '@types/nunjucks@3.2.6': resolution: {integrity: sha512-pHiGtf83na1nCzliuAdq8GowYiXvH5l931xZ0YEHaLMNFgynpEqx+IPStlu7UaDkehfvl01e4x/9Tpwhy7Ue3w==} @@ -1329,8 +1355,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.48.1': - resolution: {integrity: sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==} + '@typescript-eslint/project-service@8.57.2': + resolution: {integrity: sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1343,8 +1369,8 @@ packages: resolution: {integrity: sha512-daSWlQ87ZhsjrbMLvpuuMAt3y4ba57AuvadcR7f3nl8eS3BjRc8L9VLxFLk92RL5xdXOg6IQ+qKjjqNEimGuAg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.48.1': - resolution: {integrity: sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==} + '@typescript-eslint/scope-manager@8.57.2': + resolution: {integrity: sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/tsconfig-utils@8.43.0': @@ -1353,8 +1379,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.48.1': - resolution: {integrity: sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==} + '@typescript-eslint/tsconfig-utils@8.57.2': + resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1374,8 +1400,8 @@ packages: resolution: {integrity: sha512-vQ2FZaxJpydjSZJKiSW/LJsabFFvV7KgLC5DiLhkBcykhQj8iK9BOaDmQt74nnKdLvceM5xmhaTF+pLekrxEkw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.48.1': - resolution: {integrity: sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==} + '@typescript-eslint/types@8.57.2': + resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@5.62.0': @@ -1393,8 +1419,8 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/typescript-estree@8.48.1': - resolution: {integrity: sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==} + '@typescript-eslint/typescript-estree@8.57.2': + resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1412,11 +1438,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.48.1': - resolution: {integrity: sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==} + '@typescript-eslint/utils@8.57.2': + resolution: {integrity: sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' '@typescript-eslint/visitor-keys@5.62.0': @@ -1427,8 +1453,8 @@ packages: resolution: {integrity: sha512-T+S1KqRD4sg/bHfLwrpF/K3gQLBM1n7Rp7OjjikjTEssI2YJzQpi5WXoynOaQ93ERIuq3O8RBTOUYDKszUCEHw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.48.1': - resolution: {integrity: sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==} + '@typescript-eslint/visitor-keys@8.57.2': + resolution: {integrity: sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.3.0': @@ -1663,8 +1689,13 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - baseline-browser-mapping@2.8.32: - resolution: {integrity: sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.10: + resolution: {integrity: sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==} + engines: {node: '>=6.0.0'} hasBin: true better-path-resolve@1.0.0: @@ -1677,12 +1708,16 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.4: + resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.28.0: - resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1726,8 +1761,8 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - caniuse-lite@1.0.30001757: - resolution: {integrity: sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==} + caniuse-lite@1.0.30001781: + resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} chai@6.2.1: resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} @@ -1756,12 +1791,12 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} - ci-info@4.3.1: - resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - cjs-module-lexer@2.1.1: - resolution: {integrity: sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==} + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -1781,10 +1816,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - commander@14.0.1: - resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==} - engines: {node: '>=20'} - commander@14.0.2: resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} engines: {node: '>=20'} @@ -1830,8 +1861,8 @@ packages: supports-color: optional: true - dedent@1.7.0: - resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -1872,8 +1903,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.263: - resolution: {integrity: sha512-DrqJ11Knd+lo+dv+lltvfMDLU27g14LMdH2b0O3Pio4uk0x+z7OR+JrmyacTPN2M8w3BrZ7/RTwG3R9B7irPlg==} + electron-to-chromium@1.5.322: + resolution: {integrity: sha512-vFU34OcrvMcH66T+dYC3G4nURmgfDVewMIu6Q2urXpumAPSMmzvcn04KVVV8Opikq8Vs5nUbO/8laNhNRqSzYw==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -1985,6 +2016,10 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@9.39.1: resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2579,13 +2614,24 @@ packages: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} @@ -2631,8 +2677,8 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-releases@2.0.36: + resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -2753,10 +2799,18 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -2895,6 +2949,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3001,8 +3060,8 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} term-size@2.2.1: @@ -3048,8 +3107,8 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -3121,6 +3180,9 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -3128,8 +3190,8 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - update-browserslist-db@1.1.4: - resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -3278,25 +3340,25 @@ packages: snapshots: - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.0': {} - '@babel/core@7.28.5': + '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 debug: 4.4.3 @@ -3306,41 +3368,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.1': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@babel/compat-data': 7.28.5 + '@babel/compat-data': 7.29.0 '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.0 + browserslist: 4.28.1 lru-cache: 5.1.1 semver: 6.3.1 '@babel/helper-globals@7.28.0': {} - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.28.6': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} '@babel/helper-string-parser@7.27.1': {} @@ -3348,121 +3410,121 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.28.4': + '@babel/helpers@7.29.2': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - '@babel/parser@7.28.5': + '@babel/parser@7.29.2': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 - '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.5)': + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.5)': + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.5)': + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.5)': + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 '@babel/runtime@7.28.4': {} - '@babel/template@7.27.2': + '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 debug: 4.4.3 transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -3628,79 +3690,60 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 - '@codama/errors@1.4.4': - dependencies: - '@codama/node-types': 1.4.4 - commander: 14.0.2 - picocolors: 1.1.1 - - '@codama/errors@1.5.0': + '@codama/errors@1.5.1': dependencies: - '@codama/node-types': 1.5.0 - commander: 14.0.2 + '@codama/node-types': 1.5.1 + commander: 14.0.3 picocolors: 1.1.1 - '@codama/node-types@1.4.4': {} + '@codama/node-types@1.5.1': {} - '@codama/node-types@1.5.0': {} - - '@codama/nodes-from-anchor@1.3.6(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@codama/nodes-from-anchor@1.4.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@codama/errors': 1.4.4 - '@codama/nodes': 1.4.4 - '@codama/visitors': 1.4.4 + '@codama/errors': 1.5.1 + '@codama/nodes': 1.5.1 + '@codama/visitors': 1.5.1 '@noble/hashes': 2.0.1 - '@solana/codecs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) transitivePeerDependencies: - fastestsmallesttextencoderdecoder - typescript - '@codama/nodes@1.4.4': - dependencies: - '@codama/errors': 1.4.4 - '@codama/node-types': 1.4.4 - - '@codama/nodes@1.5.0': + '@codama/nodes@1.5.1': dependencies: - '@codama/errors': 1.5.0 - '@codama/node-types': 1.5.0 + '@codama/errors': 1.5.1 + '@codama/node-types': 1.5.1 - '@codama/renderers-core@1.3.5': + '@codama/renderers-core@1.3.6': dependencies: - '@codama/errors': 1.5.0 - '@codama/nodes': 1.5.0 - '@codama/visitors-core': 1.5.0 + '@codama/errors': 1.5.1 + '@codama/nodes': 1.5.1 + '@codama/visitors-core': 1.5.1 - '@codama/visitors-core@1.4.4': + '@codama/visitors-core@1.5.1': dependencies: - '@codama/errors': 1.4.4 - '@codama/nodes': 1.4.4 + '@codama/errors': 1.5.1 + '@codama/nodes': 1.5.1 json-stable-stringify: 1.3.0 - '@codama/visitors-core@1.5.0': + '@codama/visitors@1.5.1': dependencies: - '@codama/errors': 1.5.0 - '@codama/nodes': 1.5.0 - json-stable-stringify: 1.3.0 - - '@codama/visitors@1.4.4': - dependencies: - '@codama/errors': 1.4.4 - '@codama/nodes': 1.4.4 - '@codama/visitors-core': 1.4.4 + '@codama/errors': 1.5.1 + '@codama/nodes': 1.5.1 + '@codama/visitors-core': 1.5.1 - '@emnapi/core@1.7.1': + '@emnapi/core@1.9.1': dependencies: - '@emnapi/wasi-threads': 1.1.0 + '@emnapi/wasi-threads': 1.2.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.9.1': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.1.0': + '@emnapi/wasi-threads@1.2.0': dependencies: tslib: 2.8.1 optional: true @@ -3866,6 +3909,11 @@ snapshots: eslint: 9.39.1 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.1)': + dependencies: + eslint: 9.39.1 + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': @@ -3955,7 +4003,7 @@ snapshots: '@jest/console@30.1.2': dependencies: '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 jest-message-util: 30.1.0 jest-util: 30.0.5 @@ -3969,14 +4017,14 @@ snapshots: '@jest/test-result': 30.1.3 '@jest/transform': 30.1.2 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 ansi-escapes: 4.3.2 chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 exit-x: 0.2.2 graceful-fs: 4.2.11 jest-changed-files: 30.0.5 - jest-config: 30.1.3(@types/node@25.2.3) + jest-config: 30.1.3(@types/node@25.5.0) jest-haste-map: 30.1.0 jest-message-util: 30.1.0 jest-regex-util: 30.0.1 @@ -4003,7 +4051,7 @@ snapshots: dependencies: '@jest/fake-timers': 30.1.2 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 jest-mock: 30.0.5 '@jest/expect-utils@30.1.2': @@ -4021,7 +4069,7 @@ snapshots: dependencies: '@jest/types': 30.0.5 '@sinonjs/fake-timers': 13.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 jest-message-util: 30.1.0 jest-mock: 30.0.5 jest-util: 30.0.5 @@ -4039,7 +4087,7 @@ snapshots: '@jest/pattern@30.0.1': dependencies: - '@types/node': 25.2.3 + '@types/node': 25.5.0 jest-regex-util: 30.0.1 '@jest/reporters@30.1.3': @@ -4050,7 +4098,7 @@ snapshots: '@jest/transform': 30.1.2 '@jest/types': 30.0.5 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 collect-v8-coverage: 1.0.3 exit-x: 0.2.2 @@ -4072,7 +4120,7 @@ snapshots: '@jest/schemas@30.0.5': dependencies: - '@sinclair/typebox': 0.34.41 + '@sinclair/typebox': 0.34.48 '@jest/snapshot-utils@30.1.2': dependencies: @@ -4103,7 +4151,7 @@ snapshots: '@jest/transform@30.1.2': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@jest/types': 30.0.5 '@jridgewell/trace-mapping': 0.3.31 babel-plugin-istanbul: 7.0.1 @@ -4127,7 +4175,7 @@ snapshots: '@jest/schemas': 30.0.5 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 25.2.3 + '@types/node': 25.5.0 '@types/yargs': 17.0.35 chalk: 4.1.2 @@ -4168,11 +4216,15 @@ snapshots: '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 '@tybys/wasm-util': 0.10.1 optional: true + '@noble/curves@2.0.1': + dependencies: + '@noble/hashes': 2.0.1 + '@noble/hashes@2.0.1': {} '@nodelib/fs.scandir@2.1.5': @@ -4328,7 +4380,7 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.53.3': optional: true - '@sinclair/typebox@0.34.41': {} + '@sinclair/typebox@0.34.48': {} '@sinonjs/commons@3.0.1': dependencies: @@ -4338,72 +4390,78 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 - '@solana/codecs-core@5.0.0(typescript@5.9.3)': + '@solana/codecs-core@5.5.1(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: typescript: 5.9.3 - '@solana/codecs-core@6.0.1(typescript@5.9.3)': + '@solana/codecs-core@6.5.0(typescript@5.9.3)': dependencies: - '@solana/errors': 6.0.1(typescript@5.9.3) + '@solana/errors': 6.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-data-structures@5.0.0(typescript@5.9.3)': + '@solana/codecs-data-structures@5.5.1(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.3) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.3) - '@solana/errors': 5.0.0(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@5.0.0(typescript@5.9.3)': + '@solana/codecs-numbers@5.5.1(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.3) - '@solana/errors': 5.0.0(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: typescript: 5.9.3 - '@solana/codecs-numbers@6.0.1(typescript@5.9.3)': + '@solana/codecs-numbers@6.5.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.0.1(typescript@5.9.3) - '@solana/errors': 6.0.1(typescript@5.9.3) + '@solana/codecs-core': 6.5.0(typescript@5.9.3) + '@solana/errors': 6.5.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 - '@solana/codecs-strings@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/codecs-strings@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.3) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.3) - '@solana/errors': 5.0.0(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 - '@solana/codecs-strings@6.0.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/codecs-strings@6.5.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 6.0.1(typescript@5.9.3) - '@solana/codecs-numbers': 6.0.1(typescript@5.9.3) - '@solana/errors': 6.0.1(typescript@5.9.3) + '@solana/codecs-core': 6.5.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.5.0(typescript@5.9.3) + '@solana/errors': 6.5.0(typescript@5.9.3) optionalDependencies: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.3 - '@solana/codecs@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/codecs@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.3) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.3) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.3) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/options': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@5.0.0(typescript@5.9.3)': + '@solana/errors@5.5.1(typescript@5.9.3)': dependencies: chalk: 5.6.2 - commander: 14.0.1 + commander: 14.0.2 + optionalDependencies: typescript: 5.9.3 - '@solana/errors@6.0.1(typescript@5.9.3)': + '@solana/errors@6.5.0(typescript@5.9.3)': dependencies: chalk: 5.6.2 commander: 14.0.3 @@ -4425,13 +4483,14 @@ snapshots: typescript: 5.9.3 typescript-eslint: 8.43.0(eslint@9.39.1)(typescript@5.9.3) - '@solana/options@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@solana/options@5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.3) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.3) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.3) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) - '@solana/errors': 5.0.0(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -4449,24 +4508,24 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.28.0 '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@types/chai@5.2.3': dependencies: @@ -4508,6 +4567,10 @@ snapshots: dependencies: undici-types: 7.16.0 + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + '@types/nunjucks@3.2.6': {} '@types/semver@7.7.1': {} @@ -4534,7 +4597,7 @@ snapshots: graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -4561,17 +4624,17 @@ snapshots: '@typescript-eslint/project-service@8.43.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.48.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: @@ -4587,16 +4650,16 @@ snapshots: '@typescript-eslint/types': 8.43.0 '@typescript-eslint/visitor-keys': 8.43.0 - '@typescript-eslint/scope-manager@8.48.1': + '@typescript-eslint/scope-manager@8.57.2': dependencies: - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 '@typescript-eslint/tsconfig-utils@8.43.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.48.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -4607,7 +4670,7 @@ snapshots: '@typescript-eslint/utils': 8.43.0(eslint@9.39.1)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.1 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -4616,7 +4679,7 @@ snapshots: '@typescript-eslint/types@8.43.0': {} - '@typescript-eslint/types@8.48.1': {} + '@typescript-eslint/types@8.57.2': {} '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': dependencies: @@ -4625,7 +4688,7 @@ snapshots: debug: 4.4.3 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.7.3 + semver: 7.7.4 tsutils: 3.21.0(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -4641,31 +4704,31 @@ snapshots: debug: 4.4.3 fast-glob: 3.3.3 is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) + minimatch: 9.0.9 + semver: 7.7.4 + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.48.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.48.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.1(typescript@5.9.3) - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/visitor-keys': 8.48.1 + '@typescript-eslint/project-service': 8.57.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/visitor-keys': 8.57.2 debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.3 + minimatch: 10.2.4 + semver: 7.7.4 tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) + ts-api-utils: 2.5.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: - supports-color '@typescript-eslint/utils@5.62.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.1) '@types/json-schema': 7.0.15 '@types/semver': 7.7.1 '@typescript-eslint/scope-manager': 5.62.0 @@ -4673,14 +4736,14 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) eslint: 9.39.1 eslint-scope: 5.1.1 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript '@typescript-eslint/utils@8.43.0(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.1) '@typescript-eslint/scope-manager': 8.43.0 '@typescript-eslint/types': 8.43.0 '@typescript-eslint/typescript-estree': 8.43.0(typescript@5.9.3) @@ -4689,12 +4752,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.48.1(eslint@9.39.1)(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.2(eslint@9.39.1)(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@typescript-eslint/scope-manager': 8.48.1 - '@typescript-eslint/types': 8.48.1 - '@typescript-eslint/typescript-estree': 8.48.1(typescript@5.9.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.1) + '@typescript-eslint/scope-manager': 8.57.2 + '@typescript-eslint/types': 8.57.2 + '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) eslint: 9.39.1 typescript: 5.9.3 transitivePeerDependencies: @@ -4710,10 +4773,10 @@ snapshots: '@typescript-eslint/types': 8.43.0 eslint-visitor-keys: 4.2.1 - '@typescript-eslint/visitor-keys@8.48.1': + '@typescript-eslint/visitor-keys@8.57.2': dependencies: - '@typescript-eslint/types': 8.48.1 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.57.2 + eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.3.0': {} @@ -4865,7 +4928,7 @@ snapshots: anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 argparse@1.0.10: dependencies: @@ -4879,13 +4942,13 @@ snapshots: assertion-error@2.0.1: {} - babel-jest@30.1.2(@babel/core@7.28.5): + babel-jest@30.1.2(@babel/core@7.29.0): dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@jest/transform': 30.1.2 '@types/babel__core': 7.20.5 babel-plugin-istanbul: 7.0.1 - babel-preset-jest: 30.0.1(@babel/core@7.28.5) + babel-preset-jest: 30.0.1(@babel/core@7.29.0) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 @@ -4894,7 +4957,7 @@ snapshots: babel-plugin-istanbul@7.0.1: dependencies: - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 istanbul-lib-instrument: 6.0.3 @@ -4904,38 +4967,40 @@ snapshots: babel-plugin-jest-hoist@30.0.1: dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__core': 7.20.5 - babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.5): - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.5) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.5) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.5) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.5) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.5) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.5) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) - - babel-preset-jest@30.0.1(@babel/core@7.28.5): - dependencies: - '@babel/core': 7.28.5 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@30.0.1(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 babel-plugin-jest-hoist: 30.0.1 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) balanced-match@1.0.2: {} - baseline-browser-mapping@2.8.32: {} + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.10: {} better-path-resolve@1.0.0: dependencies: @@ -4950,17 +5015,21 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.4: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.28.0: + browserslist@4.28.1: dependencies: - baseline-browser-mapping: 2.8.32 - caniuse-lite: 1.0.30001757 - electron-to-chromium: 1.5.263 - node-releases: 2.0.27 - update-browserslist-db: 1.1.4(browserslist@4.28.0) + baseline-browser-mapping: 2.10.10 + caniuse-lite: 1.0.30001781 + electron-to-chromium: 1.5.322 + node-releases: 2.0.36 + update-browserslist-db: 1.2.3(browserslist@4.28.1) bser@2.1.1: dependencies: @@ -4998,7 +5067,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001757: {} + caniuse-lite@1.0.30001781: {} chai@6.2.1: {} @@ -5019,9 +5088,9 @@ snapshots: ci-info@3.9.0: {} - ci-info@4.3.1: {} + ci-info@4.4.0: {} - cjs-module-lexer@2.1.1: {} + cjs-module-lexer@2.2.0: {} cliui@8.0.1: dependencies: @@ -5039,8 +5108,6 @@ snapshots: color-name@1.1.4: {} - commander@14.0.1: {} - commander@14.0.2: {} commander@14.0.3: {} @@ -5069,7 +5136,7 @@ snapshots: dependencies: ms: 2.1.3 - dedent@1.7.0: {} + dedent@1.7.2: {} deep-is@0.1.4: {} @@ -5099,7 +5166,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.263: {} + electron-to-chromium@1.5.322: {} emittery@0.13.1: {} @@ -5192,7 +5259,7 @@ snapshots: eslint-plugin-jest@29.0.1(@typescript-eslint/eslint-plugin@8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(jest@30.1.3(@types/node@25.2.3))(typescript@5.9.3): dependencies: - '@typescript-eslint/utils': 8.48.1(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.2(eslint@9.39.1)(typescript@5.9.3) eslint: 9.39.1 optionalDependencies: '@typescript-eslint/eslint-plugin': 8.43.0(@typescript-eslint/parser@8.43.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3) @@ -5243,6 +5310,8 @@ snapshots: eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.1: {} + eslint@9.39.1: dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) @@ -5355,7 +5424,8 @@ snapshots: fast-levenshtein@2.0.6: {} - fastestsmallesttextencoderdecoder@1.0.22: {} + fastestsmallesttextencoderdecoder@1.0.22: + optional: true fastq@1.19.1: dependencies: @@ -5478,7 +5548,7 @@ snapshots: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 @@ -5580,11 +5650,11 @@ snapshots: istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.7.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -5625,10 +5695,10 @@ snapshots: '@jest/expect': 30.1.2 '@jest/test-result': 30.1.3 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 co: 4.6.0 - dedent: 1.7.0 + dedent: 1.7.2 is-generator-fn: 2.1.0 jest-each: 30.1.0 jest-matcher-utils: 30.1.2 @@ -5666,14 +5736,14 @@ snapshots: jest-config@30.1.3(@types/node@25.2.3): dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@jest/get-type': 30.1.0 '@jest/pattern': 30.0.1 '@jest/test-sequencer': 30.1.3 '@jest/types': 30.0.5 - babel-jest: 30.1.2(@babel/core@7.28.5) + babel-jest: 30.1.2(@babel/core@7.29.0) chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 deepmerge: 4.3.1 glob: 10.5.0 graceful-fs: 4.2.11 @@ -5696,6 +5766,38 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@30.1.3(@types/node@25.5.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.1.3 + '@jest/types': 30.0.5 + babel-jest: 30.1.2(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.1.3 + jest-docblock: 30.0.1 + jest-environment-node: 30.1.2 + jest-regex-util: 30.0.1 + jest-resolve: 30.1.3 + jest-runner: 30.1.3 + jest-util: 30.0.5 + jest-validate: 30.1.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 30.0.5 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 25.5.0 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-diff@30.1.2: dependencies: '@jest/diff-sequences': 30.0.1 @@ -5720,7 +5822,7 @@ snapshots: '@jest/environment': 30.1.2 '@jest/fake-timers': 30.1.2 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 jest-mock: 30.0.5 jest-util: 30.0.5 jest-validate: 30.1.0 @@ -5728,7 +5830,7 @@ snapshots: jest-haste-map@30.1.0: dependencies: '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -5754,7 +5856,7 @@ snapshots: jest-message-util@30.1.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 '@jest/types': 30.0.5 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -5767,7 +5869,7 @@ snapshots: jest-mock@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 jest-util: 30.0.5 jest-pnp-resolver@1.2.3(jest-resolve@30.1.3): @@ -5801,7 +5903,7 @@ snapshots: '@jest/test-result': 30.1.3 '@jest/transform': 30.1.2 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 emittery: 0.13.1 exit-x: 0.2.2 @@ -5830,9 +5932,9 @@ snapshots: '@jest/test-result': 30.1.3 '@jest/transform': 30.1.2 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 - cjs-module-lexer: 2.1.1 + cjs-module-lexer: 2.2.0 collect-v8-coverage: 1.0.3 glob: 10.5.0 graceful-fs: 4.2.11 @@ -5850,17 +5952,17 @@ snapshots: jest-snapshot@30.1.2: dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 '@jest/expect-utils': 30.1.2 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.1.2 '@jest/transform': 30.1.2 '@jest/types': 30.0.5 - babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.5) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) chalk: 4.1.2 expect: 30.1.2 graceful-fs: 4.2.11 @@ -5869,19 +5971,19 @@ snapshots: jest-message-util: 30.1.0 jest-util: 30.0.5 pretty-format: 30.0.5 - semver: 7.7.3 - synckit: 0.11.11 + semver: 7.7.4 + synckit: 0.11.12 transitivePeerDependencies: - supports-color jest-util@30.0.5: dependencies: '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 chalk: 4.1.2 - ci-info: 4.3.1 + ci-info: 4.4.0 graceful-fs: 4.2.11 - picomatch: 4.0.3 + picomatch: 4.0.4 jest-validate@30.1.0: dependencies: @@ -5896,7 +5998,7 @@ snapshots: dependencies: '@jest/test-result': 30.1.3 '@jest/types': 30.0.5 - '@types/node': 25.2.3 + '@types/node': 25.5.0 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -5905,7 +6007,7 @@ snapshots: jest-worker@30.1.0: dependencies: - '@types/node': 25.2.3 + '@types/node': 25.5.0 '@ungap/structured-clone': 1.3.0 jest-util: 30.0.5 merge-stream: 2.0.0 @@ -6012,7 +6114,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 makeerror@1.0.12: dependencies: @@ -6035,14 +6137,26 @@ snapshots: dependencies: '@isaacs/brace-expansion': 5.0.0 + minimatch@10.2.4: + dependencies: + brace-expansion: 5.0.4 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 + minimatch@9.0.9: + dependencies: + brace-expansion: 2.0.2 + minipass@7.1.2: {} mlly@1.8.0: @@ -6076,7 +6190,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.27: {} + node-releases@2.0.36: {} normalize-path@3.0.0: {} @@ -6151,7 +6265,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.0 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -6180,8 +6294,12 @@ snapshots: picomatch@2.3.1: {} + picomatch@2.3.2: {} + picomatch@4.0.3: {} + picomatch@4.0.4: {} + pify@4.0.1: {} pirates@4.0.7: {} @@ -6328,6 +6446,8 @@ snapshots: semver@7.7.3: {} + semver@7.7.4: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -6428,7 +6548,7 @@ snapshots: dependencies: has-flag: 4.0.0 - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -6438,7 +6558,7 @@ snapshots: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 - minimatch: 3.1.2 + minimatch: 3.1.5 thenify-all@1.6.0: dependencies: @@ -6469,7 +6589,7 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -6540,6 +6660,8 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.18.2: {} + universalify@0.1.2: {} unrs-resolver@1.11.1: @@ -6566,9 +6688,9 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - update-browserslist-db@1.1.4(browserslist@4.28.0): + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: - browserslist: 4.28.0 + browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 diff --git a/public/templates/accountsPage.njk b/public/templates/accountsPage.njk index 6d718d9..a74ca6b 100644 --- a/public/templates/accountsPage.njk +++ b/public/templates/accountsPage.njk @@ -42,11 +42,11 @@ impl {{ account.name | pascalCase }} { {% endfor %} ) = ( {% for seed in constantSeeds %} - {{ seed.valueManifest.render }}.as_bytes(), + {{ seed.seedBytesExpr }}, {% endfor %} ); {% elif constantSeeds.length === 1 %} - pub const PREFIX: &'static [u8] = {{ constantSeeds[0].valueManifest.render }}.as_bytes(); + pub const PREFIX: &'static [u8] = {{ constantSeeds[0].seedBytesExpr }}; {% endif %} {% endif %} @@ -67,7 +67,7 @@ impl {{ account.name | pascalCase }} { {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} crate::{{ program.name | snakeCase | upper }}_ID.as_ref(), {% elif seed.kind === 'constantPdaSeedNode' %} - {{ seed.valueManifest.render }}.as_bytes(), + {{ seed.seedBytesExpr }}, {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'publicKeyTypeNode' %} {{ seed.name | snakeCase }}.as_ref(), {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'bytesTypeNode' %} @@ -99,7 +99,7 @@ impl {{ account.name | pascalCase }} { {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} crate::{{ program.name | snakeCase | upper }}_ID.as_ref(), {% elif seed.kind === 'constantPdaSeedNode' %} - {{ seed.valueManifest.render }}.as_bytes(), + {{ seed.seedBytesExpr }}, {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'publicKeyTypeNode' %} {{ seed.name | snakeCase }}.as_ref(), {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'bytesTypeNode' %} @@ -116,6 +116,14 @@ impl {{ account.name | pascalCase }} { #[inline(always)] pub fn from_bytes(data: &[u8]) -> Result { + {% if discriminatorConstantName %} + if data.get(..{{ discriminatorConstantName }}.len()) != Some(&{{ discriminatorConstantName }}[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + {% endif %} let mut data = data; Self::deserialize(&mut data) } @@ -125,8 +133,14 @@ impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for {{ account.name | pa type Error = std::io::Error; fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { - let mut data: &[u8] = &(*account_info.data).borrow(); - Self::deserialize(&mut data) + if account_info.owner != &crate::{{ program.name | snakeCase | upper }}_ID { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account owner", + )); + } + let data: &[u8] = &(*account_info.data).borrow(); + Self::from_bytes(data) } } @@ -151,6 +165,9 @@ pub fn fetch_all_{{ account.name | snakeCase }}( let address = addresses[i]; let account = accounts[i].as_ref() .ok_or(std::io::Error::other(format!("Account not found: {address}")))?; + if account.owner != crate::{{ program.name | snakeCase | upper }}_ID { + return Err(std::io::Error::other(format!("Invalid owner for account: {address}"))); + } let data = {{ account.name | pascalCase }}::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::DecodedAccount { address, account: account.clone(), data }); } @@ -177,6 +194,9 @@ pub fn fetch_all_maybe_{{ account.name | snakeCase }}( for i in 0..addresses.len() { let address = addresses[i]; if let Some(account) = accounts[i].as_ref() { + if account.owner != crate::{{ program.name | snakeCase | upper }}_ID { + return Err(std::io::Error::other(format!("Invalid owner for account: {address}"))); + } let data = {{ account.name | pascalCase }}::from_bytes(&account.data)?; decoded_accounts.push(crate::shared::MaybeAccount::Exists(crate::shared::DecodedAccount { address, account: account.clone(), data })); } else { @@ -189,6 +209,17 @@ pub fn fetch_all_maybe_{{ account.name | snakeCase }}( {% if anchorTraits %} #[cfg(feature = "anchor")] impl anchor_lang::AccountDeserialize for {{ account.name | pascalCase }} { + {% if discriminatorConstantName %} + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < {{ discriminatorConstantName }}.len() + || buf[..{{ discriminatorConstantName }}.len()] != {{ discriminatorConstantName }}[..] + { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch.into()); + } + Self::try_deserialize_unchecked(buf) + } + {% endif %} + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { Ok(Self::deserialize(buf)?) } @@ -215,7 +246,11 @@ pub fn fetch_all_maybe_{{ account.name | snakeCase }}( #} #[cfg(feature = "anchor-idl-build")] impl anchor_lang::Discriminator for {{ account.name | pascalCase }} { + {% if discriminatorConstantName %} + const DISCRIMINATOR: &[u8] = &{{ discriminatorConstantName }}; + {% else %} const DISCRIMINATOR: &[u8] = &[0; 8]; + {% endif %} } {% endif %} diff --git a/public/templates/instructionsCpiPageBuilder.njk b/public/templates/instructionsCpiPageBuilder.njk index cb1b0e6..d6b893a 100644 --- a/public/templates/instructionsCpiPageBuilder.njk +++ b/public/templates/instructionsCpiPageBuilder.njk @@ -10,10 +10,13 @@ {% if account.isSigner %} {% set modifiers = modifiers + ', signer' if modifiers.length > 0 else 'signer' %} {% endif %} - {% if account.isOptional %} + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} + {% if isBuilderOptional %} {% set modifiers = modifiers + ', optional' if modifiers.length > 0 else 'optional' %} {% endif %} {{ '/// ' + loop.index0 + '. `[' + modifiers + ']` ' + account.name | snakeCase }} + {{- " (default to `" + account.defaultValue.publicKey + "`)" if isBuilderOptional and account.defaultValue.kind === 'publicKeyValueNode' }} + {{- " (default to PDA derived from '" + account.defaultValue.pda.name + "')" if isBuilderOptional and account.defaultValue.kind === 'pdaValueNode' and (account.defaultValue.pda.kind === 'pdaLinkNode' or account.defaultValue.pda.kind === 'pdaNode') }} {% endfor %} #[derive(Clone, Debug)] pub struct {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { @@ -21,15 +24,37 @@ pub struct {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { } impl<'a, 'b> {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { - pub fn new(program: &'b solana_account_info::AccountInfo<'a>) -> Self { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} + {% if not isBuilderOptional %} + {{ account.name | snakeCase }}: {{ "(&'b solana_account_info::AccountInfo<'a>, bool)" if account.isSigner === 'either' else "&'b solana_account_info::AccountInfo<'a>" }}, + {% endif %} + {% endfor %} + {% for arg in instructionArgs %} + {% if not arg.default and not arg.optional and not arg.innerOptionType %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% endif %} + {% endfor %} + ) -> Self { let instruction = Box::new({{ instruction.name | pascalCase }}CpiBuilderInstruction { - __program: program, + __program, {% for account in instruction.accounts %} - {{ account.name | snakeCase }}: None, + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} + {% if isBuilderOptional %} + {{ account.name | snakeCase }}: None, + {% else %} + {{ account.name | snakeCase }}, + {% endif %} {% endfor %} {% for arg in instructionArgs %} {% if not arg.default %} - {{ arg.name | snakeCase }}: None, + {% if not arg.optional and not arg.innerOptionType %} + {{ arg.name | snakeCase }}, + {% else %} + {{ arg.name | snakeCase }}: None, + {% endif %} {% endif %} {% endfor %} __remaining_accounts: Vec::new(), @@ -37,32 +62,35 @@ impl<'a, 'b> {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { Self { instruction } } {% for account in instruction.accounts %} - {{'/// `[optional account]`\n' if account.isOptional }} - {{- macros.docblock(account.docs) -}} - #[inline(always)] - pub fn {{ account.name | snakeCase }}(&mut self, {{ account.name | snakeCase }}: {{ "Option<&'b solana_account_info::AccountInfo<'a>>" if account.isOptional else "&'b solana_account_info::AccountInfo<'a>" }}{{ ', as_signer: bool' if account.isSigner === 'either' }}) -> &mut Self { - {% if account.isOptional %} - {% if account.isSigner === 'either' %} - if let Some({{ account.name | snakeCase }}) = {{ account.name | snakeCase }} { - self.instruction.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); - } else { - self.instruction.{{ account.name | snakeCase }} = None; - } - {% else %} - self.instruction.{{ account.name | snakeCase }} = {{ account.name | snakeCase }}; - {% endif %} - {% else %} - {% if account.isSigner === 'either' %} - self.instruction.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} + {% if isBuilderOptional %} + {{'/// `[optional account]`\n' if account.isOptional }} + {{- macros.docblock(account.docs) -}} + #[inline(always)] + pub fn {{ account.name | snakeCase }}(&mut self, {{ account.name | snakeCase }}: {{ "Option<&'b solana_account_info::AccountInfo<'a>>" if account.isOptional else "&'b solana_account_info::AccountInfo<'a>" }}{{ ', as_signer: bool' if account.isSigner === 'either' }}) -> &mut Self { + {% if account.isOptional %} + {% if account.isSigner === 'either' %} + if let Some({{ account.name | snakeCase }}) = {{ account.name | snakeCase }} { + self.instruction.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + } else { + self.instruction.{{ account.name | snakeCase }} = None; + } + {% else %} + self.instruction.{{ account.name | snakeCase }} = {{ account.name | snakeCase }}; + {% endif %} {% else %} - self.instruction.{{ account.name | snakeCase }} = Some({{ account.name | snakeCase }}); + {% if account.isSigner === 'either' %} + self.instruction.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + {% else %} + self.instruction.{{ account.name | snakeCase }} = Some({{ account.name | snakeCase }}); + {% endif %} {% endif %} - {% endif %} - self - } + self + } + {% endif %} {% endfor %} {% for arg in instructionArgs %} - {% if not arg.default %} + {% if not arg.default and (arg.optional or arg.innerOptionType) %} {{'/// `[optional argument]`\n' if arg.innerOptionType }} {{- "/// `[optional argument, defaults to '" + arg.value + "']`\n" if not arg.innerOptionType and arg.value -}} {{- macros.docblock(arg.docs) -}} @@ -105,8 +133,10 @@ impl<'a, 'b> {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { {% else %} {{ arg.name | snakeCase }}: self.instruction.{{ arg.name | snakeCase }}.clone(){{ '.unwrap_or(' + arg.value + ')' if arg.value else '.expect(\"' + arg.name | snakeCase + ' is not set\")' }}, {% endif %} + {% elif arg.innerOptionType %} + {{ arg.name | snakeCase }}: self.instruction.{{ arg.name | snakeCase }}.clone(), {% else %} - {{ arg.name | snakeCase }}: self.instruction.{{ arg.name | snakeCase }}.clone(){{ '.expect(\"' + arg.name | snakeCase + ' is not set\")' if not arg.innerOptionType }}, + {{ arg.name | snakeCase }}: self.instruction.{{ arg.name | snakeCase }}.clone(), {% endif %} {% endif %} {% endfor %} @@ -114,8 +144,17 @@ impl<'a, 'b> {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { {% endif %} let instruction = {{ instruction.name | pascalCase }}Cpi { __program: self.instruction.__program, - {% for account in instruction.accounts %} - {{ account.name | snakeCase }}: self.instruction.{{ account.name | snakeCase }}{{ '.expect(\"' + account.name | snakeCase + ' is not set\")' if not account.isOptional }}, + {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} + {% if account.isOptional %} + {{ account.name | snakeCase }}: self.instruction.{{ account.name | snakeCase }}, + {% elif not isBuilderOptional %} + {{ account.name | snakeCase }}: self.instruction.{{ account.name | snakeCase }}, + {% elif account.defaultValue.kind === 'programIdValueNode' %} + {{ account.name | snakeCase }}: self.instruction.{{ account.name | snakeCase }}.unwrap_or(self.instruction.__program), + {% else %} + {{ account.name | snakeCase }}: self.instruction.{{ account.name | snakeCase }}.expect("{{ account.name | snakeCase }} is not set"), + {% endif %} {% endfor %} {% if hasArgs %} __args: args, @@ -129,15 +168,29 @@ impl<'a, 'b> {{ instruction.name | pascalCase }}CpiBuilder<'a, 'b> { struct {{ instruction.name | pascalCase }}CpiBuilderInstruction<'a, 'b> { __program: &'b solana_account_info::AccountInfo<'a>, {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in cpiBuilderOptionalAccounts %} {% if account.isSigner === 'either' %} - {{ account.name | snakeCase }}: Option<(&'b solana_account_info::AccountInfo<'a>, bool)>, + {% if isBuilderOptional %} + {{ account.name | snakeCase }}: Option<(&'b solana_account_info::AccountInfo<'a>, bool)>, + {% else %} + {{ account.name | snakeCase }}: (&'b solana_account_info::AccountInfo<'a>, bool), + {% endif %} {% else %} - {{ account.name | snakeCase }}: Option<&'b solana_account_info::AccountInfo<'a>>, + {% if isBuilderOptional %} + {{ account.name | snakeCase }}: Option<&'b solana_account_info::AccountInfo<'a>>, + {% else %} + {{ account.name | snakeCase }}: &'b solana_account_info::AccountInfo<'a>, + {% endif %} {% endif %} {% endfor %} {% for arg in instructionArgs %} {% if not arg.default %} - {{ arg.name | snakeCase }}: {{ arg.type if arg.innerOptionType else 'Option<' + arg.type + '>' }}, + {% set isArgOptional = arg.optional or arg.innerOptionType %} + {% if isArgOptional %} + {{ arg.name | snakeCase }}: {{ arg.type if arg.innerOptionType else 'Option<' + arg.type + '>' }}, + {% else %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% endif %} {% endif %} {% endfor %} /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/public/templates/instructionsPageBuilder.njk b/public/templates/instructionsPageBuilder.njk index 44b3682..46fe008 100644 --- a/public/templates/instructionsPageBuilder.njk +++ b/public/templates/instructionsPageBuilder.njk @@ -1,3 +1,9 @@ +{% set pdaResolved = [] %} +{% for account in resolvedAccounts %} + {% if account.pdaDefault %} + {% set _ = pdaResolved.push(account.name) %} + {% endif %} +{% endfor %} /// Instruction builder for `{{ instruction.name | pascalCase }}`. /// /// ### Accounts: @@ -10,64 +16,113 @@ {% if account.isSigner %} {% set modifiers = modifiers + ', signer' if modifiers.length > 0 else 'signer' %} {% endif %} - {% if account.isOptional or account.defaultValue.kind === 'publicKeyValueNode' %} + {% set isBuilderOptional = account.name in builderOptionalAccounts %} + {% if isBuilderOptional %} {% set modifiers = modifiers + ', optional' if modifiers.length > 0 else 'optional' %} {% endif %} {{ '/// ' + loop.index0 + '. `[' + modifiers + ']` ' + account.name | snakeCase }} {{- " (default to `" + account.defaultValue.publicKey + "`)" if account.defaultValue.kind === 'publicKeyValueNode' }} + {{- " (default to PDA derived from '" + account.defaultValue.pda.name + "')" if account.defaultValue.kind === 'pdaValueNode' and account.name in pdaResolved }} {% endfor %} -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug{{ ', Default' if not hasRequiredAccounts and not hasRequiredArgs }})] pub struct {{ instruction.name | pascalCase }}Builder { {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in builderOptionalAccounts %} {% if account.isSigner === 'either' %} - {{ account.name | snakeCase }}: Option<(solana_address::Address, bool)>, + {{ account.name | snakeCase }}: {{ 'Option<(solana_address::Address, bool)>' if isBuilderOptional else '(solana_address::Address, bool)' }}, {% else %} - {{ account.name | snakeCase }}: Option, + {{ account.name | snakeCase }}: {{ 'Option' if isBuilderOptional else 'solana_address::Address' }}, {% endif %} {% endfor %} {% for arg in instructionArgs %} {% if not arg.default %} - {{ arg.name | snakeCase }}: {{ arg.type if arg.innerOptionType else 'Option<' + arg.type + '>' }}, + {% set isArgOptional = arg.optional or arg.innerOptionType %} + {% if isArgOptional %} + {{ arg.name | snakeCase }}: {{ arg.type if arg.innerOptionType else 'Option<' + arg.type + '>' }}, + {% else %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% endif %} {% endif %} {% endfor %} __remaining_accounts: Vec, } impl {{ instruction.name | pascalCase }}Builder { - pub fn new() -> Self { - Self::default() - } + {% if hasRequiredAccounts or hasRequiredArgs %} + pub fn new( + {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in builderOptionalAccounts %} + {% if not isBuilderOptional %} + {{ account.name | snakeCase }}: {{ '(solana_address::Address, bool)' if account.isSigner === 'either' else 'solana_address::Address' }}, + {% endif %} + {% endfor %} + {% for arg in instructionArgs %} + {% if not arg.default and not arg.optional and not arg.innerOptionType %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% endif %} + {% endfor %} + ) -> Self { + Self { + {% for account in instruction.accounts %} + {% set isBuilderOptional = account.name in builderOptionalAccounts %} + {% if isBuilderOptional %} + {{ account.name | snakeCase }}: None, + {% else %} + {{ account.name | snakeCase }}, + {% endif %} + {% endfor %} + {% for arg in instructionArgs %} + {% if not arg.default %} + {% if not arg.optional and not arg.innerOptionType %} + {{ arg.name | snakeCase }}, + {% else %} + {{ arg.name | snakeCase }}: None, + {% endif %} + {% endif %} + {% endfor %} + __remaining_accounts: Vec::new(), + } + } + {% else %} + pub fn new() -> Self { + Self::default() + } + {% endif %} {% for account in instruction.accounts %} - {% if account.isOptional %} - {{ '/// `[optional account]`\n' -}} - {% else %} - {{ "/// `[optional account, default to '" + account.defaultValue.publicKey + "']`\n" if account.defaultValue.kind === 'publicKeyValueNode' -}} - {% endif %} - {{- macros.docblock(account.docs) -}} - #[inline(always)] - pub fn {{ account.name | snakeCase }}(&mut self, {{ account.name | snakeCase }}: {{ 'Option' if account.isOptional else 'solana_address::Address' }}{{ ', as_signer: bool' if account.isSigner === 'either' }}) -> &mut Self { + {% set isBuilderOptional = account.name in builderOptionalAccounts %} + {% if isBuilderOptional %} {% if account.isOptional %} - {% if account.isSigner === 'either' %} - if let Some({{ account.name | snakeCase }}) = {{ account.name | snakeCase }} { - self.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); - } else { - self.{{ account.name | snakeCase }} = None; - } - {% else %} - self.{{ account.name | snakeCase }} = {{ account.name | snakeCase }}; - {% endif %} + {{ '/// `[optional account]`\n' -}} {% else %} - {% if account.isSigner === 'either' %} - self.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + {{ "/// `[optional account, default to '" + account.defaultValue.publicKey + "']`\n" if account.defaultValue.kind === 'publicKeyValueNode' -}} + {{ "/// `[optional account, default to PDA derived from '" + account.defaultValue.pda.name + "']`\n" if account.defaultValue.kind === 'pdaValueNode' and account.name in pdaResolved -}} + {% endif %} + {{- macros.docblock(account.docs) -}} + #[inline(always)] + pub fn {{ account.name | snakeCase }}(&mut self, {{ account.name | snakeCase }}: {{ 'Option' if account.isOptional else 'solana_address::Address' }}{{ ', as_signer: bool' if account.isSigner === 'either' }}) -> &mut Self { + {% if account.isOptional %} + {% if account.isSigner === 'either' %} + if let Some({{ account.name | snakeCase }}) = {{ account.name | snakeCase }} { + self.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + } else { + self.{{ account.name | snakeCase }} = None; + } + {% else %} + self.{{ account.name | snakeCase }} = {{ account.name | snakeCase }}; + {% endif %} {% else %} - self.{{ account.name | snakeCase }} = Some({{ account.name | snakeCase }}); + {% if account.isSigner === 'either' %} + self.{{ account.name | snakeCase }} = Some(({{ account.name | snakeCase }}, as_signer)); + {% else %} + self.{{ account.name | snakeCase }} = Some({{ account.name | snakeCase }}); + {% endif %} {% endif %} - {% endif %} - self - } + self + } + {% endif %} {% endfor %} {% for arg in instructionArgs %} - {% if not arg.default %} + {% if not arg.default and (arg.optional or arg.innerOptionType) %} {{ '/// `[optional argument]`\n' if arg.innerOptionType }} {{- "/// `[optional argument, defaults to '" + arg.value + "']`\n" if not arg.innerOptionType and arg.value -}} {{- macros.docblock(arg.docs) -}} @@ -92,17 +147,53 @@ impl {{ instruction.name | pascalCase }}Builder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { - let accounts = {{ instruction.name | pascalCase }} { - {% for account in instruction.accounts %} - {% if account.isOptional %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}, - {% elif account.defaultValue.kind === 'programId' %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}, {# Program ID set on the instruction creation. #} - {% elif account.defaultValue.kind === 'publicKeyValueNode' %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.unwrap_or(solana_address::address!("{{ account.defaultValue.publicKey }}")), + {% for account in resolvedAccounts %} + {% if account.pdaDefault %} + {% if account.pdaDefault.isLinked and not account.pdaDefault.hasVariableSeeds %} + {% if account.isSigner === 'either' %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.map(|(k, _)| k).unwrap_or( + {% else %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.unwrap_or( + {% endif %} + crate::pdas::{{ account.pdaDefault.linkedPdaName | snakeCase | upper }}_ADDRESS + ); + {% else %} + {% if account.isSigner === 'either' %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.map(|(k, _)| k).unwrap_or_else(|| { + {% else %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.unwrap_or_else(|| { + {% endif %} + {% if account.pdaDefault.isLinked %} + crate::pdas::find_{{ account.pdaDefault.linkedPdaName | snakeCase }}_pda( + {% for seed in account.pdaDefault.renderedSeeds %} + {{ seed.render }}, + {% endfor %} + ).0 {% else %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.expect("{{ account.name | snakeCase }} is not set"), + solana_address::Address::find_program_address( + &[ + {% for seed in account.pdaDefault.renderedSeeds %} + {{ seed.render }}, + {% endfor %} + ], + &{{ account.pdaDefault.programAddressExpr }}, + ).0 {% endif %} + }); + {% endif %} + {% elif account.isOptional %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}; + {% elif account.defaultValue.kind === 'programIdValueNode' %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.unwrap_or(crate::{{ program.name | snakeCase | upper }}_ID); + {% elif account.defaultValue.kind === 'publicKeyValueNode' %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.unwrap_or(solana_address::address!("{{ account.defaultValue.publicKey }}")); + {% else %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}; + {% endif %} + {% endfor %} + let accounts = {{ instruction.name | pascalCase }} { + {% for account in instruction.accounts %} + {{ account.name | snakeCase }}, {% endfor %} }; {% if hasArgs %} @@ -115,8 +206,10 @@ impl {{ instruction.name | pascalCase }}Builder { {% else %} {{ arg.name | snakeCase }}: self.{{ arg.name | snakeCase }}.clone(){{ '.unwrap_or(' + arg.value + ')' if arg.value else '.expect(\"' + arg.name | snakeCase + ' is not set\")' }}, {% endif %} + {% elif arg.innerOptionType %} + {{ arg.name | snakeCase }}: self.{{ arg.name | snakeCase }}.clone(), {% else %} - {{ arg.name | snakeCase }}: self.{{ arg.name | snakeCase }}.clone(){{ '.expect(\"' + arg.name | snakeCase + ' is not set\")' if not arg.innerOptionType }}, + {{ arg.name | snakeCase }}: self.{{ arg.name | snakeCase }}.clone(), {% endif %} {% endif %} {% endfor %} diff --git a/public/templates/pdasMod.njk b/public/templates/pdasMod.njk new file mode 100644 index 0000000..51f08c6 --- /dev/null +++ b/public/templates/pdasMod.njk @@ -0,0 +1,13 @@ +{% extends "layout.njk" %} + +{% block main %} + +{% for pda in pdasToExport %} +pub mod {{ pda.name | snakeCase }}; +{% endfor %} + +{% for pda in pdasToExport %} +pub use self::{{ pda.name | snakeCase }}::*; +{% endfor %} + +{% endblock %} diff --git a/public/templates/pdasPage.njk b/public/templates/pdasPage.njk new file mode 100644 index 0000000..e385634 --- /dev/null +++ b/public/templates/pdasPage.njk @@ -0,0 +1,106 @@ +{% extends "layout.njk" %} +{% import "macros.njk" as macros %} + +{% block main %} + +{{ imports }} + +{% if program %} +use crate::{{ program.name | snakeCase | upper }}_ID; +{% endif %} + +{# Generate SEED constants for constant seeds #} +{% set constantIndex = 0 %} +{% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind !== 'programIdValueNode' %} +pub const {{ pda.name | snakeCase | upper }}_SEED{% if constantSeeds.length > 1 %}_{{ constantIndex }}{% endif %}: &'static [u8] = {{ seed.seedBytesExpr }}; + {% set constantIndex = constantIndex + 1 %} + {% endif %} +{% endfor %} +{% if precomputedAddress %} + +pub const {{ pda.name | snakeCase | upper }}_ADDRESS: solana_address::Address = + solana_address::address!("{{ precomputedAddress }}"); +{% endif %} + +{{- macros.docblock(pda.docs) -}} +pub fn create_{{ pda.name | snakeCase }}_pda( + {% if hasVariableSeeds %} + {% for seed in seeds %} + {% if seed.kind === 'variablePdaSeedNode' %} + {{ seed.name | snakeCase }}: {{ seed.typeManifest.type }}, + {% endif %} + {% endfor %} + {% endif %} + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + {% set constantUsageIndex = 0 %} + {% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} + {% if program %} + crate::{{ program.name | snakeCase | upper }}_ID.as_ref(), + {% endif %} + {% elif seed.kind === 'constantPdaSeedNode' %} + {{ pda.name | snakeCase | upper }}_SEED{% if constantSeeds.length > 1 %}_{{ constantUsageIndex }}{% endif %}, + {% set constantUsageIndex = constantUsageIndex + 1 %} + {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'publicKeyTypeNode' %} + {{ seed.name | snakeCase }}.as_ref(), + {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'bytesTypeNode' %} + &{{ seed.name | snakeCase }}, + {% else %} + {{ seed.name | snakeCase }}.to_string().as_ref(), + {% endif %} + {% endfor %} + &[bump], + ], + {% if program %} + &{{ program.name | snakeCase | upper }}_ID, + {% else %} + // Program ID not available + {% endif %} + ) +} + +{{- macros.docblock(pda.docs) -}} +pub fn find_{{ pda.name | snakeCase }}_pda( +{% if hasVariableSeeds %} + {% for seed in seeds %} + {% if seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'publicKeyTypeNode' %} + {{ seed.name | snakeCase }}: &{{ seed.typeManifest.type }}, + {% elif seed.kind === 'variablePdaSeedNode' %} + {{ seed.name | snakeCase }}: {{ seed.typeManifest.type }}, + {% endif %} + {% endfor %} +{% endif %} +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + {% set constantUsageIndex2 = 0 %} + {% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} + {% if program %} + crate::{{ program.name | snakeCase | upper }}_ID.as_ref(), + {% endif %} + {% elif seed.kind === 'constantPdaSeedNode' %} + {{ pda.name | snakeCase | upper }}_SEED{% if constantSeeds.length > 1 %}_{{ constantUsageIndex2 }}{% endif %}, + {% set constantUsageIndex2 = constantUsageIndex2 + 1 %} + {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'publicKeyTypeNode' %} + {{ seed.name | snakeCase }}.as_ref(), + {% elif seed.kind == 'variablePdaSeedNode' and seed.resolvedType.kind == 'bytesTypeNode' %} + &{{ seed.name | snakeCase }}, + {% else %} + {{ seed.name | snakeCase }}.to_string().as_ref(), + {% endif %} + {% endfor %} + ], + {% if program %} + &{{ program.name | snakeCase | upper }}_ID, + {% else %} + // Program ID not available + {% endif %} + ) +} + +{% endblock %} diff --git a/public/templates/rootMod.njk b/public/templates/rootMod.njk index d792bcb..6c9f256 100644 --- a/public/templates/rootMod.njk +++ b/public/templates/rootMod.njk @@ -12,6 +12,9 @@ {% if instructionsToExport.length > 0 %} pub mod instructions; {% endif %} + {% if pdasToExport.length > 0 %} + pub mod pdas; + {% endif %} {% if programsToExport.length > 0 %} pub mod programs; {% endif %} diff --git a/src/getRenderMapVisitor.ts b/src/getRenderMapVisitor.ts index 55e65a1..2c7c9a1 100644 --- a/src/getRenderMapVisitor.ts +++ b/src/getRenderMapVisitor.ts @@ -1,14 +1,19 @@ import { logWarn } from '@codama/errors'; import { + constantValueNode, getAllAccounts, getAllDefinedTypes, getAllInstructionsWithSubs, + getAllPdas, getAllPrograms, + type InstructionAccountNode, + type InstructionArgumentNode, InstructionNode, isNode, isNodeFilter, pascalCase, - ProgramNode, + type PdaNode, + type ProgramNode, resolveNestedTypeNode, snakeCase, structTypeNodeFromInstructionArgumentNodes, @@ -17,6 +22,7 @@ import { import { addToRenderMap, createRenderMap, mergeRenderMaps } from '@codama/renderers-core'; import { extendVisitor, + findProgramNodeFromPath, LinkableDictionary, NodeStack, pipe, @@ -31,9 +37,12 @@ import { ImportMap } from './ImportMap'; import { renderValueNode } from './renderValueNodeVisitor'; import { CargoDependencies, + computePdaAddress, Fragment, + getByteArrayDiscriminatorConstantName, getDiscriminatorConstants, getImportFromFactory, + type GetImportFromFunction, getTraitsFromNodeFactory, LinkOverrides, render, @@ -53,7 +62,6 @@ export type GetRenderMapOptions = { export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); const stack = new NodeStack(); - let program: ProgramNode | null = null; const renderParentInstructions = options.renderParentInstructions ?? false; const dependencyMap = options.dependencyMap ?? {}; @@ -68,11 +76,16 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { return pipe( staticVisitor(() => createRenderMap(), { - keys: ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], + keys: ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode', 'pdaNode'], }), v => extendVisitor(v, { visitAccount(node) { + const accountPath = stack.getPath('accountNode'); + const program = findProgramNodeFromPath(accountPath); + if (!program) { + throw new Error('Account must be visited inside a program.'); + } const typeManifest = visit(node, typeManifestVisitor); // Discriminator constants. @@ -85,6 +98,12 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { typeManifestVisitor, }); + const discriminatorConstantName = getByteArrayDiscriminatorConstantName({ + discriminatorNodes: node.discriminators ?? [], + fields, + prefix: node.name, + }); + // Seeds. const seedsImports = new ImportMap(); const pda = node.pda ? linkables.get([...stack.getPath(), node.pda]) : undefined; @@ -100,10 +119,22 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { return seed; } const seedManifest = visit(seed.type, typeManifestVisitor); - const valueManifest = renderValueNode(seed.value, getImportFrom, true); - seedsImports.mergeWith(valueManifest.imports); const resolvedType = resolveNestedTypeNode(seed.type); - return { ...seed, resolvedType, typeManifest: seedManifest, valueManifest }; + let seedBytesExpr: string; + if (isNode(seed.value, 'stringValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + seedsImports.mergeWith(m.imports); + seedBytesExpr = `b${m.render}`; + } else if (isNode(seed.value, 'bytesValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + seedsImports.mergeWith(m.imports); + seedBytesExpr = `&${m.render}`; + } else { + const m = renderValueNode(constantValueNode(seed.type, seed.value), getImportFrom, true); + seedsImports.mergeWith(m.imports); + seedBytesExpr = `&${m.render}`; + } + return { ...seed, resolvedType, seedBytesExpr, typeManifest: seedManifest }; }); const hasVariableSeeds = pdaSeeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0; const constantSeeds = seeds @@ -120,6 +151,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { account: node, anchorTraits, constantSeeds, + discriminatorConstantName, discriminatorConstants: discriminatorConstants.render, hasVariableSeeds, imports: imports.toString(dependencyMap), @@ -149,6 +181,11 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }, visitInstruction(node) { + const instructionPath = stack.getPath('instructionNode'); + const program = findProgramNodeFromPath(instructionPath); + if (!program) { + throw new Error('Instruction must be visited inside a program.'); + } // Imports. const imports = new ImportMap(); @@ -239,30 +276,155 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { .mergeWith(discriminatorConstants.imports) .remove(`generatedInstructions::${pascalCase(node.name)}`); + // Accounts that are optional in the builder (have defaults or are IDL-optional). + const builderOptionalAccounts = new Set( + node.accounts + .filter( + account => + account.isOptional || + (account.defaultValue != null && + (isNode(account.defaultValue, ['publicKeyValueNode', 'programIdValueNode']) || + account.defaultValue.kind === 'pdaValueNode')), + ) + .map(a => a.name), + ); + // CPI can't derive AccountInfo from PDA/publicKey defaults. + const cpiBuilderOptionalAccounts = new Set( + node.accounts + .filter( + account => + account.isOptional || + (account.defaultValue != null && + isNode(account.defaultValue, ['programIdValueNode'])), + ) + .map(a => a.name), + ); + const hasRequiredAccounts = node.accounts.some(a => !builderOptionalAccounts.has(a.name)); + const hasRequiredArgs = instructionArgs.some( + arg => !arg.default && !arg.optional && !arg.innerOptionType, + ); + const requiredArgNames = instructionArgs + .filter(arg => !arg.default && !arg.optional && !arg.innerOptionType) + .map(arg => snakeCase(arg.name)); + + // Resolve PDA defaults and topologically sort accounts by dependency. + const resolvedAccounts = resolveInstructionPdaDefaults({ + accounts: node.accounts, + accountsAndArgsConflicts, + builderOptionalAccounts, + getImportFrom, + imports, + instructionArguments: node.arguments, + instructionName: node.name, + linkables, + program, + requiredArgNames, + stack, + }); + return createRenderMap(`instructions/${snakeCase(node.name)}.rs`, { content: render('instructionsPage.njk', { + accountsAndArgsConflicts, + builderOptionalAccounts: [...builderOptionalAccounts], + cpiBuilderOptionalAccounts: [...cpiBuilderOptionalAccounts], dataTraits: dataTraits.render, discriminatorConstants: discriminatorConstants.render, hasArgs, hasOptional, + hasRequiredAccounts, + hasRequiredArgs, imports: imports.toString(dependencyMap), instruction: node, instructionArgs, program, + requiredArgNames, + resolvedAccounts, typeManifest, }), imports, }); }, + visitPda(node) { + const pdaPath = stack.getPath('pdaNode'); + const program = findProgramNodeFromPath(pdaPath); + if (!program) { + throw new Error('PDA must be visited inside a program.'); + } + const imports = new ImportMap(); + + // Process seeds + const seeds = node.seeds.map(seed => { + if (isNode(seed, 'variablePdaSeedNode')) { + const seedManifest = visit(seed.type, typeManifestVisitor); + imports.mergeWith(seedManifest.imports); + const resolvedType = resolveNestedTypeNode(seed.type); + return { ...seed, resolvedType, typeManifest: seedManifest }; + } + if (isNode(seed.value, 'programIdValueNode')) { + return seed; + } + const seedManifest = visit(seed.type, typeManifestVisitor); + const resolvedType = resolveNestedTypeNode(seed.type); + let seedBytesExpr: string; + if (isNode(seed.value, 'stringValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + imports.mergeWith(m.imports); + seedBytesExpr = `b${m.render}`; + } else if (isNode(seed.value, 'bytesValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + imports.mergeWith(m.imports); + seedBytesExpr = `&${m.render}`; + } else { + const m = renderValueNode(constantValueNode(seed.type, seed.value), getImportFrom, true); + imports.mergeWith(m.imports); + seedBytesExpr = `&${m.render}`; + } + return { ...seed, resolvedType, seedBytesExpr, typeManifest: seedManifest }; + }); + + const hasVariableSeeds = node.seeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0; + const constantSeeds = seeds + .filter(isNodeFilter('constantPdaSeedNode')) + .filter(seed => !isNode(seed.value, 'programIdValueNode')); + + const programAddress = node.programId ?? program?.publicKey; + + let precomputedAddress: string | undefined; + if (!hasVariableSeeds && programAddress) { + precomputedAddress = computePdaAddress(node.seeds, programAddress) ?? undefined; + } + + // Template uses fully-qualified paths for return types and static methods, + // but variable seed types use the short form from the type manifest. + // Only remove the import when there are no variable seeds. + if (!hasVariableSeeds) { + imports.remove('solana_address::Address'); + } + + return createRenderMap(`pdas/${snakeCase(node.name)}.rs`, { + content: render('pdasPage.njk', { + constantSeeds, + hasVariableSeeds, + imports: imports.toString(dependencyMap), + pda: node, + precomputedAddress, + program, + programAddress, + seeds, + }), + imports, + }); + }, + visitProgram(node, { self }) { - program = node; let renders = mergeRenderMaps([ ...node.accounts.map(account => visit(account, self)), ...node.definedTypes.map(type => visit(type, self)), ...getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }).map(ix => visit(ix, self)), + ...node.pdas.map(pda => visit(pda, self)), ]); // Errors. @@ -277,7 +439,6 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }); } - program = null; return renders; }, @@ -287,11 +448,13 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const instructionsToExport = getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }); + const pdasToExport = getAllPdas(node); const definedTypesToExport = getAllDefinedTypes(node); const hasAnythingToExport = programsToExport.length > 0 || accountsToExport.length > 0 || instructionsToExport.length > 0 || + pdasToExport.length > 0 || definedTypesToExport.length > 0; const ctx = { @@ -299,6 +462,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { definedTypesToExport, hasAnythingToExport, instructionsToExport, + pdasToExport, programsToExport, root: node, }; @@ -318,6 +482,10 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { ? { content: render('instructionsMod.njk', ctx), imports: new ImportMap() } : undefined, ['mod.rs']: { content: render('rootMod.njk', ctx), imports: new ImportMap() }, + ['pdas/mod.rs']: + pdasToExport.length > 0 + ? { content: render('pdasMod.njk', ctx), imports: new ImportMap() } + : undefined, ['programs.rs']: programsToExport.length > 0 ? { content: render('programsMod.njk', ctx), imports: new ImportMap() } @@ -348,3 +516,380 @@ function getConflictsForInstructionAccountsAndArgs(instruction: InstructionNode) const duplicates = allNames.filter((e, i, a) => a.indexOf(e) !== i); return [...new Set(duplicates)]; } + +type RenderedSeed = { + kind: 'accountRef' | 'argumentRef' | 'constant' | 'programId' | 'value'; + rawName?: string; + render: string; +}; + +type ResolvedPdaDefault = { + accountDeps: string[]; + hasVariableSeeds: boolean; + isLinked: boolean; + linkedPdaName?: string; + programAddressExpr?: string; + renderedSeeds: RenderedSeed[]; +}; + +type ResolvedAccount = InstructionAccountNode & { + pdaDefault: ResolvedPdaDefault | null; +}; + +function resolveInstructionPdaDefaults(ctx: { + accounts: readonly InstructionAccountNode[]; + accountsAndArgsConflicts: string[]; + builderOptionalAccounts: Set; + getImportFrom: GetImportFromFunction; + imports: ImportMap; + instructionArguments: readonly InstructionArgumentNode[]; + instructionName: string; + linkables: LinkableDictionary; + program: ProgramNode; + requiredArgNames: string[]; + stack: NodeStack; +}): ResolvedAccount[] { + const { + accounts, + accountsAndArgsConflicts, + builderOptionalAccounts, + getImportFrom, + imports, + instructionArguments, + instructionName, + linkables, + program, + requiredArgNames, + stack, + } = ctx; + + // Cast to string to avoid branded CamelCaseString type. + const pdaDefaultedNames = new Set( + accounts.filter(a => a.defaultValue?.kind === 'pdaValueNode').map(a => a.name as string), + ); + + const resolvedPdas: Record = {}; + + for (const account of accounts) { + if (!account.defaultValue || !isNode(account.defaultValue, 'pdaValueNode')) { + continue; + } + const defaultValue = account.defaultValue; + + let pdaNode: PdaNode | undefined; + const isLinked = isNode(defaultValue.pda, 'pdaLinkNode'); + const linkedPdaName = isLinked ? (defaultValue.pda as { name: string }).name : undefined; + + if (isLinked) { + pdaNode = linkables.get([...stack.getPath(), defaultValue.pda]) ?? undefined; + } else if (isNode(defaultValue.pda, 'pdaNode')) { + pdaNode = defaultValue.pda; + } + + // Linked PDAs can work without pdaNode (iterate defaultValue.seeds directly). + if (!isLinked && !pdaNode) { + logWarn( + `[Rust] Could not resolve PDA node for account [${account.name}] ` + + `in instruction [${instructionName}]. The account will be treated as required.`, + ); + continue; + } + + const programAddressExpr = pdaNode?.programId + ? `solana_address::address!("${pdaNode.programId}")` + : `crate::${snakeCase(program.name).toUpperCase()}_ID`; + + // Upstream account defaults for seed resolution. + const accountDefaults: Record = {}; + const eitherSignerAccounts = new Set(); + for (const seedBinding of defaultValue.seeds) { + if (isNode(seedBinding.value, 'accountValueNode')) { + const refName = seedBinding.value.name; + const refAccount = accounts.find(a => a.name === refName); + if (refAccount?.defaultValue && isNode(refAccount.defaultValue, 'publicKeyValueNode')) { + accountDefaults[refName] = `solana_address::address!("${refAccount.defaultValue.publicKey}")`; + } else if (refAccount?.defaultValue && isNode(refAccount.defaultValue, 'programIdValueNode')) { + accountDefaults[refName] = `crate::${snakeCase(program.name).toUpperCase()}_ID`; + } + if (refAccount?.isSigner === 'either') { + eitherSignerAccounts.add(refName); + } + } + } + + const renderedSeeds: RenderedSeed[] = []; + const accountDeps: string[] = []; + let seedsComplete = true; + + // Two rendering paths because extractPdasVisitor only extracts same-program + // PDAs — cross-program derivations (e.g. ATAs via the associated-token-program) + // stay inline as pdaNode since they can't live in this program's pdas module. + // + // Linked (pdaLinkNode): call the standalone find_*_pda() with typed args. + // Inline (pdaNode): emit find_program_address() with raw byte-slice seeds. + if (isLinked) { + for (const seedBinding of defaultValue.seeds) { + const seedValue = seedBinding.value; + + if (isNode(seedValue, 'accountValueNode')) { + const refName = snakeCase(seedValue.name); + const isEither = eitherSignerAccounts.has(seedValue.name); + const isOptional = builderOptionalAccounts.has(seedValue.name); + const eitherExtract = isEither ? (isOptional ? '.map(|(k, _)| k)' : '.0') : ''; + + if (pdaDefaultedNames.has(seedValue.name)) { + accountDeps.push(seedValue.name); + renderedSeeds.push({ kind: 'accountRef', rawName: refName, render: `&${refName}` }); + } else if (!isOptional) { + // Required account — direct field access, no Option unwrap. + renderedSeeds.push({ + kind: 'accountRef', + rawName: refName, + render: `&self.${refName}${eitherExtract}`, + }); + } else { + const defaultExpr = accountDefaults[seedValue.name]; + let render: string; + if (defaultExpr) { + render = `&self.${refName}${eitherExtract}.unwrap_or(${defaultExpr})`; + } else { + render = `&self.${refName}${eitherExtract}.expect("${refName} is needed for ${snakeCase(account.name)} PDA")`; + } + renderedSeeds.push({ kind: 'accountRef', rawName: refName, render }); + } + } else if (isNode(seedValue, 'argumentValueNode')) { + const argFieldName = accountsAndArgsConflicts.includes(seedValue.name) + ? `${seedValue.name}_arg` + : seedValue.name; + const fieldName = snakeCase(argFieldName); + const isRequiredArg = requiredArgNames.includes(fieldName); + + const arg = instructionArguments.find(a => a.name === seedValue.name); + let argDefault: { isOmitted: boolean; value: string } | null = null; + if (arg?.defaultValue && isNode(arg.defaultValue, VALUE_NODES)) { + const { render: value } = renderValueNode(arg.defaultValue, getImportFrom); + argDefault = { isOmitted: arg.defaultValueStrategy === 'omitted', value }; + } + + // Pubkey seeds need by-ref for the typed find_*_pda() signature. + let isByRef = false; + if (pdaNode) { + const pdaSeed = pdaNode.seeds.find( + s => isNode(s, 'variablePdaSeedNode') && s.name === seedBinding.name, + ); + if (pdaSeed && isNode(pdaSeed, 'variablePdaSeedNode')) { + isByRef = resolveNestedTypeNode(pdaSeed.type).kind === 'publicKeyTypeNode'; + } + } + + if (argDefault && argDefault.isOmitted) { + renderedSeeds.push({ + kind: 'argumentRef', + render: `${isByRef ? '&' : ''}${argDefault.value}`, + }); + } else if (isRequiredArg) { + // Required arg — direct field access, no Option unwrap. + renderedSeeds.push({ + kind: 'argumentRef', + render: `${isByRef ? '&' : ''}self.${fieldName}.clone()`, + }); + } else { + renderedSeeds.push({ + kind: 'argumentRef', + render: `${isByRef ? '&' : ''}self.${fieldName}.clone().expect("${fieldName} is needed for ${snakeCase(account.name)} PDA")`, + }); + } + } + } + } else { + for (const seed of pdaNode!.seeds) { + if (isNode(seed, 'constantPdaSeedNode')) { + if (isNode(seed.value, 'programIdValueNode')) { + renderedSeeds.push({ + kind: 'programId', + render: `crate::${snakeCase(program.name).toUpperCase()}_ID.as_ref()`, + }); + } else { + const valueManifest = renderValueNode(seed.value, getImportFrom); + imports.mergeWith(valueManifest.imports); + renderedSeeds.push({ kind: 'constant', render: `&${valueManifest.render}` }); + } + continue; + } + + if (!isNode(seed, 'variablePdaSeedNode')) continue; + + const binding = defaultValue.seeds.find(s => s.name === seed.name); + if (!binding) { + logWarn( + `[Rust] Missing seed value for variable seed [${seed.name}] ` + + `in PDA default for account [${account.name}] ` + + `of instruction [${instructionName}]. Skipping PDA resolution.`, + ); + seedsComplete = false; + break; + } + + const resolvedType = resolveNestedTypeNode(seed.type); + const seedValue = binding.value; + + if (isNode(seedValue, 'accountValueNode')) { + const refName = snakeCase(seedValue.name); + const isEither = eitherSignerAccounts.has(seedValue.name); + const isOptional = builderOptionalAccounts.has(seedValue.name); + const eitherExtract = isEither ? (isOptional ? '.map(|(k, _)| k)' : '.0') : ''; + const defaultExpr = accountDefaults[seedValue.name]; + + if (pdaDefaultedNames.has(seedValue.name)) { + accountDeps.push(seedValue.name); + } + + let valueExpr: string; + if (pdaDefaultedNames.has(seedValue.name)) { + valueExpr = refName; + } else if (!isOptional) { + // Required account — direct field access. + valueExpr = `self.${refName}${eitherExtract}`; + } else if (defaultExpr) { + valueExpr = `self.${refName}${eitherExtract}.unwrap_or(${defaultExpr})`; + } else { + valueExpr = `self.${refName}${eitherExtract}.expect("${refName} is needed for ${snakeCase(account.name)} PDA")`; + } + + if (resolvedType.kind === 'publicKeyTypeNode') { + renderedSeeds.push({ kind: 'accountRef', rawName: refName, render: `${valueExpr}.as_ref()` }); + } else if (resolvedType.kind === 'bytesTypeNode') { + renderedSeeds.push({ kind: 'accountRef', rawName: refName, render: `&${valueExpr}` }); + } else { + renderedSeeds.push({ + kind: 'accountRef', + rawName: refName, + render: `${valueExpr}.to_string().as_ref()`, + }); + } + } else if (isNode(seedValue, 'argumentValueNode')) { + const argFieldName = accountsAndArgsConflicts.includes(seedValue.name) + ? `${seedValue.name}_arg` + : seedValue.name; + const fieldName = snakeCase(argFieldName); + const isRequiredArg = requiredArgNames.includes(fieldName); + + const arg = instructionArguments.find(a => a.name === seedValue.name); + let argDefault: { isOmitted: boolean; value: string } | null = null; + if (arg?.defaultValue && isNode(arg.defaultValue, VALUE_NODES)) { + const { render: value } = renderValueNode(arg.defaultValue, getImportFrom); + argDefault = { isOmitted: arg.defaultValueStrategy === 'omitted', value }; + } + + if (argDefault && argDefault.isOmitted) { + if (resolvedType.kind === 'publicKeyTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `${argDefault.value}.as_ref()` }); + } else if (resolvedType.kind === 'bytesTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `&${argDefault.value}` }); + } else { + renderedSeeds.push({ + kind: 'argumentRef', + render: `${argDefault.value}.to_string().as_ref()`, + }); + } + } else if (isRequiredArg) { + // Required arg — direct field access, no Option unwrap. + const valueExpr = `self.${fieldName}.clone()`; + if (resolvedType.kind === 'publicKeyTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `${valueExpr}.as_ref()` }); + } else if (resolvedType.kind === 'bytesTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `&${valueExpr}` }); + } else { + renderedSeeds.push({ + kind: 'argumentRef', + render: `${valueExpr}.to_string().as_ref()`, + }); + } + } else { + const valueExpr = `self.${fieldName}.clone().expect("${fieldName} is needed for ${snakeCase(account.name)} PDA")`; + if (resolvedType.kind === 'publicKeyTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `${valueExpr}.as_ref()` }); + } else if (resolvedType.kind === 'bytesTypeNode') { + renderedSeeds.push({ kind: 'argumentRef', render: `&${valueExpr}` }); + } else { + renderedSeeds.push({ + kind: 'argumentRef', + render: `${valueExpr}.to_string().as_ref()`, + }); + } + } + } else { + const valueManifest = renderValueNode(seedValue, getImportFrom, true); + imports.mergeWith(valueManifest.imports); + if (resolvedType.kind === 'publicKeyTypeNode') { + renderedSeeds.push({ kind: 'value', render: `${valueManifest.render}.as_ref()` }); + } else { + renderedSeeds.push({ kind: 'value', render: `${valueManifest.render}.as_bytes()` }); + } + } + } + } + + if (!seedsComplete) continue; + + const pdaHasVariableSeeds = pdaNode ? pdaNode.seeds.some(s => isNode(s, 'variablePdaSeedNode')) : true; + + resolvedPdas[account.name] = { + accountDeps, + hasVariableSeeds: pdaHasVariableSeeds, + isLinked, + linkedPdaName, + programAddressExpr, + renderedSeeds, + }; + } + + // DFS topological sort with cycle detection and propagation. + const accountDeps = new Map>(); + for (const account of accounts) { + const name = account.name; + accountDeps.set(name, new Set()); + const pdaInfo = resolvedPdas[name]; + if (pdaInfo) { + for (const dep of pdaInfo.accountDeps) { + accountDeps.get(name)!.add(dep); + } + } + } + + const sortedNames: string[] = []; + const visited = new Set(); + const visiting = new Set(); + + const topoVisit = (name: string): boolean => { + if (visited.has(name)) return resolvedPdas[name] !== undefined || !pdaDefaultedNames.has(name); + if (visiting.has(name)) { + logWarn( + `[Rust] Circular PDA dependency detected for account [${name}] ` + + `in instruction [${instructionName}]. Falling back to required account.`, + ); + delete resolvedPdas[name]; + return false; + } + visiting.add(name); + for (const dep of accountDeps.get(name) ?? []) { + if (accountDeps.has(dep) && !topoVisit(dep)) { + // Dependency lost its PDA resolution — remove ours too. + delete resolvedPdas[name]; + } + } + visiting.delete(name); + visited.add(name); + sortedNames.push(name); + return resolvedPdas[name] !== undefined || !pdaDefaultedNames.has(name); + }; + + for (const account of accounts) { + topoVisit(account.name); + } + + return sortedNames.map(name => { + const account = accounts.find(a => a.name === name)!; + return { ...account, pdaDefault: resolvedPdas[name] ?? null }; + }); +} diff --git a/src/getTypeManifestVisitor.ts b/src/getTypeManifestVisitor.ts index 5bddf8e..6639448 100644 --- a/src/getTypeManifestVisitor.ts +++ b/src/getTypeManifestVisitor.ts @@ -231,6 +231,12 @@ export function getTypeManifestVisitor(options: { parentNode, traitOptions, ); + } else if (parentNode && ['(u64)', '(i64)', '(u128)', '(i128)'].includes(childManifest.type)) { + derive = getSerdeFieldAttribute( + 'serde_with::As::', + parentNode, + traitOptions, + ); } return { @@ -419,6 +425,12 @@ export function getTypeManifestVisitor(options: { parentNode, traitOptions, ); + } else if (['u64', 'i64', 'u128', 'i128'].includes(fieldManifest.type)) { + derive = getSerdeFieldAttribute( + 'serde_with::As::', + parentNode, + traitOptions, + ); } else if ( isNode(resolvedNestedType, 'arrayTypeNode') && isNode(resolvedNestedType.count, 'fixedCountNode') && diff --git a/src/utils/computePda.ts b/src/utils/computePda.ts new file mode 100644 index 0000000..345dfdb --- /dev/null +++ b/src/utils/computePda.ts @@ -0,0 +1,159 @@ +import { createHash } from 'node:crypto'; + +import { type ConstantPdaSeedNode, isNode, type PdaSeedNode, resolveNestedTypeNode } from '@codama/nodes'; +import { ed25519 } from '@noble/curves/ed25519.js'; +import { getBase58Decoder, getBase58Encoder } from '@solana/codecs-strings'; + +import { getBytesFromBytesValueNode } from './codecs'; + +function isOnCurve(bytes: Uint8Array): boolean { + return ed25519.utils.isValidPublicKey(bytes); +} + +/** + * Mirrors Solana's `Pubkey::find_program_address`. + * Returns the base58 address and bump, or `null` if no valid bump exists. + */ +export function findProgramAddress( + seeds: Uint8Array[], + programId: Uint8Array, +): { address: string; bump: number } | null { + for (let bump = 255; bump >= 0; bump--) { + const hash = createHash('sha256'); + for (const seed of seeds) { + hash.update(seed); + } + hash.update(Uint8Array.from([bump])); + hash.update(programId); + hash.update(Buffer.from('ProgramDerivedAddress')); + const candidate = hash.digest(); + + if (!isOnCurve(candidate)) { + return { + address: getBase58Decoder().decode(candidate), + bump, + }; + } + } + return null; +} + +function serializeNumber(value: number, format: string, endian: 'be' | 'le'): Uint8Array | null { + const isLE = endian === 'le'; + switch (format) { + case 'u8': + return Uint8Array.from([value & 0xff]); + case 'i8': { + const buf = new ArrayBuffer(1); + new DataView(buf).setInt8(0, value); + return new Uint8Array(buf); + } + case 'u16': { + const buf = new ArrayBuffer(2); + new DataView(buf).setUint16(0, value, isLE); + return new Uint8Array(buf); + } + case 'i16': { + const buf = new ArrayBuffer(2); + new DataView(buf).setInt16(0, value, isLE); + return new Uint8Array(buf); + } + case 'u32': { + const buf = new ArrayBuffer(4); + new DataView(buf).setUint32(0, value, isLE); + return new Uint8Array(buf); + } + case 'i32': { + const buf = new ArrayBuffer(4); + new DataView(buf).setInt32(0, value, isLE); + return new Uint8Array(buf); + } + case 'f32': { + const buf = new ArrayBuffer(4); + new DataView(buf).setFloat32(0, value, isLE); + return new Uint8Array(buf); + } + case 'f64': { + const buf = new ArrayBuffer(8); + new DataView(buf).setFloat64(0, value, isLE); + return new Uint8Array(buf); + } + case 'u64': + case 'i64': { + const buf = new ArrayBuffer(8); + const view = new DataView(buf); + if (format === 'u64') view.setBigUint64(0, BigInt(value), isLE); + else view.setBigInt64(0, BigInt(value), isLE); + return new Uint8Array(buf); + } + case 'u128': + case 'i128': { + const bytes = new Uint8Array(16); + const view = new DataView(bytes.buffer); + const big = BigInt(value); + const mask = (1n << 64n) - 1n; + const lo = big & mask; + const hi = (big >> 64n) & mask; + if (isLE) { + view.setBigUint64(0, lo, true); + view.setBigUint64(8, hi, true); + } else { + view.setBigUint64(0, hi, false); + view.setBigUint64(8, lo, false); + } + return bytes; + } + default: + return null; + } +} + +function extractConstantSeedBytes(seed: ConstantPdaSeedNode, programAddress: string): Uint8Array | null { + const { value } = seed; + + if (isNode(value, 'programIdValueNode')) { + return getBase58Encoder().encode(programAddress) as Uint8Array; + } + if (isNode(value, 'stringValueNode')) { + return new TextEncoder().encode(value.string); + } + if (isNode(value, 'bytesValueNode')) { + return getBytesFromBytesValueNode(value); + } + if (isNode(value, 'numberValueNode')) { + const resolvedType = resolveNestedTypeNode(seed.type); + if (isNode(resolvedType, 'numberTypeNode')) { + return serializeNumber(value.number, resolvedType.format, resolvedType.endian); + } + return null; + } + if (isNode(value, 'publicKeyValueNode')) { + return getBase58Encoder().encode(value.publicKey) as Uint8Array; + } + + return null; +} + +/** + * Computes a PDA address at codegen time for PDAs with only constant seeds. + * Returns the base58 address string, or `null` if computation is not possible. + */ +export function computePdaAddress(seeds: readonly PdaSeedNode[], programAddress: string): string | null { + try { + const seedBytes: Uint8Array[] = []; + for (const seed of seeds) { + if (!isNode(seed, 'constantPdaSeedNode')) { + return null; + } + const bytes = extractConstantSeedBytes(seed, programAddress); + if (!bytes) return null; + seedBytes.push(bytes); + } + + const programIdBytes = getBase58Encoder().encode(programAddress) as Uint8Array; + const result = findProgramAddress(seedBytes, programIdBytes); + return result?.address ?? null; + } catch { + return null; + } +} diff --git a/src/utils/discriminatorConstant.ts b/src/utils/discriminatorConstant.ts index 8e88e34..0b42178 100644 --- a/src/utils/discriminatorConstant.ts +++ b/src/utils/discriminatorConstant.ts @@ -25,6 +25,34 @@ function mergeFragments(fragments: Fragment[], merge: (parts: string[]) => strin return { imports, render }; } +export function getByteArrayDiscriminatorConstantName(scope: { + discriminatorNodes: DiscriminatorNode[]; + fields: InstructionArgumentNode[] | StructFieldTypeNode[]; + prefix: string; +}): string | null { + const { discriminatorNodes, fields, prefix } = scope; + + for (const disc of discriminatorNodes) { + if (isNode(disc, 'constantDiscriminatorNode')) { + return snakeCase(camelCase(`${prefix}_discriminator`)).toUpperCase(); + } + if (isNode(disc, 'fieldDiscriminatorNode')) { + const field = fields.find(f => f.name === disc.name); + if ( + field && + field.defaultValue && + isNode(field.defaultValue, VALUE_NODES) && + isNode(field.type, 'fixedSizeTypeNode') && + isNode(field.type.type, 'bytesTypeNode') + ) { + return snakeCase(camelCase(`${prefix}_${disc.name}`)).toUpperCase(); + } + } + } + + return null; +} + export function getDiscriminatorConstants(scope: { discriminatorNodes: DiscriminatorNode[]; fields: InstructionArgumentNode[] | StructFieldTypeNode[]; diff --git a/src/utils/index.ts b/src/utils/index.ts index 6e73eb3..48569a6 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,5 +1,6 @@ export * from './cargoToml'; export * from './codecs'; +export * from './computePda'; export * from './discriminatorConstant'; export * from './fragment'; export * from './linkOverrides'; diff --git a/src/utils/render.ts b/src/utils/render.ts index 0dcff19..df8a24a 100644 --- a/src/utils/render.ts +++ b/src/utils/render.ts @@ -6,7 +6,7 @@ import nunjucks, { ConfigureOptions as NunJucksOptions } from 'nunjucks'; export function rustDocblock(docs: string[]): string { if (docs.length <= 0) return ''; - const lines = docs.map(doc => `/// ${doc}`); + const lines = docs.flatMap(doc => doc.split('\n')).map(doc => `/// ${doc}`); return `${lines.join('\n')}\n`; } diff --git a/src/utils/traitOptions.ts b/src/utils/traitOptions.ts index da98dd9..fa39e6c 100644 --- a/src/utils/traitOptions.ts +++ b/src/utils/traitOptions.ts @@ -95,6 +95,17 @@ export function getTraitsFromNode( }), ]; + // Add serde rename_all = "camelCase" container attribute for structs only. + // Enums keep PascalCase variant names to match the JS SDK. + const { featureName, hasSerde } = findSerdeFeature(allTraits, options.featureFlags); + if (hasSerde && nodeType === 'struct') { + if (featureName) { + traitLines.push(`#[cfg_attr(feature = "${featureName}", serde(rename_all = "camelCase"))]\n`); + } else { + traitLines.push(`#[serde(rename_all = "camelCase")]\n`); + } + } + return { imports, render: traitLines.join('') }; } @@ -144,7 +155,10 @@ function partitionTraitsInFeatures( const unfeaturedTraits: string[] = []; const featuredTraits: Record = {}; + const seenTraits = new Set(); + for (const trait of traits) { + seenTraits.add(trait); const feature: string | undefined = reverseFeatureFlags[trait]; if (feature === undefined) { unfeaturedTraits.push(trait); @@ -154,6 +168,16 @@ function partitionTraitsInFeatures( } } + // Inject feature-flagged traits that weren't already in the defaults/overrides. + for (const [feature, flaggedTraits] of Object.entries(featureFlags)) { + for (const trait of flaggedTraits) { + if (!seenTraits.has(trait)) { + if (!featuredTraits[feature]) featuredTraits[feature] = []; + featuredTraits[feature].push(trait); + } + } + } + return [unfeaturedTraits, featuredTraits]; } @@ -166,6 +190,40 @@ function extractFullyQualifiedNames(traits: string[], imports: ImportMap): strin }); } +/** + * Determines whether serde traits are present and which feature flag (if any) they are behind. + */ +function findSerdeFeature( + allTraits: string[], + featureFlags: Record, +): { featureName: string | undefined; hasSerde: boolean } { + const allTraitsAndFeatured = [...allTraits, ...Object.values(featureFlags).flat()]; + const hasSerde = allTraitsAndFeatured.some( + t => t === 'serde::Serialize' || t === 'Serialize' || t === 'serde::Deserialize' || t === 'Deserialize', + ); + + if (!hasSerde) { + return { featureName: undefined, hasSerde: false }; + } + + const partitioned = partitionTraitsInFeatures(allTraits, featureFlags); + const featured = partitioned[1]; + + let featureName: string | undefined; + for (const [feature, traits] of Object.entries(featured)) { + if ( + traits.some( + t => t === 'serde::Serialize' || t === 'serde::Deserialize' || t === 'Serialize' || t === 'Deserialize', + ) + ) { + featureName = feature; + break; + } + } + + return { featureName, hasSerde: true }; +} + /** * Helper function to get the serde field attribute format based on trait configuration. * Returns the appropriate attribute string for serde field customization, or empty string if no serde traits. @@ -191,33 +249,13 @@ export function getSerdeFieldAttribute( const nodeOverrides: string[] | undefined = sanitizedOverrides[node.name]; const allTraits = nodeOverrides === undefined ? getDefaultTraits(nodeType, options) : nodeOverrides; - // Check if serde traits are present. - const hasSerdeSerialize = allTraits.some(t => t === 'serde::Serialize' || t === 'Serialize'); - const hasSerdeDeserialize = allTraits.some(t => t === 'serde::Deserialize' || t === 'Deserialize'); - - if (!hasSerdeSerialize && !hasSerdeDeserialize) { + const { featureName, hasSerde } = findSerdeFeature(allTraits, options.featureFlags); + if (!hasSerde) { return ''; } - // Check if serde is feature-flagged. - const partitionedTraits = partitionTraitsInFeatures(allTraits, options.featureFlags); - const featuredTraits = partitionedTraits[1]; - - // Find which feature flag contains serde traits. - let serdeFeatureName: string | undefined; - for (const [feature, traits] of Object.entries(featuredTraits)) { - if ( - traits.some( - t => t === 'serde::Serialize' || t === 'serde::Deserialize' || t === 'Serialize' || t === 'Deserialize', - ) - ) { - serdeFeatureName = feature; - break; - } - } - - if (serdeFeatureName) { - return `#[cfg_attr(feature = "${serdeFeatureName}", serde(with = "${serdeWith}"))]\n`; + if (featureName) { + return `#[cfg_attr(feature = "${featureName}", serde(with = "${serdeWith}"))]\n`; } else { return `#[serde(with = "${serdeWith}")]\n`; } diff --git a/test/accountsPage.test.ts b/test/accountsPage.test.ts index 3dc7232..1c40caa 100644 --- a/test/accountsPage.test.ts +++ b/test/accountsPage.test.ts @@ -1,9 +1,12 @@ import { accountNode, bytesTypeNode, + bytesValueNode, camelCase, + constantDiscriminatorNode, constantPdaSeedNode, constantPdaSeedNodeFromString, + constantValueNode, fixedSizeTypeNode, numberTypeNode, numberValueNode, @@ -11,6 +14,8 @@ import { pdaNode, programNode, publicKeyTypeNode, + structFieldTypeNode, + structTypeNode, variablePdaSeedNode, } from '@codama/nodes'; import { getFromRenderMap } from '@codama/renderers-core'; @@ -103,7 +108,7 @@ test('it renders constant PDA seeds as prefix consts', () => { '/// 0. `TestAccount::PREFIX.0`', '/// 1. my_account (`Address`)', '/// 2. `TestAccount::PREFIX.1`', - /pub const PREFIX: \(\s*&'static \[u8\],\s*&'static \[u8\],\s*\) = \(\s*"myPrefix"\.as_bytes\(\),\s*42\.as_bytes\(\),\s*\)/, + /pub const PREFIX: \(\s*&'static \[u8\],\s*&'static \[u8\],\s*\) = \(\s*b"myPrefix",\s*&42u64\.to_le_bytes\(\),\s*\)/, ]); }); @@ -136,6 +141,7 @@ test('it renders anchor traits impl', () => { 'impl anchor_lang::AccountDeserialize for TestAccount', 'impl anchor_lang::AccountSerialize for TestAccount {}', 'impl anchor_lang::Owner for TestAccount', + 'const DISCRIMINATOR: &[u8] = &[0; 8]', ]); }); @@ -171,6 +177,206 @@ test('it renders fetch functions', () => { ]); }); +test('it validates byte-array discriminator in from_bytes and TryFrom', () => { + // Given an account with a byte-array discriminator field. + const node = programNode({ + accounts: [ + accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: bytesValueNode('base16', 'b9959c4ef56cac44'), + defaultValueStrategy: 'omitted', + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + }), + structFieldTypeNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + ]), + discriminators: [ + { + kind: 'fieldDiscriminatorNode', + name: camelCase('discriminator'), + offset: 0, + }, + ], + name: 'testAccount', + }), + ], + name: 'myProgram', + publicKey: '1111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + // Then from_bytes validates the discriminator before deserializing. + codeContains(code, ['TEST_ACCOUNT_DISCRIMINATOR', 'invalid account discriminator', 'Self::from_bytes(data)']); + + // And the Discriminator trait uses the real constant. + codeContains(code, ['const DISCRIMINATOR: &[u8] = &TEST_ACCOUNT_DISCRIMINATOR;']); +}); + +test('it validates constant discriminator in from_bytes and TryFrom', () => { + // Given an account with a constantDiscriminatorNode (no discriminator struct field). + const node = programNode({ + accounts: [ + accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + name: 'amount', + type: numberTypeNode('u64'), + }), + ]), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ), + ], + name: 'testAccount', + }), + ], + name: 'myProgram', + publicKey: '1111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + // from_bytes validates the discriminator. + codeContains(code, ['TEST_ACCOUNT_DISCRIMINATOR', 'invalid account discriminator']); + + // Anchor Discriminator trait uses the real constant. + codeContains(code, ['const DISCRIMINATOR: &[u8] = &TEST_ACCOUNT_DISCRIMINATOR;']); +}); + +test('it validates account owner in TryFrom and fetch', () => { + // Given an account with a discriminator. + const node = programNode({ + accounts: [ + accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: bytesValueNode('base16', 'b9959c4ef56cac44'), + defaultValueStrategy: 'omitted', + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + }), + ]), + discriminators: [ + { + kind: 'fieldDiscriminatorNode', + name: camelCase('discriminator'), + offset: 0, + }, + ], + name: 'testAccount', + }), + ], + name: 'myProgram', + publicKey: '1111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + // TryFrom checks account owner. + codeContains(code, ['invalid account owner', 'account_info.owner', 'MY_PROGRAM_ID']); + + // Fetch functions check account owner. + codeContains(code, ['Invalid owner for account']); +}); + +test('it validates account owner even without a discriminator', () => { + const node = programNode({ + accounts: [accountNode({ name: 'testAccount' })], + name: 'myProgram', + publicKey: '1111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + codeContains(code, ['invalid account owner', 'MY_PROGRAM_ID']); + codeDoesNotContains(code, ['invalid account discriminator']); +}); + +test('it validates discriminator in anchor try_deserialize', () => { + // Given an account with a byte-array discriminator. + const node = programNode({ + accounts: [ + accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: bytesValueNode('base16', 'b9959c4ef56cac44'), + defaultValueStrategy: 'omitted', + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + }), + ]), + discriminators: [ + { + kind: 'fieldDiscriminatorNode', + name: camelCase('discriminator'), + offset: 0, + }, + ], + name: 'testAccount', + }), + ], + name: 'myProgram', + publicKey: '1111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + // try_deserialize checks the discriminator before delegating to unchecked. + codeContains(code, [ + 'fn try_deserialize(buf: &mut &[u8])', + 'AccountDiscriminatorMismatch', + 'TEST_ACCOUNT_DISCRIMINATOR', + ]); +}); + +test('it skips discriminator validation when field has no default value', () => { + // Given an account with a byte-array discriminator field but no defaultValue. + const node = programNode({ + accounts: [ + accountNode({ + data: structTypeNode([ + structFieldTypeNode({ + name: 'discriminator', + type: fixedSizeTypeNode(bytesTypeNode(), 8), + }), + ]), + discriminators: [ + { + kind: 'fieldDiscriminatorNode', + name: camelCase('discriminator'), + offset: 0, + }, + ], + name: 'testAccount', + }), + ], + name: 'myProgram', + publicKey: '1111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'accounts/test_account.rs').content; + + // Then from_bytes does not validate a discriminator. + codeDoesNotContains(code, ['invalid account discriminator', 'TEST_ACCOUNT_DISCRIMINATOR']); +}); + test('it renders account without anchor traits', () => { // Given the following account. const node = programNode({ diff --git a/test/instructionsPage.test.ts b/test/instructionsPage.test.ts index 8d1ad3a..5d1e93a 100644 --- a/test/instructionsPage.test.ts +++ b/test/instructionsPage.test.ts @@ -1,10 +1,32 @@ -import { instructionArgumentNode, instructionNode, programNode, stringTypeNode } from '@codama/nodes'; +import { + accountValueNode, + argumentValueNode, + bytesTypeNode, + bytesValueNode, + constantPdaSeedNode, + constantPdaSeedNodeFromString, + instructionAccountNode, + instructionArgumentNode, + instructionNode, + numberTypeNode, + numberValueNode, + pdaLinkNode, + pdaNode, + pdaSeedValueNode, + pdaValueNode, + programIdValueNode, + programNode, + publicKeyTypeNode, + publicKeyValueNode, + stringTypeNode, + variablePdaSeedNode, +} from '@codama/nodes'; import { getFromRenderMap } from '@codama/renderers-core'; import { visit } from '@codama/visitors-core'; -import { test } from 'vitest'; +import { expect, test } from 'vitest'; import { getRenderMapVisitor } from '../src'; -import { codeContains } from './_setup'; +import { codeContains, codeDoesNotContains } from './_setup'; test('it renders a public instruction data struct', () => { // Given the following program with 1 instruction. @@ -52,6 +74,711 @@ test('it renders an instruction with a remainder str', () => { ]); }); +test('it auto-derives PDA accounts from pdaLinkNode defaults', () => { + // Given an instruction with a PDA-defaulted account. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'realm' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('realm', accountValueNode('realm')), + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('owner', accountValueNode('owner')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then we expect the PDA to be auto-derived. + codeContains(content, [ + `unwrap_or_else(|| {`, + `crate::pdas::find_record_pda(`, + `&self.realm,`, + `&self.mint,`, + `&self.owner,`, + `.0`, + `default to PDA derived from 'record'`, + ]); +}); + +test('it passes argument seeds by value for non-Pubkey types', () => { + // Given an instruction with a PDA that has a string argument seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('label', argumentValueNode('label')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'label', type: stringTypeNode('utf8') })], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('label', stringTypeNode('utf8')), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then we expect by-ref for the account seed (required, direct access) + // and by-value for the argument seed (required, direct clone). + codeContains(content, [`crate::pdas::find_record_pda(`, `&self.owner,`, `self.label.clone(),`]); +}); + +test('it resolves upstream account defaults as PDA seeds', () => { + // Given an instruction where a PDA seed references an account with a publicKeyValueNode default. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'tokenProgram', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('ata'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('tokenProgram', accountValueNode('tokenProgram')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'ata', + }), + ], + name: 'createAta', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_ata.rs').content; + + // Then we expect the tokenProgram seed to use unwrap_or with its default. + codeContains(content, [ + `crate::pdas::find_ata_pda(`, + `&self.owner,`, + `&self.token_program.unwrap_or(solana_address::address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"))`, + `&self.mint,`, + ]); +}); + +test('it resolves programIdValueNode defaults as PDA seed defaults', () => { + // Given a PDA seed that references an account with a programIdValueNode default. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: programIdValueNode(), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'programAddress', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('programAddress', accountValueNode('programAddress')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then the programAddress seed uses unwrap_or with the program ID constant. + codeContains(content, [`&self.program_address.unwrap_or(crate::TEST_PROGRAM_ID)`]); +}); + +test('it passes Pubkey argument seeds by reference', () => { + // Given an instruction with a PDA that has a Pubkey argument seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('delegate', argumentValueNode('delegate')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'delegate', type: publicKeyTypeNode() })], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + constantPdaSeedNode(bytesTypeNode(), bytesValueNode('utf8', 'rec')), + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('delegate', publicKeyTypeNode()), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // owner is required (direct), delegate is a required arg (direct clone). + codeContains(content, [`&self.owner,`, `&self.delegate.clone(),`]); +}); + +test('it handles argument/account name conflicts in PDA seeds', () => { + // Given a non-Pubkey argument that conflicts with an account name. + const stringConflict = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('label', argumentValueNode('owner')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'owner', type: stringTypeNode('utf8') })], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('label', stringTypeNode('utf8')), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const content1 = getFromRenderMap( + visit(stringConflict, getRenderMapVisitor()), + 'instructions/create_record.rs', + ).content; + // owner is required (direct), owner_arg is a required arg (direct clone). + codeContains(content1, [`&self.owner,`, `self.owner_arg.clone(),`]); + + // And a Pubkey argument that conflicts — should also get _arg suffix with by-ref. + const pubkeyConflict = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'delegate' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('delegate')), + pdaSeedValueNode('delegate', argumentValueNode('delegate')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'delegate', type: publicKeyTypeNode() })], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('delegate', publicKeyTypeNode()), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const content2 = getFromRenderMap( + visit(pubkeyConflict, getRenderMapVisitor()), + 'instructions/create_record.rs', + ).content; + // delegate is required (direct), delegate_arg is a required arg (direct clone). + codeContains(content2, [`&self.delegate,`, `&self.delegate_arg.clone(),`]); +}); + +test('it handles argument defaults in PDA seeds', () => { + // Omitted arguments are inlined as their default value. + const omittedArg = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('kind', argumentValueNode('kind')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [ + instructionArgumentNode({ + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + name: 'kind', + type: numberTypeNode('u32'), + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('kind', numberTypeNode('u32')), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const content1 = getFromRenderMap( + visit(omittedArg, getRenderMapVisitor()), + 'instructions/create_record.rs', + ).content; + codeContains(content1, [`42`]); + expect(content1).not.toContain('self.kind'); + + // Non-omitted arguments still use expect (no silent defaulting for PDA seeds). + const nonOmittedArg = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('version', argumentValueNode('version')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [ + instructionArgumentNode({ + defaultValue: numberValueNode(1), + name: 'version', + type: numberTypeNode('u32'), + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('version', numberTypeNode('u32')), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const content2 = getFromRenderMap( + visit(nonOmittedArg, getRenderMapVisitor()), + 'instructions/create_record.rs', + ).content; + codeContains(content2, [`self.version.clone().expect("version is needed for record PDA")`]); +}); + +test('it extracts Pubkey from either-signer tuple for PDA seeds', () => { + // Given a PDA seed that references an isSigner: 'either' account. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + isOptional: false, + isSigner: 'either', + isWritable: false, + name: 'authority', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('authority', accountValueNode('authority')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // authority is required either-signer — direct .0 extraction, no expect. + codeContains(content, [`&self.authority.0,`]); +}); + +test('it extracts Pubkey from either-signer tuple for inline pdaNode seeds', () => { + // Given an inline pdaNode seed that references an isSigner: 'either' account. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + isOptional: false, + isSigner: 'either', + isWritable: false, + name: 'authority', + }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'record', + seeds: [variablePdaSeedNode('authority', publicKeyTypeNode())], + }), + [pdaSeedValueNode('authority', accountValueNode('authority'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then we expect the seed to extract the Pubkey from the (Pubkey, bool) tuple. + // authority is a required constructor arg, so the field is (Pubkey, bool) directly. + codeContains(content, [`self.authority.0.as_ref()`]); +}); + +test('it renders a builder that auto-derives inline pdaNode accounts', () => { + // Given an instruction with an inline pdaNode default (constant + variable seeds). + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'guard', + seeds: [ + constantPdaSeedNode(bytesTypeNode(), bytesValueNode('utf8', 'my_seed')), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [pdaSeedValueNode('mint', accountValueNode('mint'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'guard', + }), + ], + name: 'createGuard', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_guard.rs').content; + + // Then the builder should generate inline find_program_address. + codeContains(content, [ + `unwrap_or_else(|| {`, + `solana_address::Address::find_program_address(`, + // Constant seed rendered as byte array reference. + /&\[109, 121, 95, 115, 101, 101, 100\]/, + // Variable seed — mint is required, direct .as_ref(). + `self.mint.as_ref()`, + // Uses default program ID. + `&crate::TEST_PROGRAM_ID`, + `.0`, + `default to PDA derived from 'guard'`, + ]); +}); + +test('it renders inline pdaNode with argumentValueNode variable seed using type dispatch', () => { + // Given an instruction with an argument-valued variable seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'record', + seeds: [ + constantPdaSeedNode(bytesTypeNode(), bytesValueNode('utf8', 'rec')), + variablePdaSeedNode('mint', publicKeyTypeNode()), + variablePdaSeedNode('label', stringTypeNode('utf8')), + ], + }), + [ + pdaSeedValueNode('mint', accountValueNode('mint')), + pdaSeedValueNode('label', argumentValueNode('label')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'label', type: stringTypeNode('utf8') })], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then argument seeds use .to_string().as_ref() for string types (not bare .as_ref()). + codeContains(content, [`self.mint.as_ref()`, `self.label.clone().to_string().as_ref()`]); +}); + +test('it renders inline pdaNode with custom programId', () => { + // Given an instruction with an inline pdaNode that specifies a custom programId. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'ata', + programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + seeds: [variablePdaSeedNode('mint', publicKeyTypeNode())], + }), + [pdaSeedValueNode('mint', accountValueNode('mint'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'ata', + }), + ], + name: 'createAta', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_ata.rs').content; + + // Then the custom programId is used instead of the current program's ID. + codeContains(content, [`&solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")`]); +}); + +test('it resolves upstream account defaults when used as inline PDA seeds', () => { + // Given an instruction where a PDA seed references an account with its own default. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'mint' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'tokenProgram', + }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'ata', + programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('tokenProgram', publicKeyTypeNode()), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('tokenProgram', accountValueNode('tokenProgram')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'ata', + }), + ], + name: 'createAta', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_ata.rs').content; + + // Then tokenProgram seed uses unwrap_or with its default instead of expect. + codeContains(content, [ + `self.token_program.unwrap_or(solana_address::address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")).as_ref()`, + ]); + // And required accounts without defaults still use expect. + codeContains(content, [`self.owner.as_ref()`, `self.mint.as_ref()`]); +}); + +test('it renders inline pdaNode with programIdValueNode constant seed', () => { + // Given an instruction with a programIdValueNode as a constant seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'record', + seeds: [ + constantPdaSeedNode(bytesTypeNode(), programIdValueNode()), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [pdaSeedValueNode('mint', accountValueNode('mint'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Then the programId is used as a constant seed. + codeContains(content, [`crate::TEST_PROGRAM_ID.as_ref()`]); +}); + test('it renders a default impl for instruction data struct', () => { // Given the following program with 1 instruction. const node = programNode({ @@ -69,3 +796,837 @@ test('it renders a default impl for instruction data struct', () => { `fn default(`, ]); }); + +test('it resolves cascading PDA defaults via let bindings', () => { + // Given an instruction where vault (inline PDA) depends on pool (linked PDA). + // Without let bindings, vault would read self.pool (still None) and panic. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('pool'), [ + pdaSeedValueNode('mint', accountValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'pool', + }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'vault', + programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + seeds: [ + variablePdaSeedNode('authority', publicKeyTypeNode()), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [ + pdaSeedValueNode('authority', accountValueNode('pool')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'vault', + }), + ], + name: 'swap', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'pool', + seeds: [variablePdaSeedNode('mint', publicKeyTypeNode())], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/swap.rs').content; + + // Then pool is emitted as a let binding. + codeContains(content, [`let pool = self.pool.unwrap_or_else(|| {`, `find_pool_pda(`]); + // And vault is also a let binding that references the local `pool`, not self.pool. + codeContains(content, [`let vault = self.vault.unwrap_or_else(|| {`, `pool.as_ref()`]); + // And the struct literal uses shorthand field names. + codeContains(content, [/Swap \{\s*mint,/]); + // Verify vault does NOT read self.pool (which would panic). + expect(content).not.toContain('self.pool.expect'); +}); + +test('it topologically sorts PDA let bindings when dependency is declared after dependent', () => { + // Given an instruction where vault (inline PDA) references authority (linked PDA), + // but vault is declared BEFORE authority in the accounts list. + // This mirrors the real-world claim_airdrop pattern. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + // vault comes first but depends on authority + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'vault', + programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + seeds: [ + variablePdaSeedNode('authority', publicKeyTypeNode()), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [ + pdaSeedValueNode('authority', accountValueNode('authority')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'vault', + }), + // authority comes second but is vault's dependency + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('authority'), []), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'authority', + }), + ], + name: 'claimAirdrop', + }), + ], + name: 'testProgram', + pdas: [pdaNode({ name: 'authority', seeds: [] })], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/claim_airdrop.rs').content; + + // Then authority's let binding must appear BEFORE vault's let binding, + // even though vault is declared first in the accounts list. + const authorityPos = content.indexOf('let authority ='); + const vaultPos = content.indexOf('let vault ='); + expect(authorityPos).toBeGreaterThan(-1); + expect(vaultPos).toBeGreaterThan(-1); + expect(authorityPos).toBeLessThan(vaultPos); + + // And vault references the local `authority`, not self.authority. + codeContains(content, [`authority.as_ref()`]); + expect(content).not.toContain('self.authority.expect'); +}); + +test('it handles argument/account name conflicts in inline pdaNode seeds', () => { + // Given an inline PDA with an argument seed whose name conflicts with an account name. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('authority', publicKeyTypeNode()), + variablePdaSeedNode('label', stringTypeNode('utf8')), + ], + }), + [ + pdaSeedValueNode('authority', accountValueNode('owner')), + pdaSeedValueNode('label', argumentValueNode('owner')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'owner', type: stringTypeNode('utf8') })], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // The account seed should reference self.owner (the account field). + codeContains(content, [`self.owner.as_ref()`]); + // The argument seed should reference self.owner_arg (the _arg suffixed field). + codeContains(content, [`self.owner_arg.clone()`]); +}); + +test('it handles omitted-default argument seeds in inline pdaNode', () => { + // Given an inline PDA with an omitted-default argument seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('kind', numberTypeNode('u32')), + ], + }), + [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('kind', argumentValueNode('kind')), + ], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [ + instructionArgumentNode({ + defaultValue: numberValueNode(42), + defaultValueStrategy: 'omitted', + name: 'kind', + type: numberTypeNode('u32'), + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // The omitted arg should be inlined as its default value, not read from self.kind. + codeContains(content, [`42`]); + expect(content).not.toContain('self.kind'); +}); + +test('it falls back to .expect() for both accounts in a circular PDA dependency', () => { + // Given two accounts with circular PDA dependencies (A depends on B, B depends on A). + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'pdaA', + seeds: [variablePdaSeedNode('b', publicKeyTypeNode())], + }), + [pdaSeedValueNode('b', accountValueNode('accountB'))], + ), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'accountA', + }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'pdaB', + seeds: [variablePdaSeedNode('a', publicKeyTypeNode())], + }), + [pdaSeedValueNode('a', accountValueNode('accountA'))], + ), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'accountB', + }), + ], + name: 'circular', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/circular.rs').content; + + // Then BOTH accounts lose PDA resolution and become required constructor params. + // They resolve via let-bindings with direct field access. + codeContains(content, ['let account_a = self.account_a', 'let account_b = self.account_b']); + // No PDA derivation code should be emitted for either. + codeDoesNotContains(content, ['find_program_address', 'unwrap_or_else']); +}); + +test('it bails entire PDA resolution when a variable seed has no binding', () => { + // Given an inline PDA with a variable seed that has no matching binding. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'vault', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + // Only provide binding for 'mint', not 'owner' — incomplete seeds. + [pdaSeedValueNode('mint', accountValueNode('mint'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'vault', + }), + ], + name: 'deposit', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/deposit.rs').content; + + // PDA resolution fails — vault becomes a required constructor param. + // Resolved via let-binding with direct field access. + codeContains(content, ['let vault = self.vault']); + codeDoesNotContains(content, ['find_program_address', 'unwrap_or_else', '.expect(']); +}); + +test('it renders required args as constructor params', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [instructionAccountNode({ isSigner: false, isWritable: true, name: 'myAccount' })], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], + name: 'myInstruction', + }), + ], + name: 'myProgram', + publicKey: 'Dummy11111111111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'instructions/my_instruction.rs').content; + + codeContains(code, [ + /pub struct MyInstructionBuilder \{[^}]*amount: u64,/, + /pub fn new\([^)]*amount: u64/, + `#[derive(Clone, Debug)]`, + ]); + + codeDoesNotContains(code, [ + `pub fn amount(&mut self`, + `expect("amount is not set")`, + `#[derive(Clone, Debug, Default)]`, + ]); +}); + +test('it renders required args as constructor params even without required accounts', () => { + const node = programNode({ + instructions: [ + instructionNode({ + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], + name: 'myInstruction', + }), + ], + name: 'myProgram', + publicKey: 'Dummy11111111111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'instructions/my_instruction.rs').content; + + codeContains(code, [`#[derive(Clone, Debug)]`, /pub fn new\([^)]*amount: u64/]); + + codeDoesNotContains(code, [`#[derive(Clone, Debug, Default)]`, `Self::default()`]); +}); + +test('it renders required accounts as constructor params with PDA accounts staying optional', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'realm' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('realm', accountValueNode('realm')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Required accounts in new(). + codeContains(content, [ + `#[derive(Clone, Debug)]`, + /pub fn new\(\s*realm: solana_address::Address,\s*mint: solana_address::Address,/, + ]); + + // PDA account is NOT in new(), stays Option. + codeContains(content, [/record: Option/, `pub fn record(&mut self`]); + + // Required accounts are bare types, not Option. + codeContains(content, [ + /realm: solana_address::Address,\s*mint: solana_address::Address,\s*record: Option/, + ]); + + // No setters for required accounts. + codeDoesNotContains(content, [`pub fn realm(&mut self`, `pub fn mint(&mut self`]); +}); + +test('it renders required account as pdaLinkNode seed without expect', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Required account used as PDA seed — direct access, no expect. + codeContains(content, [`&self.owner,`]); + codeDoesNotContains(content, [`self.owner.expect`]); +}); + +test('it renders required either-signer account as pdaLinkNode seed with .0 extraction', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + isOptional: false, + isSigner: 'either', + isWritable: false, + name: 'authority', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('authority', accountValueNode('authority')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Required either-signer: bare tuple type, new() param, .0 in seed. + codeContains(content, [ + /authority: \(solana_address::Address, bool\),/, + /pub fn new\([^)]*authority: \(solana_address::Address, bool\)/, + `&self.authority.0,`, + ]); + codeDoesNotContains(content, [ + `Option<(solana_address::Address, bool)>`, + `.map(|(k, _)| k).expect`, + `pub fn authority(&mut self`, + ]); +}); + +test('it renders required account as inline pdaNode seed without expect', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'guard', + seeds: [ + constantPdaSeedNode(bytesTypeNode(), bytesValueNode('utf8', 'my_seed')), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + [pdaSeedValueNode('mint', accountValueNode('mint'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'guard', + }), + ], + name: 'createGuard', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_guard.rs').content; + + // Required account as inline PDA seed — direct .as_ref(), no expect. + codeContains(content, [`self.mint.as_ref()`]); + codeDoesNotContains(content, [`self.mint.expect`]); +}); + +test('it renders required arg as pdaLinkNode seed without expect', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('label', argumentValueNode('label')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + ], + arguments: [instructionArgumentNode({ name: 'label', type: stringTypeNode('utf8') })], + name: 'createRecord', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'record', + seeds: [ + variablePdaSeedNode('owner', publicKeyTypeNode()), + variablePdaSeedNode('label', stringTypeNode('utf8')), + ], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + // Required arg in new(). + codeContains(content, [/pub fn new\([^)]*label: TrailingStr/]); + // Required arg as PDA seed — no expect. + codeContains(content, [`self.label.clone(),`]); + codeDoesNotContains(content, [`self.label.clone().expect`]); +}); + +test('it renders mixed required accounts, PDA defaults, and publicKey defaults', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'tokenProgram', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('ata'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('tokenProgram', accountValueNode('tokenProgram')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'ata', + }), + ], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], + name: 'createAta', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_ata.rs').content; + + // Required accounts and args in new(). + codeContains(content, [ + /pub fn new\(\s*owner: solana_address::Address,\s*mint: solana_address::Address,\s*amount: u64,/, + `#[derive(Clone, Debug)]`, + ]); + + // publicKey default stays optional with setter. + codeContains(content, [ + `pub fn token_program(&mut self`, + `unwrap_or(solana_address::address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"))`, + ]); + + // PDA account stays optional with setter. + codeContains(content, [`pub fn ata(&mut self`, /ata: Option/]); + + // Required accounts: no setters, no expect. + codeDoesNotContains(content, [ + `pub fn owner(&mut self`, + `pub fn mint(&mut self`, + `pub fn amount(&mut self`, + `expect("owner is not set")`, + `expect("mint is not set")`, + `expect("amount is not set")`, + ]); + + // PDA seed for required accounts uses direct access. + codeContains(content, [`&self.owner,`]); + // PDA seed for publicKey default uses unwrap_or. + codeContains(content, [ + `&self.token_program.unwrap_or(solana_address::address!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"))`, + ]); + // PDA seed for required account 'mint' uses direct access. + codeContains(content, [`&self.mint,`]); +}); + +test('it renders programIdValueNode default account with unwrap_or program ID', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: programIdValueNode(), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'selfProgram', + }), + ], + name: 'myInstruction', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/my_instruction.rs').content; + + // programIdValueNode account is builder-optional (Option in struct). + codeContains(content, [`self_program: Option`, `pub fn self_program(&mut self`]); + // In struct literal, unwraps with program ID default. + codeContains(content, [`self.self_program.unwrap_or(crate::TEST_PROGRAM_ID)`]); + // Required account 'owner' is in new(). + codeContains(content, [/pub fn new\([^)]*owner: solana_address::Address/]); + // programIdValueNode account is NOT in new(). + codeDoesNotContains(content, [/pub fn new\([^)]*self_program/]); +}); + +test('it renders CPI builder with required accounts, args, and defaults', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: publicKeyValueNode('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'tokenProgram', + }), + instructionAccountNode({ + defaultValue: programIdValueNode(), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'selfProgram', + }), + ], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], + name: 'myInstruction', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/my_instruction.rs').content; + + const cpiSection = content.substring(content.indexOf('Instruction builder for `MyInstruction` via CPI')); + + codeContains(cpiSection, [ + /MyInstructionCpiBuilder<'a, 'b>/, + /pub fn new\(\s*__program: &'b solana_account_info::AccountInfo<'a>,\s*owner: &'b solana_account_info::AccountInfo<'a>,\s*token_program: &'b solana_account_info::AccountInfo<'a>,\s*amount: u64,/, + ]); + codeContains(cpiSection, [ + /owner: &'b solana_account_info::AccountInfo<'a>,\s*token_program: &'b solana_account_info::AccountInfo<'a>,\s*self_program: Option<&'b solana_account_info::AccountInfo<'a>>,/, + ]); + codeContains(cpiSection, [/amount: u64,\s*\/\/\//]); + codeContains(cpiSection, [`self.instruction.self_program.unwrap_or(self.instruction.__program)`]); + codeContains(cpiSection, [/token_program: self\.instruction\.token_program,/]); + codeContains(cpiSection, [/\[signer\].*owner/, /\[optional\].*self_program/]); + codeDoesNotContains(cpiSection, [/\[optional\].*token_program/]); + codeDoesNotContains(cpiSection, [`pub fn token_program(`]); +}); + +test('it renders CPI builder with PDA-defaulted accounts as required constructor params', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'owner' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('record'), [ + pdaSeedValueNode('owner', accountValueNode('owner')), + pdaSeedValueNode('mint', accountValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'record', + }), + instructionAccountNode({ + defaultValue: programIdValueNode(), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'selfProgram', + }), + ], + name: 'createRecord', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + const cpiSection = content.substring(content.indexOf('Instruction builder for `CreateRecord` via CPI')); + + codeContains(cpiSection, [ + /CreateRecordCpiBuilder<'a, 'b>/, + /pub fn new\(\s*__program: &'b solana_account_info::AccountInfo<'a>,\s*owner: &'b solana_account_info::AccountInfo<'a>,\s*mint: &'b solana_account_info::AccountInfo<'a>,\s*record: &'b solana_account_info::AccountInfo<'a>,/, + ]); + codeContains(cpiSection, [ + /record: &'b solana_account_info::AccountInfo<'a>,\s*self_program: Option<&'b solana_account_info::AccountInfo<'a>>,/, + ]); + codeContains(cpiSection, [/record: self\.instruction\.record,/]); + codeContains(cpiSection, [`self.instruction.self_program.unwrap_or(self.instruction.__program)`]); + codeDoesNotContains(cpiSection, [`pub fn record(`]); + codeContains(cpiSection, [`pub fn self_program(`]); + codeDoesNotContains(cpiSection, [/\[optional\].*record/]); + codeContains(cpiSection, [/\[optional\].*self_program/]); + + // Regular Builder still has record as optional (PDA auto-derived). + codeContains(content, [/pub struct CreateRecordBuilder \{[^}]*record: Option/]); +}); + +test('it avoids CPI builder param name collision when instruction has an account named program', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: true, isWritable: false, name: 'user' }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'program' }), + ], + name: 'myInstruction', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/my_instruction.rs').content; + const cpiSection = content.substring(content.indexOf('Instruction builder for `MyInstruction` via CPI')); + + // CPI builder first param is __program (not program) to avoid collision. + codeContains(cpiSection, [/pub fn new\(\s*__program: &'b solana_account_info::AccountInfo<'a>,/]); + // The instruction account named 'program' is a separate param. + codeContains(cpiSection, [/program: &'b solana_account_info::AccountInfo<'a>,/]); +}); + +test('it uses unwrap_or with precomputed address for zero-variable-seed linked PDA', () => { + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('config'), []), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'config', + }), + ], + name: 'doSomething', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'config', + seeds: [constantPdaSeedNodeFromString('utf8', 'config')], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/do_something.rs').content; + + codeContains(content, ['unwrap_or(', 'crate::pdas::CONFIG_ADDRESS']); + codeDoesNotContains(content, ['unwrap_or_else', 'find_config_pda']); +}); diff --git a/test/pdasPage.test.ts b/test/pdasPage.test.ts new file mode 100644 index 0000000..673d86d --- /dev/null +++ b/test/pdasPage.test.ts @@ -0,0 +1,211 @@ +import { + bytesTypeNode, + constantPdaSeedNode, + constantPdaSeedNodeFromBytes, + constantPdaSeedNodeFromString, + fixedSizeTypeNode, + numberTypeNode, + numberValueNode, + pdaNode, + programNode, + publicKeyTypeNode, + rootNode, + variablePdaSeedNode, +} from '@codama/nodes'; +import { getFromRenderMap } from '@codama/renderers-core'; +import { visit } from '@codama/visitors-core'; +import { test } from 'vitest'; + +import { getRenderMapVisitor } from '../src'; +import { codeContains, codeDoesNotContains } from './_setup'; + +test('it renders a standalone PDA with variable seeds', () => { + // Given a program with a PDA that has variable seeds. + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'metadata'), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect a standalone PDA file to be created. + codeContains(getFromRenderMap(renderMap, 'pdas/my_pda.rs').content, [ + 'pub const MY_PDA_SEED: &\'static [u8] = b"metadata";', + 'pub fn create_my_pda_pda(', + 'mint: Address,', + 'bump: u8,', + 'pub fn find_my_pda_pda(', + 'mint: &Address,', + '-> (solana_address::Address, u8)', + ]); +}); + +test('it renders a PDA with only constant seeds', () => { + // Given a program with a PDA that has only constant seeds. + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'configPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'config'), + constantPdaSeedNode(numberTypeNode('u64'), numberValueNode(1)), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + codeContains(getFromRenderMap(renderMap, 'pdas/config_pda.rs').content, [ + 'pub const CONFIG_PDA_SEED_0: &\'static [u8] = b"config";', + "pub const CONFIG_PDA_SEED_1: &'static [u8] = &1u64.to_le_bytes();", + 'pub const CONFIG_PDA_ADDRESS: solana_address::Address =', + 'solana_address::address!("EdgDu3sEjDtMpJuDkG8VsWnKq16EYxTsuwCmSko3wZnR")', + 'pub fn create_config_pda_pda(', + 'bump: u8,', + 'pub fn find_config_pda_pda(', + ') -> (solana_address::Address, u8)', + ]); +}); + +test('it renders a PDA with byte array seeds', () => { + // Given a program with a PDA that has byte array seeds. + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'hashPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'hash'), + variablePdaSeedNode('dataHash', fixedSizeTypeNode(bytesTypeNode(), 32)), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the byte array to be handled correctly. + codeContains(getFromRenderMap(renderMap, 'pdas/hash_pda.rs').content, [ + 'pub const HASH_PDA_SEED: &\'static [u8] = b"hash";', + 'pub fn create_hash_pda_pda(', + 'data_hash: [u8; 32],', + '&data_hash,', + 'pub fn find_hash_pda_pda(', + 'data_hash: [u8; 32],', + ]); +}); + +test('it renders a PDA module file', () => { + // Given a root node with a program containing multiple PDAs. + const program = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'firstPda', + seeds: [constantPdaSeedNodeFromString('utf8', 'first')], + }), + pdaNode({ + name: 'secondPda', + seeds: [constantPdaSeedNodeFromString('utf8', 'second')], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + const node = rootNode(program); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect a module file to be created. + codeContains(getFromRenderMap(renderMap, 'pdas/mod.rs').content, [ + 'pub mod first_pda;', + 'pub mod second_pda;', + 'pub use self::first_pda::*;', + 'pub use self::second_pda::*;', + ]); +}); + +test('it includes PDAs module in the root mod file', () => { + // Given a root node with a program containing PDAs. + const program = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [constantPdaSeedNodeFromString('utf8', 'test')], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + const node = rootNode(program); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect the pdas module to be included in the root mod. + codeContains(getFromRenderMap(renderMap, 'mod.rs').content, ['pub mod pdas;']); +}); + +test('it does not emit a precomputed address for PDAs with variable seeds', () => { + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'metadata'), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + codeDoesNotContains(getFromRenderMap(renderMap, 'pdas/my_pda.rs').content, ['_ADDRESS']); +}); + +test('it renders a PDA with byte array constant seeds', () => { + // Given a program with a PDA that has byte array seeds (e.g. from Anchor IDL extraction). + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'guardPda', + seeds: [ + constantPdaSeedNodeFromBytes('base58', 'F9bS'), + variablePdaSeedNode('mint', publicKeyTypeNode()), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then we expect byte array seeds to use &[...] syntax, not b[...]. + codeContains(getFromRenderMap(renderMap, 'pdas/guard_pda.rs').content, [ + "pub const GUARD_PDA_SEED: &'static [u8] = &[", + 'pub fn create_guard_pda_pda(', + 'mint: Address,', + 'pub fn find_guard_pda_pda(', + 'mint: &Address,', + ]); +}); diff --git a/test/utils/traitOptions.test.ts b/test/utils/traitOptions.test.ts index 5609923..68f677b 100644 --- a/test/utils/traitOptions.test.ts +++ b/test/utils/traitOptions.test.ts @@ -131,8 +131,8 @@ describe('default values', () => { overrides: { coordinates: ['My', 'special::Traits', 'serde::Serialize'] }, }); - // Then we expect the following traits to be rendered. - expect(render).toBe(`#[derive(My, Traits, Serialize)]\n`); + // Then we expect the following traits to be rendered (including rename_all since serde is present). + expect(render).toBe(`#[derive(My, Traits, Serialize)]\n#[serde(rename_all = "camelCase")]\n`); }); }); @@ -342,6 +342,104 @@ describe('overridden traits', () => { }); }); +describe('feature-flag-only traits (not in defaults)', () => { + test('it injects feature-flagged traits that are not in any defaults', () => { + // Given a struct defined type with no serde in defaults. + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + }); + + // When we specify traits only in featureFlags (not in baseDefaults). + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize'], + }, + }); + + // Then we expect the feature-only trait to appear in cfg_attr (with rename_all). + expect(render).toBe( + `#[derive(Clone, Debug)]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize))]\n` + + `#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]\n`, + ); + }); + + test('it injects multiple feature-flag-only traits across different features', () => { + // Given a struct defined type. + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + }); + + // When we specify traits only in featureFlags with multiple features. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['Clone'], + featureFlags: { + extra: ['MyExtraTrait'], + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + // Then all feature-only traits appear in their respective cfg_attr blocks (with rename_all for serde). + expect(render).toBe( + `#[derive(Clone)]\n` + + `#[cfg_attr(feature = "extra", derive(MyExtraTrait))]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n` + + `#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]\n`, + ); + }); + + test('it mixes default-partitioned and feature-only traits correctly', () => { + // Given a struct defined type. + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + }); + + // When some featureFlags traits are in defaults and some are not. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + baseDefaults: ['Clone', 'Debug', 'serde::Serialize'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + // Then Serialize (in defaults) and Deserialize (not in defaults) both appear under serde (with rename_all). + expect(render).toBe( + `#[derive(Clone, Debug)]\n` + + `#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]\n` + + `#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]\n`, + ); + }); + + test('it works with feature-only traits and no defaults at all', () => { + // Given a struct defined type. + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + }); + + // When all traits are only in featureFlags. + const { render } = getTraitsFromNode(node, { + ...RESET_OPTIONS, + featureFlags: { + serde: ['serde::Serialize'], + }, + }); + + // Then only cfg_attr is rendered with no #[derive(...)] (with rename_all). + expect(render).toBe( + `#[cfg_attr(feature = "serde", derive(serde::Serialize))]\n` + + `#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]\n`, + ); + }); +}); + describe('fully qualified name traits', () => { test('it can use fully qualified names for traits instead of importing them', () => { // Given a scalar enum defined type. @@ -635,4 +733,251 @@ describe('conditional serde field attributes', () => { expect(account).toContain('#[serde(with = "serde_with::As::")]'); expect(account).not.toContain('#[cfg_attr(feature = "serde"'); }); + + test('it emits serde field attributes when serde is only in featureFlags (not in defaults)', () => { + // Given an account with a Pubkey field. + const node = accountNode({ + data: structTypeNode([structFieldTypeNode({ name: 'authority', type: publicKeyTypeNode() })]), + name: 'myAccount', + }); + + // When serde traits are only in featureFlags, not in baseDefaults. + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['BorshSerialize', 'BorshDeserialize', 'Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }, + }), + ); + + // Then we expect both cfg_attr derive and cfg_attr serde field attributes. + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + expect(account).toContain('#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]'); + expect(account).toContain( + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]', + ); + }); + + test('it generates DisplayFromStr for u64 fields when serde is feature-flagged', () => { + const node = accountNode({ + data: structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + name: 'myAccount', + }); + + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['BorshSerialize', 'BorshDeserialize', 'Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }, + }), + ); + + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + expect(account).toContain( + '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))]', + ); + }); + + test('it generates DisplayFromStr for i64 fields when serde is not feature-flagged', () => { + const node = accountNode({ + data: structTypeNode([structFieldTypeNode({ name: 'timestamp', type: numberTypeNode('i64') })]), + name: 'myAccount', + }); + + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['serde::Serialize', 'serde::Deserialize', 'Clone', 'Debug'], + featureFlags: {}, + }, + }), + ); + + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + expect(account).toContain('#[serde(with = "serde_with::As::")]'); + expect(account).not.toContain('#[cfg_attr(feature = "serde"'); + }); + + test('it generates DisplayFromStr for u128 and i128 fields', () => { + const node = accountNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'bigUnsigned', type: numberTypeNode('u128') }), + structFieldTypeNode({ name: 'bigSigned', type: numberTypeNode('i128') }), + ]), + name: 'myAccount', + }); + + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['BorshSerialize', 'BorshDeserialize', 'Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }, + }), + ); + + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + // Both u128 and i128 fields should have DisplayFromStr. + const matches = account.match( + /#\[cfg_attr\(feature = "serde", serde\(with = "serde_with::As::"\)\)\]/g, + ); + expect(matches).toHaveLength(2); + }); + + test('it does not generate DisplayFromStr for u32 fields', () => { + const node = accountNode({ + data: structTypeNode([structFieldTypeNode({ name: 'count', type: numberTypeNode('u32') })]), + name: 'myAccount', + }); + + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['BorshSerialize', 'BorshDeserialize', 'Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }, + }), + ); + + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + expect(account).not.toContain('DisplayFromStr'); + }); + + test('it does not generate DisplayFromStr for u64 fields when serde is absent', () => { + const node = accountNode({ + data: structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + name: 'myAccount', + }); + + const renderMap = visit( + rootNode(programNode({ accounts: [node], name: 'myProgram', publicKey: '1111' })), + getRenderMapVisitor({ + traitOptions: { + baseDefaults: ['BorshSerialize', 'BorshDeserialize', 'Clone', 'Debug'], + featureFlags: {}, + }, + }), + ); + + const account = getFromRenderMap(renderMap, 'accounts/my_account.rs').content; + expect(account).not.toContain('DisplayFromStr'); + }); +}); + +describe('serde rename_all container attribute', () => { + test('it adds rename_all when serde is in baseDefaults (not feature-flagged)', () => { + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'myField', type: numberTypeNode('u32') })]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['serde::Serialize', 'serde::Deserialize', 'Clone', 'Debug'], + featureFlags: {}, + }); + + expect(render).toContain('#[serde(rename_all = "camelCase")]'); + expect(render).not.toContain('cfg_attr'); + }); + + test('it adds rename_all with cfg_attr when serde is feature-flagged', () => { + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'myField', type: numberTypeNode('u32') })]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + expect(render).toContain('#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]'); + }); + + test('it does not add rename_all when no serde traits are present', () => { + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'myField', type: numberTypeNode('u32') })]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['Clone', 'Debug'], + featureFlags: {}, + }); + + expect(render).not.toContain('rename_all'); + expect(render).not.toContain('serde'); + }); + + test('it does not add rename_all on scalar enums', () => { + const node = definedTypeNode({ + name: 'MyEnum', + type: enumTypeNode([enumEmptyVariantTypeNode('VariantA'), enumEmptyVariantTypeNode('VariantB')]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + expect(render).not.toContain('rename_all'); + }); + + test('it does not add rename_all on data enums', () => { + const node = definedTypeNode({ + name: 'MyEnum', + type: enumTypeNode([ + enumEmptyVariantTypeNode('VariantA'), + enumStructVariantTypeNode( + 'VariantB', + structTypeNode([structFieldTypeNode({ name: 'someField', type: numberTypeNode('u64') })]), + ), + ]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['Clone', 'Debug'], + featureFlags: { + serde: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + expect(render).not.toContain('rename_all'); + }); + + test('it uses custom feature name for rename_all', () => { + const node = definedTypeNode({ + name: 'MyStruct', + type: structTypeNode([structFieldTypeNode({ name: 'myField', type: numberTypeNode('u32') })]), + }); + + const { render } = getTraitsFromNode(node, { + baseDefaults: ['Clone', 'Debug'], + featureFlags: { + json_support: ['serde::Serialize', 'serde::Deserialize'], + }, + }); + + expect(render).toContain('#[cfg_attr(feature = "json_support", serde(rename_all = "camelCase"))]'); + expect(render).not.toContain('feature = "serde"'); + }); });