diff --git a/.changeset/add-event-codegen.md b/.changeset/add-event-codegen.md new file mode 100644 index 0000000..e3c7c4b --- /dev/null +++ b/.changeset/add-event-codegen.md @@ -0,0 +1,5 @@ +--- +'@codama/renderers-rust': minor +--- + +Add event codegen support diff --git a/.changeset/anchor-cpi-event-framing.md b/.changeset/anchor-cpi-event-framing.md new file mode 100644 index 0000000..92d976d --- /dev/null +++ b/.changeset/anchor-cpi-event-framing.md @@ -0,0 +1,5 @@ +--- +'@codama/renderers-rust': minor +--- + +Support Anchor CPI event framing in event codegen 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 0931114..ccb9d89 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" @@ -575,6 +584,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[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" @@ -605,6 +626,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-cpi 3.1.0", + "solana-decode-error", + "solana-instruction 3.2.0", + "solana-program-error 3.0.0", + "solana-rpc-client", + "spl-collections", + "thiserror 1.0.69", +] + [[package]] name = "codama-renderers-rust-e2e-memo" version = "0.0.0" @@ -638,6 +683,42 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "codama-renderers-rust-e2e-raydium-cpmm" +version = "0.0.0" +dependencies = [ + "anchor-lang", + "borsh 1.5.7", + "num-derive", + "num-traits", + "solana-account 3.0.0", + "solana-account-info 3.1.0", + "solana-address 2.2.0", + "solana-cpi 3.1.0", + "solana-instruction 3.2.0", + "solana-program-error 3.0.0", + "solana-rpc-client", + "thiserror 1.0.69", +] + +[[package]] +name = "codama-renderers-rust-e2e-raydium-launchpad" +version = "0.0.0" +dependencies = [ + "anchor-lang", + "borsh 1.5.7", + "num-derive", + "num-traits", + "solana-account 3.0.0", + "solana-account-info 3.1.0", + "solana-address 2.2.0", + "solana-cpi 3.1.0", + "solana-instruction 3.2.0", + "solana-program-error 3.0.0", + "solana-rpc-client", + "thiserror 1.0.69", +] + [[package]] name = "codama-renderers-rust-e2e-system" version = "0.0.0" @@ -726,6 +807,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -823,6 +910,16 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "deranged" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +dependencies = [ + "powerfmt", + "serde_core", +] + [[package]] name = "digest" version = "0.9.0" @@ -854,6 +951,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 = "either" version = "1.15.0" @@ -1139,6 +1242,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "http" version = "1.4.0" @@ -1239,6 +1348,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" @@ -1352,6 +1485,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" @@ -1360,6 +1504,8 @@ checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.16.0", + "serde", + "serde_core", ] [[package]] @@ -1443,6 +1589,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" @@ -1583,6 +1738,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.4.2" @@ -1701,6 +1862,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1916,6 +2083,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" @@ -2082,6 +2269,30 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[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" @@ -2177,6 +2388,38 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +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]] +name = "serde_with_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "sha2" version = "0.9.9" @@ -3924,6 +4167,37 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.8.1" @@ -4048,7 +4322,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", @@ -4062,7 +4336,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", @@ -4398,12 +4672,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.52.0" diff --git a/Cargo.toml b/Cargo.toml index 676cc87..1352002 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 d766a97..2b2bb35 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..a4b979e 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,54 @@ impl CreateGuardBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let mint = self.mint; + let guard = self + .guard + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.mint).0); + let guard_authority = self.guard_authority; + let mint_token_account = self.mint_token_account.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.guard_authority.as_ref(), + &[ + 6, 221, 246, 225, 238, 117, 143, 222, 24, 66, 93, 188, 228, 108, 205, 218, + 182, 26, 252, 77, 131, 185, 13, 39, 254, 189, 249, 40, 216, 161, 139, 252, + ], + self.mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + 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 +460,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 +507,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 +542,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 +571,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..152cba4 100644 --- a/e2e/anchor/src/generated/instructions/execute.rs +++ b/e2e/anchor/src/generated/instructions/execute.rs @@ -7,6 +7,7 @@ use borsh::BorshDeserialize; use borsh::BorshSerialize; +use solana_address::Address; pub const EXECUTE_DISCRIMINATOR: [u8; 8] = [105, 37, 101, 197, 75, 251, 102, 26]; @@ -121,49 +122,46 @@ impl ExecuteInstructionArgs { /// 1. `[]` mint /// 2. `[]` destination_account /// 3. `[]` owner_delegate -/// 4. `[]` extra_metas_account -/// 5. `[]` guard +/// 4. `[optional]` extra_metas_account (default to PDA derived from 'extraMetasAccount') +/// 5. `[optional]` guard (default to PDA derived from '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, instruction_sysvar_account: Option, - amount: Option, + amount: u64, + guard_mint: Address, __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, + amount: u64, + guard_mint: Address, + ) -> Self { + Self { + source_account, + mint, + destination_account, + owner_delegate, + extra_metas_account: None, + guard: None, + instruction_sysvar_account: None, + amount, + guard_mint, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'extraMetasAccount']` #[inline(always)] pub fn extra_metas_account( &mut self, @@ -172,6 +170,7 @@ impl ExecuteBuilder { self.extra_metas_account = Some(extra_metas_account); self } + /// `[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); @@ -186,11 +185,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 +202,32 @@ 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 + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.guard_mint.clone()).0); + 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 +397,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 +457,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 +480,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..c972c7c 100644 --- a/e2e/anchor/src/generated/instructions/initialize.rs +++ b/e2e/anchor/src/generated/instructions/initialize.rs @@ -7,6 +7,7 @@ use borsh::BorshDeserialize; use borsh::BorshSerialize; +use solana_address::Address; pub const INITIALIZE_DISCRIMINATOR: [u8; 8] = [43, 34, 13, 49, 167, 88, 235, 235]; @@ -94,27 +95,43 @@ impl Default for InitializeInstructionData { /// /// ### Accounts: /// -/// 0. `[writable]` extra_metas_account -/// 1. `[]` guard +/// 0. `[writable, optional]` extra_metas_account (default to PDA derived from 'extraMetasAccount') +/// 1. `[optional]` guard (default to PDA derived from '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, + mint: solana_address::Address, + transfer_hook_authority: solana_address::Address, system_program: Option, - payer: Option, + payer: solana_address::Address, + guard_mint: Address, __remaining_accounts: Vec, } impl InitializeBuilder { - pub fn new() -> Self { - Self::default() + pub fn new( + mint: solana_address::Address, + transfer_hook_authority: solana_address::Address, + payer: solana_address::Address, + guard_mint: Address, + ) -> Self { + Self { + extra_metas_account: None, + guard: None, + mint, + transfer_hook_authority, + system_program: None, + payer, + guard_mint, + __remaining_accounts: Vec::new(), + } } + /// `[optional account, default to PDA derived from 'extraMetasAccount']` #[inline(always)] pub fn extra_metas_account( &mut self, @@ -123,35 +140,18 @@ impl InitializeBuilder { self.extra_metas_account = Some(extra_metas_account); self } + /// `[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 - } - #[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 +169,25 @@ impl InitializeBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let mint = self.mint; + 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 + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.guard_mint.clone()).0); + 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 +337,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 +394,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 +411,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..41d0f22 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,43 @@ impl UpdateGuardBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_instruction::Instruction { + let mint = self.mint; + let guard = self + .guard + .unwrap_or_else(|| crate::pdas::find_guard_pda(&self.mint).0); + let guard_authority = self.guard_authority; + let token_account = self.token_account.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.guard_authority.as_ref(), + &[ + 6, 221, 246, 225, 238, 117, 143, 222, 24, 66, 93, 188, 228, 108, 205, 218, + 182, 26, 252, 77, 131, 185, 13, 39, 254, 189, 249, 40, 216, 161, 139, 252, + ], + self.mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + 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 +398,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 +435,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 +472,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 +494,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/anchor/src/lib.rs b/e2e/anchor/src/lib.rs index 9974b79..7020a76 100644 --- a/e2e/anchor/src/lib.rs +++ b/e2e/anchor/src/lib.rs @@ -2,3 +2,43 @@ mod generated; pub use generated::programs::WEN_TRANSFER_GUARD_ID as ID; pub use generated::*; + +#[cfg(test)] +mod tests { + use solana_address::Address; + + #[test] + fn execute_auto_derives_guard_from_guard_mint() { + let mint = Address::new_from_array([2u8; 32]); + let guard_mint = Address::new_from_array([7u8; 32]); + let ix = crate::instructions::ExecuteBuilder::new( + Address::new_from_array([1u8; 32]), // source_account + mint, // mint + Address::new_from_array([3u8; 32]), // destination_account + Address::new_from_array([4u8; 32]), // owner_delegate + 42, // amount + guard_mint, + ) + .instruction(); + + let expected = crate::pdas::find_guard_pda(&guard_mint).0; + assert_eq!(ix.accounts[5].pubkey, expected, "guard"); + // The seed must come from `guard_mint`, not the instruction's `mint` account. + assert_ne!(ix.accounts[5].pubkey, crate::pdas::find_guard_pda(&mint).0); + } + + #[test] + fn initialize_auto_derives_guard_from_guard_mint() { + let guard_mint = Address::new_from_array([9u8; 32]); + let ix = crate::instructions::InitializeBuilder::new( + Address::new_from_array([1u8; 32]), // mint + Address::new_from_array([2u8; 32]), // transfer_hook_authority + Address::new_from_array([3u8; 32]), // payer + guard_mint, + ) + .instruction(); + + let expected = crate::pdas::find_guard_pda(&guard_mint).0; + assert_eq!(ix.accounts[1].pubkey, expected, "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..60d62c1 --- /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-rpc-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-rpc-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..f12d692 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..b5b9081 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..d62e596 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..3f69835 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..e69f999 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..d5122a0 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..05d5391 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..3655f8f --- /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_rpc_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_rpc_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_rpc_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_rpc_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..ba8be19 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..a49e893 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..b7a2a95 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..c9be104 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..6c901f0 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..065a15e --- /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_rpc_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_rpc_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_rpc_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_rpc_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..7b476d1 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..43528b7 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..1edc54b --- /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_rpc_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_rpc_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_rpc_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_rpc_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..a874558 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..19660e6 --- /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_rpc_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_rpc_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_rpc_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_rpc_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..496aa3e --- /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 governing_token_mint = self.governing_token_mint; + 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 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/raydium-cpmm/Cargo.toml b/e2e/raydium-cpmm/Cargo.toml new file mode 100644 index 0000000..b04ca00 --- /dev/null +++ b/e2e/raydium-cpmm/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "codama-renderers-rust-e2e-raydium-cpmm" +version = "0.0.0" +edition = "2021" + +[features] +anchor = ["dep:anchor-lang"] +anchor-idl-build = ["anchor", "anchor-lang?/idl-build"] +test-sbf = [] +fetch = ["dep:solana-rpc-client"] + +[dependencies] +anchor-lang = { workspace = true, optional = true } +borsh = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } +solana-account = { workspace = true } +solana-account-info = { workspace = true } +solana-address = { workspace = true, features = ["borsh", "copy", "curve25519", "decode"] } +solana-rpc-client = { workspace = true, optional = true } +solana-cpi = { workspace = true } +solana-instruction = { workspace = true } +solana-program-error = { workspace = true } +thiserror = { workspace = true } diff --git a/e2e/raydium-cpmm/idl.json b/e2e/raydium-cpmm/idl.json new file mode 100644 index 0000000..5a93905 --- /dev/null +++ b/e2e/raydium-cpmm/idl.json @@ -0,0 +1,2115 @@ +{ + "address": "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C", + "metadata": { + "name": "raydium_cp_swap", + "version": "0.2.0", + "spec": "0.1.0", + "description": "Raydium constant product AMM, supports Token2022 and without Openbook" + }, + "instructions": [ + { + "name": "collect_fund_fee", + "docs": [ + "Collect the fund fee accrued to the pool", + "", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_0_requested` - The maximum amount of token_0 to send, can be 0 to collect fees in only token_1", + "* `amount_1_requested` - The maximum amount of token_1 to send, can be 0 to collect fees in only token_0", + "" + ], + "discriminator": [ + 167, + 138, + 78, + 149, + 223, + 194, + 6, + 126 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Only admin or fund_owner can collect fee now" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Pool state stores accumulated protocol fee amount" + ], + "writable": true + }, + { + "name": "amm_config", + "docs": [ + "Amm config account stores fund_owner" + ] + }, + { + "name": "token_0_vault", + "docs": [ + "The address that holds pool tokens for token_0" + ], + "writable": true + }, + { + "name": "token_1_vault", + "docs": [ + "The address that holds pool tokens for token_1" + ], + "writable": true + }, + { + "name": "vault_0_mint", + "docs": [ + "The mint of token_0 vault" + ] + }, + { + "name": "vault_1_mint", + "docs": [ + "The mint of token_1 vault" + ] + }, + { + "name": "recipient_token_0_account", + "docs": [ + "The address that receives the collected token_0 fund fees" + ], + "writable": true + }, + { + "name": "recipient_token_1_account", + "docs": [ + "The address that receives the collected token_1 fund fees" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "The SPL program to perform token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "token_program_2022", + "docs": [ + "The SPL program 2022 to perform token transfers" + ], + "address": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + } + ], + "args": [ + { + "name": "amount_0_requested", + "type": "u64" + }, + { + "name": "amount_1_requested", + "type": "u64" + } + ] + }, + { + "name": "collect_protocol_fee", + "docs": [ + "Collect the protocol fee accrued to the pool", + "", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_0_requested` - The maximum amount of token_0 to send, can be 0 to collect fees in only token_1", + "* `amount_1_requested` - The maximum amount of token_1 to send, can be 0 to collect fees in only token_0", + "" + ], + "discriminator": [ + 136, + 136, + 252, + 221, + 194, + 66, + 126, + 89 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Only admin or owner can collect fee now" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Pool state stores accumulated protocol fee amount" + ], + "writable": true + }, + { + "name": "amm_config", + "docs": [ + "Amm config account stores owner" + ] + }, + { + "name": "token_0_vault", + "docs": [ + "The address that holds pool tokens for token_0" + ], + "writable": true + }, + { + "name": "token_1_vault", + "docs": [ + "The address that holds pool tokens for token_1" + ], + "writable": true + }, + { + "name": "vault_0_mint", + "docs": [ + "The mint of token_0 vault" + ] + }, + { + "name": "vault_1_mint", + "docs": [ + "The mint of token_1 vault" + ] + }, + { + "name": "recipient_token_0_account", + "docs": [ + "The address that receives the collected token_0 protocol fees" + ], + "writable": true + }, + { + "name": "recipient_token_1_account", + "docs": [ + "The address that receives the collected token_1 protocol fees" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "The SPL program to perform token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "token_program_2022", + "docs": [ + "The SPL program 2022 to perform token transfers" + ], + "address": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + } + ], + "args": [ + { + "name": "amount_0_requested", + "type": "u64" + }, + { + "name": "amount_1_requested", + "type": "u64" + } + ] + }, + { + "name": "create_amm_config", + "docs": [ + "# Arguments", + "", + "* `ctx`- The accounts needed by instruction.", + "* `index` - The index of amm config, there may be multiple config.", + "* `trade_fee_rate` - Trade fee rate, can be changed.", + "* `protocol_fee_rate` - The rate of protocol fee within trade fee.", + "* `fund_fee_rate` - The rate of fund fee within trade fee.", + "" + ], + "discriminator": [ + 137, + 52, + 237, + 212, + 215, + 117, + 108, + 104 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Address to be set as protocol owner." + ], + "writable": true, + "signer": true, + "address": "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + }, + { + "name": "amm_config", + "docs": [ + "Initialize config state account to store protocol owner address and fee rates." + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 97, + 109, + 109, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "arg", + "path": "index" + } + ] + } + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "index", + "type": "u16" + }, + { + "name": "trade_fee_rate", + "type": "u64" + }, + { + "name": "protocol_fee_rate", + "type": "u64" + }, + { + "name": "fund_fee_rate", + "type": "u64" + }, + { + "name": "create_pool_fee", + "type": "u64" + } + ] + }, + { + "name": "deposit", + "docs": [ + "Deposit lp token to the pool", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `lp_token_amount` - Pool token amount to transfer. token_a and token_b amount are set by the current exchange rate and size of the pool", + "* `maximum_token_0_amount` - Maximum token 0 amount to deposit, prevents excessive slippage", + "* `maximum_token_1_amount` - Maximum token 1 amount to deposit, prevents excessive slippage", + "" + ], + "discriminator": [ + 242, + 35, + 198, + 137, + 82, + 225, + 242, + 182 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Pays to mint the position" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "writable": true + }, + { + "name": "owner_lp_token", + "docs": [ + "Owner lp token account" + ], + "writable": true + }, + { + "name": "token_0_account", + "docs": [ + "The payer's token account for token_0" + ], + "writable": true + }, + { + "name": "token_1_account", + "docs": [ + "The payer's token account for token_1" + ], + "writable": true + }, + { + "name": "token_0_vault", + "docs": [ + "The address that holds pool tokens for token_0" + ], + "writable": true + }, + { + "name": "token_1_vault", + "docs": [ + "The address that holds pool tokens for token_1" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "token Program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "token_program_2022", + "docs": [ + "Token program 2022" + ], + "address": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + }, + { + "name": "vault_0_mint", + "docs": [ + "The mint of token_0 vault" + ] + }, + { + "name": "vault_1_mint", + "docs": [ + "The mint of token_1 vault" + ] + }, + { + "name": "lp_mint", + "docs": [ + "Lp token mint" + ], + "writable": true + } + ], + "args": [ + { + "name": "lp_token_amount", + "type": "u64" + }, + { + "name": "maximum_token_0_amount", + "type": "u64" + }, + { + "name": "maximum_token_1_amount", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "docs": [ + "Creates a pool for the given token pair and the initial price", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `init_amount_0` - the initial amount_0 to deposit", + "* `init_amount_1` - the initial amount_1 to deposit", + "* `open_time` - the timestamp allowed for swap", + "" + ], + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "creator", + "docs": [ + "Address paying to create the pool. Can be anyone" + ], + "writable": true, + "signer": true + }, + { + "name": "amm_config", + "docs": [ + "Which config the pool belongs to." + ] + }, + { + "name": "authority", + "docs": [ + "pool vault and lp mint authority" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "PDA account:", + "seeds = [", + "POOL_SEED.as_bytes(),", + "amm_config.key().as_ref(),", + "token_0_mint.key().as_ref(),", + "token_1_mint.key().as_ref(),", + "],", + "", + "Or random account: must be signed by cli" + ], + "writable": true + }, + { + "name": "token_0_mint", + "docs": [ + "Token_0 mint, the key must smaller than token_1 mint." + ] + }, + { + "name": "token_1_mint", + "docs": [ + "Token_1 mint, the key must grater then token_0 mint." + ] + }, + { + "name": "lp_mint", + "docs": [ + "pool lp mint" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116 + ] + }, + { + "kind": "account", + "path": "pool_state" + } + ] + } + }, + { + "name": "creator_token_0", + "docs": [ + "payer token0 account" + ], + "writable": true + }, + { + "name": "creator_token_1", + "docs": [ + "creator token1 account" + ], + "writable": true + }, + { + "name": "creator_lp_token", + "docs": [ + "creator lp token account" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "creator" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "lp_mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "token_0_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "token_0_mint" + } + ] + } + }, + { + "name": "token_1_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "token_1_mint" + } + ] + } + }, + { + "name": "create_pool_fee", + "docs": [ + "create pool fee account" + ], + "writable": true, + "address": "DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8" + }, + { + "name": "observation_state", + "docs": [ + "an account to store oracle observations" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 111, + 98, + 115, + 101, + 114, + 118, + 97, + 116, + 105, + 111, + 110 + ] + }, + { + "kind": "account", + "path": "pool_state" + } + ] + } + }, + { + "name": "token_program", + "docs": [ + "Program to create mint account and mint tokens" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "token_0_program", + "docs": [ + "Spl token program or token program 2022" + ] + }, + { + "name": "token_1_program", + "docs": [ + "Spl token program or token program 2022" + ] + }, + { + "name": "associated_token_program", + "docs": [ + "Program to create an ATA for receiving position NFT" + ], + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "system_program", + "docs": [ + "To create a new program account" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "rent", + "docs": [ + "Sysvar for program account" + ], + "address": "SysvarRent111111111111111111111111111111111" + } + ], + "args": [ + { + "name": "init_amount_0", + "type": "u64" + }, + { + "name": "init_amount_1", + "type": "u64" + }, + { + "name": "open_time", + "type": "u64" + } + ] + }, + { + "name": "swap_base_input", + "docs": [ + "Swap the tokens in the pool base input amount", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `amount_in` - input amount to transfer, output to DESTINATION is based on the exchange rate", + "* `minimum_amount_out` - Minimum amount of output token, prevents excessive slippage", + "" + ], + "discriminator": [ + 143, + 190, + 90, + 218, + 196, + 30, + 51, + 222 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "amm_config", + "docs": [ + "The factory state to read protocol fees" + ] + }, + { + "name": "pool_state", + "docs": [ + "The program account of the pool in which the swap will be performed" + ], + "writable": true + }, + { + "name": "input_token_account", + "docs": [ + "The user token account for input token" + ], + "writable": true + }, + { + "name": "output_token_account", + "docs": [ + "The user token account for output token" + ], + "writable": true + }, + { + "name": "input_vault", + "docs": [ + "The vault token account for input token" + ], + "writable": true + }, + { + "name": "output_vault", + "docs": [ + "The vault token account for output token" + ], + "writable": true + }, + { + "name": "input_token_program", + "docs": [ + "SPL program for input token transfers" + ] + }, + { + "name": "output_token_program", + "docs": [ + "SPL program for output token transfers" + ] + }, + { + "name": "input_token_mint", + "docs": [ + "The mint of input token" + ] + }, + { + "name": "output_token_mint", + "docs": [ + "The mint of output token" + ] + }, + { + "name": "observation_state", + "docs": [ + "The program account for the most recent oracle observation" + ], + "writable": true + } + ], + "args": [ + { + "name": "amount_in", + "type": "u64" + }, + { + "name": "minimum_amount_out", + "type": "u64" + } + ] + }, + { + "name": "swap_base_output", + "docs": [ + "Swap the tokens in the pool base output amount", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `max_amount_in` - input amount prevents excessive slippage", + "* `amount_out` - amount of output token", + "" + ], + "discriminator": [ + 55, + 217, + 98, + 86, + 163, + 74, + 180, + 173 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "amm_config", + "docs": [ + "The factory state to read protocol fees" + ] + }, + { + "name": "pool_state", + "docs": [ + "The program account of the pool in which the swap will be performed" + ], + "writable": true + }, + { + "name": "input_token_account", + "docs": [ + "The user token account for input token" + ], + "writable": true + }, + { + "name": "output_token_account", + "docs": [ + "The user token account for output token" + ], + "writable": true + }, + { + "name": "input_vault", + "docs": [ + "The vault token account for input token" + ], + "writable": true + }, + { + "name": "output_vault", + "docs": [ + "The vault token account for output token" + ], + "writable": true + }, + { + "name": "input_token_program", + "docs": [ + "SPL program for input token transfers" + ] + }, + { + "name": "output_token_program", + "docs": [ + "SPL program for output token transfers" + ] + }, + { + "name": "input_token_mint", + "docs": [ + "The mint of input token" + ] + }, + { + "name": "output_token_mint", + "docs": [ + "The mint of output token" + ] + }, + { + "name": "observation_state", + "docs": [ + "The program account for the most recent oracle observation" + ], + "writable": true + } + ], + "args": [ + { + "name": "max_amount_in", + "type": "u64" + }, + { + "name": "amount_out", + "type": "u64" + } + ] + }, + { + "name": "update_amm_config", + "docs": [ + "Updates the owner of the amm config", + "Must be called by the current owner or admin", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `trade_fee_rate`- The new trade fee rate of amm config, be set when `param` is 0", + "* `protocol_fee_rate`- The new protocol fee rate of amm config, be set when `param` is 1", + "* `fund_fee_rate`- The new fund fee rate of amm config, be set when `param` is 2", + "* `new_owner`- The config's new owner, be set when `param` is 3", + "* `new_fund_owner`- The config's new fund owner, be set when `param` is 4", + "* `param`- The value can be 0 | 1 | 2 | 3 | 4, otherwise will report a error", + "" + ], + "discriminator": [ + 49, + 60, + 174, + 136, + 154, + 28, + 116, + 200 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "The amm config owner or admin" + ], + "signer": true, + "address": "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + }, + { + "name": "amm_config", + "docs": [ + "Amm config account to be changed" + ], + "writable": true + } + ], + "args": [ + { + "name": "param", + "type": "u8" + }, + { + "name": "value", + "type": "u64" + } + ] + }, + { + "name": "update_pool_status", + "docs": [ + "Update pool status for given value", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `status` - The value of status", + "" + ], + "discriminator": [ + 130, + 87, + 108, + 6, + 46, + 224, + 117, + 123 + ], + "accounts": [ + { + "name": "authority", + "signer": true, + "address": "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + }, + { + "name": "pool_state", + "writable": true + } + ], + "args": [ + { + "name": "status", + "type": "u8" + } + ] + }, + { + "name": "withdraw", + "docs": [ + "Withdraw lp for token0 and token1", + "", + "# Arguments", + "", + "* `ctx`- The context of accounts", + "* `lp_token_amount` - Amount of pool tokens to burn. User receives an output of token a and b based on the percentage of the pool tokens that are returned.", + "* `minimum_token_0_amount` - Minimum amount of token 0 to receive, prevents excessive slippage", + "* `minimum_token_1_amount` - Minimum amount of token 1 to receive, prevents excessive slippage", + "" + ], + "discriminator": [ + 183, + 18, + 70, + 156, + 148, + 109, + 161, + 34 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Pays to mint the position" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Pool state account" + ], + "writable": true + }, + { + "name": "owner_lp_token", + "docs": [ + "Owner lp token account" + ], + "writable": true + }, + { + "name": "token_0_account", + "docs": [ + "The token account for receive token_0," + ], + "writable": true + }, + { + "name": "token_1_account", + "docs": [ + "The token account for receive token_1" + ], + "writable": true + }, + { + "name": "token_0_vault", + "docs": [ + "The address that holds pool tokens for token_0" + ], + "writable": true + }, + { + "name": "token_1_vault", + "docs": [ + "The address that holds pool tokens for token_1" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "token Program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "token_program_2022", + "docs": [ + "Token program 2022" + ], + "address": "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + }, + { + "name": "vault_0_mint", + "docs": [ + "The mint of token_0 vault" + ] + }, + { + "name": "vault_1_mint", + "docs": [ + "The mint of token_1 vault" + ] + }, + { + "name": "lp_mint", + "docs": [ + "Pool lp token mint" + ], + "writable": true + }, + { + "name": "memo_program", + "docs": [ + "memo program" + ], + "address": "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr" + } + ], + "args": [ + { + "name": "lp_token_amount", + "type": "u64" + }, + { + "name": "minimum_token_0_amount", + "type": "u64" + }, + { + "name": "minimum_token_1_amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "AmmConfig", + "discriminator": [ + 218, + 244, + 33, + 104, + 203, + 203, + 43, + 111 + ] + }, + { + "name": "ObservationState", + "discriminator": [ + 122, + 174, + 197, + 53, + 129, + 9, + 165, + 132 + ] + }, + { + "name": "PoolState", + "discriminator": [ + 247, + 237, + 227, + 245, + 215, + 195, + 222, + 70 + ] + } + ], + "events": [ + { + "name": "LpChangeEvent", + "discriminator": [ + 121, + 163, + 205, + 201, + 57, + 218, + 117, + 60 + ] + }, + { + "name": "SwapEvent", + "discriminator": [ + 64, + 198, + 205, + 232, + 38, + 8, + 113, + 226 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "NotApproved", + "msg": "Not approved" + }, + { + "code": 6001, + "name": "InvalidOwner", + "msg": "Input account owner is not the program address" + }, + { + "code": 6002, + "name": "EmptySupply", + "msg": "Input token account empty" + }, + { + "code": 6003, + "name": "InvalidInput", + "msg": "InvalidInput" + }, + { + "code": 6004, + "name": "IncorrectLpMint", + "msg": "Address of the provided lp token mint is incorrect" + }, + { + "code": 6005, + "name": "ExceededSlippage", + "msg": "Exceeds desired slippage limit" + }, + { + "code": 6006, + "name": "ZeroTradingTokens", + "msg": "Given pool token amount results in zero trading tokens" + }, + { + "code": 6007, + "name": "NotSupportMint", + "msg": "Not support token_2022 mint extension" + }, + { + "code": 6008, + "name": "InvalidVault", + "msg": "invaild vault" + }, + { + "code": 6009, + "name": "InitLpAmountTooLess", + "msg": "Init lp amount is too less(Because 100 amount lp will be locked)" + }, + { + "code": 6010, + "name": "TransferFeeCalculateNotMatch", + "msg": "TransferFee calculate not match" + } + ], + "types": [ + { + "name": "AmmConfig", + "docs": [ + "Holds the current owner of the factory" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "bump", + "docs": [ + "Bump to identify PDA" + ], + "type": "u8" + }, + { + "name": "disable_create_pool", + "docs": [ + "Status to control if new pool can be create" + ], + "type": "bool" + }, + { + "name": "index", + "docs": [ + "Config index" + ], + "type": "u16" + }, + { + "name": "trade_fee_rate", + "docs": [ + "The trade fee, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "protocol_fee_rate", + "docs": [ + "The protocol fee" + ], + "type": "u64" + }, + { + "name": "fund_fee_rate", + "docs": [ + "The fund fee, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "create_pool_fee", + "docs": [ + "Fee for create a new pool" + ], + "type": "u64" + }, + { + "name": "protocol_owner", + "docs": [ + "Address of the protocol fee owner" + ], + "type": "pubkey" + }, + { + "name": "fund_owner", + "docs": [ + "Address of the fund fee owner" + ], + "type": "pubkey" + }, + { + "name": "padding", + "docs": [ + "padding" + ], + "type": { + "array": [ + "u64", + 16 + ] + } + } + ] + } + }, + { + "name": "LpChangeEvent", + "docs": [ + "Emitted when deposit and withdraw" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_id", + "type": "pubkey" + }, + { + "name": "lp_amount_before", + "type": "u64" + }, + { + "name": "token_0_vault_before", + "docs": [ + "pool vault sub trade fees" + ], + "type": "u64" + }, + { + "name": "token_1_vault_before", + "docs": [ + "pool vault sub trade fees" + ], + "type": "u64" + }, + { + "name": "token_0_amount", + "docs": [ + "calculate result without transfer fee" + ], + "type": "u64" + }, + { + "name": "token_1_amount", + "docs": [ + "calculate result without transfer fee" + ], + "type": "u64" + }, + { + "name": "token_0_transfer_fee", + "type": "u64" + }, + { + "name": "token_1_transfer_fee", + "type": "u64" + }, + { + "name": "change_type", + "type": "u8" + } + ] + } + }, + { + "name": "Observation", + "docs": [ + "The element of observations in ObservationState" + ], + "serialization": "bytemuckunsafe", + "repr": { + "kind": "c", + "packed": true + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "block_timestamp", + "docs": [ + "The block timestamp of the observation" + ], + "type": "u64" + }, + { + "name": "cumulative_token_0_price_x32", + "docs": [ + "the cumulative of token0 price during the duration time, Q32.32, the remaining 64 bit for overflow" + ], + "type": "u128" + }, + { + "name": "cumulative_token_1_price_x32", + "docs": [ + "the cumulative of token1 price during the duration time, Q32.32, the remaining 64 bit for overflow" + ], + "type": "u128" + } + ] + } + }, + { + "name": "ObservationState", + "serialization": "bytemuckunsafe", + "repr": { + "kind": "c", + "packed": true + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "initialized", + "docs": [ + "Whether the ObservationState is initialized" + ], + "type": "bool" + }, + { + "name": "observation_index", + "docs": [ + "the most-recently updated index of the observations array" + ], + "type": "u16" + }, + { + "name": "pool_id", + "type": "pubkey" + }, + { + "name": "observations", + "docs": [ + "observation array" + ], + "type": { + "array": [ + { + "defined": { + "name": "Observation" + } + }, + 100 + ] + } + }, + { + "name": "padding", + "docs": [ + "padding for feature update" + ], + "type": { + "array": [ + "u64", + 4 + ] + } + } + ] + } + }, + { + "name": "PoolState", + "serialization": "bytemuckunsafe", + "repr": { + "kind": "c", + "packed": true + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "amm_config", + "docs": [ + "Which config the pool belongs" + ], + "type": "pubkey" + }, + { + "name": "pool_creator", + "docs": [ + "pool creator" + ], + "type": "pubkey" + }, + { + "name": "token_0_vault", + "docs": [ + "Token A" + ], + "type": "pubkey" + }, + { + "name": "token_1_vault", + "docs": [ + "Token B" + ], + "type": "pubkey" + }, + { + "name": "lp_mint", + "docs": [ + "Pool tokens are issued when A or B tokens are deposited.", + "Pool tokens can be withdrawn back to the original A or B token." + ], + "type": "pubkey" + }, + { + "name": "token_0_mint", + "docs": [ + "Mint information for token A" + ], + "type": "pubkey" + }, + { + "name": "token_1_mint", + "docs": [ + "Mint information for token B" + ], + "type": "pubkey" + }, + { + "name": "token_0_program", + "docs": [ + "token_0 program" + ], + "type": "pubkey" + }, + { + "name": "token_1_program", + "docs": [ + "token_1 program" + ], + "type": "pubkey" + }, + { + "name": "observation_key", + "docs": [ + "observation account to store oracle data" + ], + "type": "pubkey" + }, + { + "name": "auth_bump", + "type": "u8" + }, + { + "name": "status", + "docs": [ + "Bitwise representation of the state of the pool", + "bit0, 1: disable deposit(value is 1), 0: normal", + "bit1, 1: disable withdraw(value is 2), 0: normal", + "bit2, 1: disable swap(value is 4), 0: normal" + ], + "type": "u8" + }, + { + "name": "lp_mint_decimals", + "type": "u8" + }, + { + "name": "mint_0_decimals", + "docs": [ + "mint0 and mint1 decimals" + ], + "type": "u8" + }, + { + "name": "mint_1_decimals", + "type": "u8" + }, + { + "name": "lp_supply", + "docs": [ + "True circulating supply without burns and lock ups" + ], + "type": "u64" + }, + { + "name": "protocol_fees_token_0", + "docs": [ + "The amounts of token_0 and token_1 that are owed to the liquidity provider." + ], + "type": "u64" + }, + { + "name": "protocol_fees_token_1", + "type": "u64" + }, + { + "name": "fund_fees_token_0", + "type": "u64" + }, + { + "name": "fund_fees_token_1", + "type": "u64" + }, + { + "name": "open_time", + "docs": [ + "The timestamp allowed for swap in the pool." + ], + "type": "u64" + }, + { + "name": "recent_epoch", + "docs": [ + "recent epoch" + ], + "type": "u64" + }, + { + "name": "padding", + "docs": [ + "padding for future updates" + ], + "type": { + "array": [ + "u64", + 31 + ] + } + } + ] + } + }, + { + "name": "SwapEvent", + "docs": [ + "Emitted when swap" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_id", + "type": "pubkey" + }, + { + "name": "input_vault_before", + "docs": [ + "pool vault sub trade fees" + ], + "type": "u64" + }, + { + "name": "output_vault_before", + "docs": [ + "pool vault sub trade fees" + ], + "type": "u64" + }, + { + "name": "input_amount", + "docs": [ + "calculate result without transfer fee" + ], + "type": "u64" + }, + { + "name": "output_amount", + "docs": [ + "calculate result without transfer fee" + ], + "type": "u64" + }, + { + "name": "input_transfer_fee", + "type": "u64" + }, + { + "name": "output_transfer_fee", + "type": "u64" + }, + { + "name": "base_input", + "type": "bool" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/e2e/raydium-cpmm/src/generated/accounts/amm_config.rs b/e2e/raydium-cpmm/src/generated/accounts/amm_config.rs new file mode 100644 index 0000000..6c63da7 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/accounts/amm_config.rs @@ -0,0 +1,181 @@ +//! 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 AmmConfig { + pub discriminator: [u8; 8], + /// Bump to identify PDA + pub bump: u8, + /// Status to control if new pool can be create + pub disable_create_pool: bool, + /// Config index + pub index: u16, + /// The trade fee, denominated in hundredths of a bip (10^-6) + pub trade_fee_rate: u64, + /// The protocol fee + pub protocol_fee_rate: u64, + /// The fund fee, denominated in hundredths of a bip (10^-6) + pub fund_fee_rate: u64, + /// Fee for create a new pool + pub create_pool_fee: u64, + /// Address of the protocol fee owner + pub protocol_owner: Address, + /// Address of the fund fee owner + pub fund_owner: Address, + /// padding + pub padding: [u64; 16], +} + +pub const AMM_CONFIG_DISCRIMINATOR: [u8; 8] = [218, 244, 33, 104, 203, 203, 43, 111]; + +impl AmmConfig { + pub const LEN: usize = 236; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..AMM_CONFIG_DISCRIMINATOR.len()) != Some(&AMM_CONFIG_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for AmmConfig { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_CP_SWAP_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_amm_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_amm_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_amm_config( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = AmmConfig::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_amm_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_amm_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_amm_config( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = AmmConfig::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 AmmConfig { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < AMM_CONFIG_DISCRIMINATOR.len() + || buf[..AMM_CONFIG_DISCRIMINATOR.len()] != AMM_CONFIG_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for AmmConfig {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for AmmConfig { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_CP_SWAP_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for AmmConfig {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for AmmConfig { + const DISCRIMINATOR: &[u8] = &AMM_CONFIG_DISCRIMINATOR; +} diff --git a/e2e/raydium-cpmm/src/generated/accounts/mod.rs b/e2e/raydium-cpmm/src/generated/accounts/mod.rs new file mode 100644 index 0000000..8018f52 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/accounts/mod.rs @@ -0,0 +1,14 @@ +//! 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#amm_config; +pub(crate) mod r#observation_state; +pub(crate) mod r#pool_state; + +pub use self::r#amm_config::*; +pub use self::r#observation_state::*; +pub use self::r#pool_state::*; diff --git a/e2e/raydium-cpmm/src/generated/accounts/observation_state.rs b/e2e/raydium-cpmm/src/generated/accounts/observation_state.rs new file mode 100644 index 0000000..99f63d1 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/accounts/observation_state.rs @@ -0,0 +1,173 @@ +//! 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::Observation; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ObservationState { + pub discriminator: [u8; 8], + /// Whether the ObservationState is initialized + pub initialized: bool, + /// the most-recently updated index of the observations array + pub observation_index: u16, + pub pool_id: Address, + /// observation array + pub observations: [Observation; 100], + /// padding for feature update + pub padding: [u64; 4], +} + +pub const OBSERVATION_STATE_DISCRIMINATOR: [u8; 8] = [122, 174, 197, 53, 129, 9, 165, 132]; + +impl ObservationState { + pub const LEN: usize = 4075; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..OBSERVATION_STATE_DISCRIMINATOR.len()) + != Some(&OBSERVATION_STATE_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for ObservationState { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_CP_SWAP_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_observation_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_observation_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_observation_state( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ObservationState::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_observation_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_observation_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_observation_state( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = ObservationState::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 ObservationState { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < OBSERVATION_STATE_DISCRIMINATOR.len() + || buf[..OBSERVATION_STATE_DISCRIMINATOR.len()] != OBSERVATION_STATE_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for ObservationState {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for ObservationState { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_CP_SWAP_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for ObservationState {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for ObservationState { + const DISCRIMINATOR: &[u8] = &OBSERVATION_STATE_DISCRIMINATOR; +} diff --git a/e2e/raydium-cpmm/src/generated/accounts/pool_state.rs b/e2e/raydium-cpmm/src/generated/accounts/pool_state.rs new file mode 100644 index 0000000..768d44e --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/accounts/pool_state.rs @@ -0,0 +1,205 @@ +//! 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 PoolState { + pub discriminator: [u8; 8], + /// Which config the pool belongs + pub amm_config: Address, + /// pool creator + pub pool_creator: Address, + /// Token A + pub token0_vault: Address, + /// Token B + pub token1_vault: Address, + /// Pool tokens are issued when A or B tokens are deposited. + /// Pool tokens can be withdrawn back to the original A or B token. + pub lp_mint: Address, + /// Mint information for token A + pub token0_mint: Address, + /// Mint information for token B + pub token1_mint: Address, + /// token_0 program + pub token0_program: Address, + /// token_1 program + pub token1_program: Address, + /// observation account to store oracle data + pub observation_key: Address, + pub auth_bump: u8, + /// Bitwise representation of the state of the pool + /// bit0, 1: disable deposit(value is 1), 0: normal + /// bit1, 1: disable withdraw(value is 2), 0: normal + /// bit2, 1: disable swap(value is 4), 0: normal + pub status: u8, + pub lp_mint_decimals: u8, + /// mint0 and mint1 decimals + pub mint0_decimals: u8, + pub mint1_decimals: u8, + /// True circulating supply without burns and lock ups + pub lp_supply: u64, + /// The amounts of token_0 and token_1 that are owed to the liquidity provider. + pub protocol_fees_token0: u64, + pub protocol_fees_token1: u64, + pub fund_fees_token0: u64, + pub fund_fees_token1: u64, + /// The timestamp allowed for swap in the pool. + pub open_time: u64, + /// recent epoch + pub recent_epoch: u64, + /// padding for future updates + pub padding: [u64; 31], +} + +pub const POOL_STATE_DISCRIMINATOR: [u8; 8] = [247, 237, 227, 245, 215, 195, 222, 70]; + +impl PoolState { + pub const LEN: usize = 637; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..POOL_STATE_DISCRIMINATOR.len()) != Some(&POOL_STATE_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for PoolState { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_CP_SWAP_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_pool_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_pool_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_pool_state( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PoolState::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_pool_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_pool_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_pool_state( + rpc: &solana_rpc_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::RAYDIUM_CP_SWAP_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PoolState::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 PoolState { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < POOL_STATE_DISCRIMINATOR.len() + || buf[..POOL_STATE_DISCRIMINATOR.len()] != POOL_STATE_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for PoolState {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for PoolState { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_CP_SWAP_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for PoolState {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for PoolState { + const DISCRIMINATOR: &[u8] = &POOL_STATE_DISCRIMINATOR; +} diff --git a/e2e/raydium-cpmm/src/generated/errors/mod.rs b/e2e/raydium-cpmm/src/generated/errors/mod.rs new file mode 100644 index 0000000..164fee8 --- /dev/null +++ b/e2e/raydium-cpmm/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 raydium_cp_swap; + +pub use self::raydium_cp_swap::RaydiumCpSwapError; diff --git a/e2e/raydium-cpmm/src/generated/errors/raydium_cp_swap.rs b/e2e/raydium-cpmm/src/generated/errors/raydium_cp_swap.rs new file mode 100644 index 0000000..33f3db2 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/errors/raydium_cp_swap.rs @@ -0,0 +1,52 @@ +//! 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 RaydiumCpSwapError { + /// 6000 - Not approved + #[error("Not approved")] + NotApproved = 0x1770, + /// 6001 - Input account owner is not the program address + #[error("Input account owner is not the program address")] + InvalidOwner = 0x1771, + /// 6002 - Input token account empty + #[error("Input token account empty")] + EmptySupply = 0x1772, + /// 6003 - InvalidInput + #[error("InvalidInput")] + InvalidInput = 0x1773, + /// 6004 - Address of the provided lp token mint is incorrect + #[error("Address of the provided lp token mint is incorrect")] + IncorrectLpMint = 0x1774, + /// 6005 - Exceeds desired slippage limit + #[error("Exceeds desired slippage limit")] + ExceededSlippage = 0x1775, + /// 6006 - Given pool token amount results in zero trading tokens + #[error("Given pool token amount results in zero trading tokens")] + ZeroTradingTokens = 0x1776, + /// 6007 - Not support token_2022 mint extension + #[error("Not support token_2022 mint extension")] + NotSupportMint = 0x1777, + /// 6008 - invaild vault + #[error("invaild vault")] + InvalidVault = 0x1778, + /// 6009 - Init lp amount is too less(Because 100 amount lp will be locked) + #[error("Init lp amount is too less(Because 100 amount lp will be locked)")] + InitLpAmountTooLess = 0x1779, + /// 6010 - TransferFee calculate not match + #[error("TransferFee calculate not match")] + TransferFeeCalculateNotMatch = 0x177A, +} + +impl From for solana_program_error::ProgramError { + fn from(e: RaydiumCpSwapError) -> Self { + solana_program_error::ProgramError::Custom(e as u32) + } +} diff --git a/e2e/raydium-cpmm/src/generated/events/lp_change_event.rs b/e2e/raydium-cpmm/src/generated/events/lp_change_event.rs new file mode 100644 index 0000000..f67d272 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/events/lp_change_event.rs @@ -0,0 +1,45 @@ +//! 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 LpChangeEvent { + pub pool_id: Address, + pub lp_amount_before: u64, + /// pool vault sub trade fees + pub token0_vault_before: u64, + /// pool vault sub trade fees + pub token1_vault_before: u64, + /// calculate result without transfer fee + pub token0_amount: u64, + /// calculate result without transfer fee + pub token1_amount: u64, + pub token0_transfer_fee: u64, + pub token1_transfer_fee: u64, + pub change_type: u8, +} + +pub const LP_CHANGE_EVENT_DISCRIMINATOR: [u8; 8] = [121, 163, 205, 201, 57, 218, 117, 60]; + +impl LpChangeEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..LP_CHANGE_EVENT_DISCRIMINATOR.len()) + != Some(&LP_CHANGE_EVENT_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + let mut data = &data[8..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-cpmm/src/generated/events/mod.rs b/e2e/raydium-cpmm/src/generated/events/mod.rs new file mode 100644 index 0000000..d36c7e6 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/events/mod.rs @@ -0,0 +1,14 @@ +//! 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#lp_change_event; +pub(crate) mod r#raydium_cp_swap_events; +pub(crate) mod r#swap_event; + +pub use self::r#lp_change_event::*; +pub use self::r#raydium_cp_swap_events::*; +pub use self::r#swap_event::*; diff --git a/e2e/raydium-cpmm/src/generated/events/raydium_cp_swap_events.rs b/e2e/raydium-cpmm/src/generated/events/raydium_cp_swap_events.rs new file mode 100644 index 0000000..209e1e4 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/events/raydium_cp_swap_events.rs @@ -0,0 +1,54 @@ +//! 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::events::LpChangeEvent; +use crate::generated::events::SwapEvent; +use crate::generated::events::LP_CHANGE_EVENT_DISCRIMINATOR; +use crate::generated::events::SWAP_EVENT_DISCRIMINATOR; +use borsh::BorshDeserialize; + +/// Event kinds for the `raydium_cp_swap` program. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RaydiumCpSwapEventKind { + LpChangeEvent, + SwapEvent, +} + +/// Identifies a `raydium_cp_swap` event from the provided data. +pub fn identify_raydium_cp_swap_event(data: &[u8]) -> Option { + if data.get(..LP_CHANGE_EVENT_DISCRIMINATOR.len()) == Some(&LP_CHANGE_EVENT_DISCRIMINATOR[..]) { + return Some(RaydiumCpSwapEventKind::LpChangeEvent); + } + if data.get(..SWAP_EVENT_DISCRIMINATOR.len()) == Some(&SWAP_EVENT_DISCRIMINATOR[..]) { + return Some(RaydiumCpSwapEventKind::SwapEvent); + } + None +} + +/// Parsed event variants for the `raydium_cp_swap` program. +#[derive(Clone, Debug, PartialEq)] +pub enum RaydiumCpSwapEvent { + LpChangeEvent(LpChangeEvent), + SwapEvent(SwapEvent), +} + +/// Tries to parse a `raydium_cp_swap` event from the provided data. +pub fn try_parse_raydium_cp_swap_event( + data: &[u8], +) -> Option> { + let event_kind = identify_raydium_cp_swap_event(data)?; + Some(match event_kind { + RaydiumCpSwapEventKind::LpChangeEvent => { + let mut data = &data[8..]; + LpChangeEvent::deserialize(&mut data).map(RaydiumCpSwapEvent::LpChangeEvent) + } + RaydiumCpSwapEventKind::SwapEvent => { + let mut data = &data[8..]; + SwapEvent::deserialize(&mut data).map(RaydiumCpSwapEvent::SwapEvent) + } + }) +} diff --git a/e2e/raydium-cpmm/src/generated/events/swap_event.rs b/e2e/raydium-cpmm/src/generated/events/swap_event.rs new file mode 100644 index 0000000..de94e5d --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/events/swap_event.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SwapEvent { + pub pool_id: Address, + /// pool vault sub trade fees + pub input_vault_before: u64, + /// pool vault sub trade fees + pub output_vault_before: u64, + /// calculate result without transfer fee + pub input_amount: u64, + /// calculate result without transfer fee + pub output_amount: u64, + pub input_transfer_fee: u64, + pub output_transfer_fee: u64, + pub base_input: bool, +} + +pub const SWAP_EVENT_DISCRIMINATOR: [u8; 8] = [64, 198, 205, 232, 38, 8, 113, 226]; + +impl SwapEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..SWAP_EVENT_DISCRIMINATOR.len()) != Some(&SWAP_EVENT_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + let mut data = &data[8..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/collect_fund_fee.rs b/e2e/raydium-cpmm/src/generated/instructions/collect_fund_fee.rs new file mode 100644 index 0000000..e03e4ab --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/collect_fund_fee.rs @@ -0,0 +1,628 @@ +//! 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 COLLECT_FUND_FEE_DISCRIMINATOR: [u8; 8] = [167, 138, 78, 149, 223, 194, 6, 126]; + +/// Accounts. +#[derive(Debug)] +pub struct CollectFundFee { + /// Only admin or fund_owner can collect fee now + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + /// Pool state stores accumulated protocol fee amount + pub pool_state: solana_address::Address, + /// Amm config account stores fund_owner + pub amm_config: solana_address::Address, + /// The address that holds pool tokens for token_0 + pub token0_vault: solana_address::Address, + /// The address that holds pool tokens for token_1 + pub token1_vault: solana_address::Address, + /// The mint of token_0 vault + pub vault0_mint: solana_address::Address, + /// The mint of token_1 vault + pub vault1_mint: solana_address::Address, + /// The address that receives the collected token_0 fund fees + pub recipient_token0_account: solana_address::Address, + /// The address that receives the collected token_1 fund fees + pub recipient_token1_account: solana_address::Address, + /// The SPL program to perform token transfers + pub token_program: solana_address::Address, + /// The SPL program 2022 to perform token transfers + pub token_program2022: solana_address::Address, +} + +impl CollectFundFee { + pub fn instruction( + &self, + args: CollectFundFeeInstructionArgs, + ) -> 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: CollectFundFeeInstructionArgs, + 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.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault0_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault1_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token0_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token1_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program2022, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CollectFundFeeInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectFundFeeInstructionData { + discriminator: [u8; 8], +} + +impl CollectFundFeeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [167, 138, 78, 149, 223, 194, 6, 126], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CollectFundFeeInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectFundFeeInstructionArgs { + pub amount0_requested: u64, + pub amount1_requested: u64, +} + +impl CollectFundFeeInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CollectFundFee`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[]` amm_config +/// 4. `[writable]` token0_vault +/// 5. `[writable]` token1_vault +/// 6. `[]` vault0_mint +/// 7. `[]` vault1_mint +/// 8. `[writable]` recipient_token0_account +/// 9. `[writable]` recipient_token1_account +/// 10. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 11. `[optional]` token_program2022 (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) +#[derive(Clone, Debug)] +pub struct CollectFundFeeBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + amm_config: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + recipient_token0_account: solana_address::Address, + recipient_token1_account: solana_address::Address, + token_program: Option, + token_program2022: Option, + amount0_requested: u64, + amount1_requested: u64, + __remaining_accounts: Vec, +} + +impl CollectFundFeeBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + amm_config: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + recipient_token0_account: solana_address::Address, + recipient_token1_account: solana_address::Address, + amount0_requested: u64, + amount1_requested: u64, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program: None, + token_program2022: None, + amount0_requested, + amount1_requested, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// The SPL program to perform token transfers + #[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 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb']` + /// The SPL program 2022 to perform token transfers + #[inline(always)] + pub fn token_program2022(&mut self, token_program2022: solana_address::Address) -> &mut Self { + self.token_program2022 = Some(token_program2022); + 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 authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let amm_config = self.amm_config; + let token0_vault = self.token0_vault; + let token1_vault = self.token1_vault; + let vault0_mint = self.vault0_mint; + let vault1_mint = self.vault1_mint; + let recipient_token0_account = self.recipient_token0_account; + let recipient_token1_account = self.recipient_token1_account; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let token_program2022 = self.token_program2022.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let accounts = CollectFundFee { + owner, + authority, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program, + token_program2022, + }; + let args = CollectFundFeeInstructionArgs { + amount0_requested: self.amount0_requested.clone(), + amount1_requested: self.amount1_requested.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `collect_fund_fee` CPI accounts. +pub struct CollectFundFeeCpiAccounts<'a, 'b> { + /// Only admin or fund_owner can collect fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account stores fund_owner + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_0 fund fees + pub recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_1 fund fees + pub recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program to perform token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program 2022 to perform token transfers + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, +} + +/// `collect_fund_fee` CPI instruction. +pub struct CollectFundFeeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only admin or fund_owner can collect fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account stores fund_owner + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_0 fund fees + pub recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_1 fund fees + pub recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program to perform token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program 2022 to perform token transfers + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CollectFundFeeInstructionArgs, +} + +impl<'a, 'b> CollectFundFeeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CollectFundFeeCpiAccounts<'a, 'b>, + args: CollectFundFeeInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + amm_config: accounts.amm_config, + token0_vault: accounts.token0_vault, + token1_vault: accounts.token1_vault, + vault0_mint: accounts.vault0_mint, + vault1_mint: accounts.vault1_mint, + recipient_token0_account: accounts.recipient_token0_account, + recipient_token1_account: accounts.recipient_token1_account, + token_program: accounts.token_program, + token_program2022: accounts.token_program2022, + __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.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault0_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault1_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token0_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token1_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program2022.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 = CollectFundFeeInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(13 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.token0_vault.clone()); + account_infos.push(self.token1_vault.clone()); + account_infos.push(self.vault0_mint.clone()); + account_infos.push(self.vault1_mint.clone()); + account_infos.push(self.recipient_token0_account.clone()); + account_infos.push(self.recipient_token1_account.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.token_program2022.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 `CollectFundFee` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[]` amm_config +/// 4. `[writable]` token0_vault +/// 5. `[writable]` token1_vault +/// 6. `[]` vault0_mint +/// 7. `[]` vault1_mint +/// 8. `[writable]` recipient_token0_account +/// 9. `[writable]` recipient_token1_account +/// 10. `[]` token_program +/// 11. `[]` token_program2022 +#[derive(Clone, Debug)] +pub struct CollectFundFeeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CollectFundFeeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + amount0_requested: u64, + amount1_requested: u64, + ) -> Self { + let instruction = Box::new(CollectFundFeeCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program, + token_program2022, + amount0_requested, + amount1_requested, + __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 = CollectFundFeeInstructionArgs { + amount0_requested: self.instruction.amount0_requested.clone(), + amount1_requested: self.instruction.amount1_requested.clone(), + }; + let instruction = CollectFundFeeCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + amm_config: self.instruction.amm_config, + token0_vault: self.instruction.token0_vault, + token1_vault: self.instruction.token1_vault, + vault0_mint: self.instruction.vault0_mint, + vault1_mint: self.instruction.vault1_mint, + recipient_token0_account: self.instruction.recipient_token0_account, + recipient_token1_account: self.instruction.recipient_token1_account, + token_program: self.instruction.token_program, + token_program2022: self.instruction.token_program2022, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CollectFundFeeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + amount0_requested: u64, + amount1_requested: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/collect_protocol_fee.rs b/e2e/raydium-cpmm/src/generated/instructions/collect_protocol_fee.rs new file mode 100644 index 0000000..fd22fa8 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/collect_protocol_fee.rs @@ -0,0 +1,632 @@ +//! 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 COLLECT_PROTOCOL_FEE_DISCRIMINATOR: [u8; 8] = [136, 136, 252, 221, 194, 66, 126, 89]; + +/// Accounts. +#[derive(Debug)] +pub struct CollectProtocolFee { + /// Only admin or owner can collect fee now + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + /// Pool state stores accumulated protocol fee amount + pub pool_state: solana_address::Address, + /// Amm config account stores owner + pub amm_config: solana_address::Address, + /// The address that holds pool tokens for token_0 + pub token0_vault: solana_address::Address, + /// The address that holds pool tokens for token_1 + pub token1_vault: solana_address::Address, + /// The mint of token_0 vault + pub vault0_mint: solana_address::Address, + /// The mint of token_1 vault + pub vault1_mint: solana_address::Address, + /// The address that receives the collected token_0 protocol fees + pub recipient_token0_account: solana_address::Address, + /// The address that receives the collected token_1 protocol fees + pub recipient_token1_account: solana_address::Address, + /// The SPL program to perform token transfers + pub token_program: solana_address::Address, + /// The SPL program 2022 to perform token transfers + pub token_program2022: solana_address::Address, +} + +impl CollectProtocolFee { + pub fn instruction( + &self, + args: CollectProtocolFeeInstructionArgs, + ) -> 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: CollectProtocolFeeInstructionArgs, + 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.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault0_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault1_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token0_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token1_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program2022, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CollectProtocolFeeInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectProtocolFeeInstructionData { + discriminator: [u8; 8], +} + +impl CollectProtocolFeeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [136, 136, 252, 221, 194, 66, 126, 89], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CollectProtocolFeeInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectProtocolFeeInstructionArgs { + pub amount0_requested: u64, + pub amount1_requested: u64, +} + +impl CollectProtocolFeeInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CollectProtocolFee`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[]` amm_config +/// 4. `[writable]` token0_vault +/// 5. `[writable]` token1_vault +/// 6. `[]` vault0_mint +/// 7. `[]` vault1_mint +/// 8. `[writable]` recipient_token0_account +/// 9. `[writable]` recipient_token1_account +/// 10. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 11. `[optional]` token_program2022 (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) +#[derive(Clone, Debug)] +pub struct CollectProtocolFeeBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + amm_config: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + recipient_token0_account: solana_address::Address, + recipient_token1_account: solana_address::Address, + token_program: Option, + token_program2022: Option, + amount0_requested: u64, + amount1_requested: u64, + __remaining_accounts: Vec, +} + +impl CollectProtocolFeeBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + amm_config: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + recipient_token0_account: solana_address::Address, + recipient_token1_account: solana_address::Address, + amount0_requested: u64, + amount1_requested: u64, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program: None, + token_program2022: None, + amount0_requested, + amount1_requested, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// The SPL program to perform token transfers + #[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 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb']` + /// The SPL program 2022 to perform token transfers + #[inline(always)] + pub fn token_program2022(&mut self, token_program2022: solana_address::Address) -> &mut Self { + self.token_program2022 = Some(token_program2022); + 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 authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let amm_config = self.amm_config; + let token0_vault = self.token0_vault; + let token1_vault = self.token1_vault; + let vault0_mint = self.vault0_mint; + let vault1_mint = self.vault1_mint; + let recipient_token0_account = self.recipient_token0_account; + let recipient_token1_account = self.recipient_token1_account; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let token_program2022 = self.token_program2022.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let accounts = CollectProtocolFee { + owner, + authority, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program, + token_program2022, + }; + let args = CollectProtocolFeeInstructionArgs { + amount0_requested: self.amount0_requested.clone(), + amount1_requested: self.amount1_requested.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `collect_protocol_fee` CPI accounts. +pub struct CollectProtocolFeeCpiAccounts<'a, 'b> { + /// Only admin or owner can collect fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account stores owner + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_0 protocol fees + pub recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_1 protocol fees + pub recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program to perform token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program 2022 to perform token transfers + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, +} + +/// `collect_protocol_fee` CPI instruction. +pub struct CollectProtocolFeeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only admin or owner can collect fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account stores owner + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_0 protocol fees + pub recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected token_1 protocol fees + pub recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program to perform token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// The SPL program 2022 to perform token transfers + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CollectProtocolFeeInstructionArgs, +} + +impl<'a, 'b> CollectProtocolFeeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CollectProtocolFeeCpiAccounts<'a, 'b>, + args: CollectProtocolFeeInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + amm_config: accounts.amm_config, + token0_vault: accounts.token0_vault, + token1_vault: accounts.token1_vault, + vault0_mint: accounts.vault0_mint, + vault1_mint: accounts.vault1_mint, + recipient_token0_account: accounts.recipient_token0_account, + recipient_token1_account: accounts.recipient_token1_account, + token_program: accounts.token_program, + token_program2022: accounts.token_program2022, + __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.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault0_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault1_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token0_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token1_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program2022.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 = CollectProtocolFeeInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(13 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.token0_vault.clone()); + account_infos.push(self.token1_vault.clone()); + account_infos.push(self.vault0_mint.clone()); + account_infos.push(self.vault1_mint.clone()); + account_infos.push(self.recipient_token0_account.clone()); + account_infos.push(self.recipient_token1_account.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.token_program2022.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 `CollectProtocolFee` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[]` amm_config +/// 4. `[writable]` token0_vault +/// 5. `[writable]` token1_vault +/// 6. `[]` vault0_mint +/// 7. `[]` vault1_mint +/// 8. `[writable]` recipient_token0_account +/// 9. `[writable]` recipient_token1_account +/// 10. `[]` token_program +/// 11. `[]` token_program2022 +#[derive(Clone, Debug)] +pub struct CollectProtocolFeeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CollectProtocolFeeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + amount0_requested: u64, + amount1_requested: u64, + ) -> Self { + let instruction = Box::new(CollectProtocolFeeCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + amm_config, + token0_vault, + token1_vault, + vault0_mint, + vault1_mint, + recipient_token0_account, + recipient_token1_account, + token_program, + token_program2022, + amount0_requested, + amount1_requested, + __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 = CollectProtocolFeeInstructionArgs { + amount0_requested: self.instruction.amount0_requested.clone(), + amount1_requested: self.instruction.amount1_requested.clone(), + }; + let instruction = CollectProtocolFeeCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + amm_config: self.instruction.amm_config, + token0_vault: self.instruction.token0_vault, + token1_vault: self.instruction.token1_vault, + vault0_mint: self.instruction.vault0_mint, + vault1_mint: self.instruction.vault1_mint, + recipient_token0_account: self.instruction.recipient_token0_account, + recipient_token1_account: self.instruction.recipient_token1_account, + token_program: self.instruction.token_program, + token_program2022: self.instruction.token_program2022, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CollectProtocolFeeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token0_account: &'b solana_account_info::AccountInfo<'a>, + recipient_token1_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + amount0_requested: u64, + amount1_requested: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/create_amm_config.rs b/e2e/raydium-cpmm/src/generated/instructions/create_amm_config.rs new file mode 100644 index 0000000..87b6064 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/create_amm_config.rs @@ -0,0 +1,409 @@ +//! 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_AMM_CONFIG_DISCRIMINATOR: [u8; 8] = [137, 52, 237, 212, 215, 117, 108, 104]; + +/// Accounts. +#[derive(Debug)] +pub struct CreateAmmConfig { + /// Address to be set as protocol owner. + pub owner: solana_address::Address, + /// Initialize config state account to store protocol owner address and fee rates. + pub amm_config: solana_address::Address, + + pub system_program: solana_address::Address, +} + +impl CreateAmmConfig { + pub fn instruction( + &self, + args: CreateAmmConfigInstructionArgs, + ) -> 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: CreateAmmConfigInstructionArgs, + 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.owner, true)); + accounts.push(solana_instruction::AccountMeta::new(self.amm_config, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateAmmConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateAmmConfigInstructionData { + discriminator: [u8; 8], +} + +impl CreateAmmConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [137, 52, 237, 212, 215, 117, 108, 104], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateAmmConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateAmmConfigInstructionArgs { + pub index: u16, + pub trade_fee_rate: u64, + pub protocol_fee_rate: u64, + pub fund_fee_rate: u64, + pub create_pool_fee: u64, +} + +impl CreateAmmConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateAmmConfig`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer, optional]` owner (default to `GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ`) +/// 1. `[writable, optional]` amm_config (default to PDA derived from 'ammConfig') +/// 2. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreateAmmConfigBuilder { + owner: Option, + amm_config: Option, + system_program: Option, + index: u16, + trade_fee_rate: u64, + protocol_fee_rate: u64, + fund_fee_rate: u64, + create_pool_fee: u64, + __remaining_accounts: Vec, +} + +impl CreateAmmConfigBuilder { + pub fn new( + index: u16, + trade_fee_rate: u64, + protocol_fee_rate: u64, + fund_fee_rate: u64, + create_pool_fee: u64, + ) -> Self { + Self { + owner: None, + amm_config: None, + system_program: None, + index, + trade_fee_rate, + protocol_fee_rate, + fund_fee_rate, + create_pool_fee, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ']` + /// Address to be set as protocol owner. + #[inline(always)] + pub fn owner(&mut self, owner: solana_address::Address) -> &mut Self { + self.owner = Some(owner); + self + } + /// `[optional account, default to PDA derived from 'ammConfig']` + /// Initialize config state account to store protocol owner address and fee rates. + #[inline(always)] + pub fn amm_config(&mut self, amm_config: solana_address::Address) -> &mut Self { + self.amm_config = Some(amm_config); + 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 owner = self.owner.unwrap_or(solana_address::address!( + "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + )); + let amm_config = self + .amm_config + .unwrap_or_else(|| crate::pdas::find_amm_config_pda(self.index.clone()).0); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreateAmmConfig { + owner, + amm_config, + system_program, + }; + let args = CreateAmmConfigInstructionArgs { + index: self.index.clone(), + trade_fee_rate: self.trade_fee_rate.clone(), + protocol_fee_rate: self.protocol_fee_rate.clone(), + fund_fee_rate: self.fund_fee_rate.clone(), + create_pool_fee: self.create_pool_fee.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_amm_config` CPI accounts. +pub struct CreateAmmConfigCpiAccounts<'a, 'b> { + /// Address to be set as protocol owner. + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Initialize config state account to store protocol owner address and fee rates. + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_amm_config` CPI instruction. +pub struct CreateAmmConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Address to be set as protocol owner. + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Initialize config state account to store protocol owner address and fee rates. + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CreateAmmConfigInstructionArgs, +} + +impl<'a, 'b> CreateAmmConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateAmmConfigCpiAccounts<'a, 'b>, + args: CreateAmmConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + amm_config: accounts.amm_config, + 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(3 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(*self.owner.key, true)); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_config.key, + false, + )); + 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 = CreateAmmConfigInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.amm_config.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 `CreateAmmConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` owner +/// 1. `[writable]` amm_config +/// 2. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreateAmmConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateAmmConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + index: u16, + trade_fee_rate: u64, + protocol_fee_rate: u64, + fund_fee_rate: u64, + create_pool_fee: u64, + ) -> Self { + let instruction = Box::new(CreateAmmConfigCpiBuilderInstruction { + __program, + owner, + amm_config, + system_program, + index, + trade_fee_rate, + protocol_fee_rate, + fund_fee_rate, + create_pool_fee, + __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 = CreateAmmConfigInstructionArgs { + index: self.instruction.index.clone(), + trade_fee_rate: self.instruction.trade_fee_rate.clone(), + protocol_fee_rate: self.instruction.protocol_fee_rate.clone(), + fund_fee_rate: self.instruction.fund_fee_rate.clone(), + create_pool_fee: self.instruction.create_pool_fee.clone(), + }; + let instruction = CreateAmmConfigCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + amm_config: self.instruction.amm_config, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateAmmConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + index: u16, + trade_fee_rate: u64, + protocol_fee_rate: u64, + fund_fee_rate: u64, + create_pool_fee: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/deposit.rs b/e2e/raydium-cpmm/src/generated/instructions/deposit.rs new file mode 100644 index 0000000..bfbba46 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/deposit.rs @@ -0,0 +1,658 @@ +//! 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_DISCRIMINATOR: [u8; 8] = [242, 35, 198, 137, 82, 225, 242, 182]; + +/// Accounts. +#[derive(Debug)] +pub struct Deposit { + /// Pays to mint the position + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + + pub pool_state: solana_address::Address, + /// Owner lp token account + pub owner_lp_token: solana_address::Address, + /// The payer's token account for token_0 + pub token0_account: solana_address::Address, + /// The payer's token account for token_1 + pub token1_account: solana_address::Address, + /// The address that holds pool tokens for token_0 + pub token0_vault: solana_address::Address, + /// The address that holds pool tokens for token_1 + pub token1_vault: solana_address::Address, + /// token Program + pub token_program: solana_address::Address, + /// Token program 2022 + pub token_program2022: solana_address::Address, + /// The mint of token_0 vault + pub vault0_mint: solana_address::Address, + /// The mint of token_1 vault + pub vault1_mint: solana_address::Address, + /// Lp token mint + pub lp_mint: solana_address::Address, +} + +impl Deposit { + pub fn instruction(&self, args: DepositInstructionArgs) -> 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: DepositInstructionArgs, + 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.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.owner_lp_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program2022, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault0_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault1_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.lp_mint, false)); + accounts.extend_from_slice(remaining_accounts); + let mut data = DepositInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct DepositInstructionData { + discriminator: [u8; 8], +} + +impl DepositInstructionData { + pub fn new() -> Self { + Self { + discriminator: [242, 35, 198, 137, 82, 225, 242, 182], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for DepositInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct DepositInstructionArgs { + pub lp_token_amount: u64, + pub maximum_token0_amount: u64, + pub maximum_token1_amount: u64, +} + +impl DepositInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `Deposit`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[writable]` owner_lp_token +/// 4. `[writable]` token0_account +/// 5. `[writable]` token1_account +/// 6. `[writable]` token0_vault +/// 7. `[writable]` token1_vault +/// 8. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 9. `[optional]` token_program2022 (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) +/// 10. `[]` vault0_mint +/// 11. `[]` vault1_mint +/// 12. `[writable]` lp_mint +#[derive(Clone, Debug)] +pub struct DepositBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + owner_lp_token: solana_address::Address, + token0_account: solana_address::Address, + token1_account: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + token_program: Option, + token_program2022: Option, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + lp_mint: solana_address::Address, + lp_token_amount: u64, + maximum_token0_amount: u64, + maximum_token1_amount: u64, + __remaining_accounts: Vec, +} + +impl DepositBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + owner_lp_token: solana_address::Address, + token0_account: solana_address::Address, + token1_account: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + lp_mint: solana_address::Address, + lp_token_amount: u64, + maximum_token0_amount: u64, + maximum_token1_amount: u64, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program: None, + token_program2022: None, + vault0_mint, + vault1_mint, + lp_mint, + lp_token_amount, + maximum_token0_amount, + maximum_token1_amount, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// 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 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb']` + /// Token program 2022 + #[inline(always)] + pub fn token_program2022(&mut self, token_program2022: solana_address::Address) -> &mut Self { + self.token_program2022 = Some(token_program2022); + 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 authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let owner_lp_token = self.owner_lp_token; + let token0_account = self.token0_account; + let token1_account = self.token1_account; + let token0_vault = self.token0_vault; + let token1_vault = self.token1_vault; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let token_program2022 = self.token_program2022.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let vault0_mint = self.vault0_mint; + let vault1_mint = self.vault1_mint; + let lp_mint = self.lp_mint; + let accounts = Deposit { + owner, + authority, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program, + token_program2022, + vault0_mint, + vault1_mint, + lp_mint, + }; + let args = DepositInstructionArgs { + lp_token_amount: self.lp_token_amount.clone(), + maximum_token0_amount: self.maximum_token0_amount.clone(), + maximum_token1_amount: self.maximum_token1_amount.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `deposit` CPI accounts. +pub struct DepositCpiAccounts<'a, 'b> { + /// Pays to mint the position + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Owner lp token account + pub owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// The payer's token account for token_0 + pub token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The payer's token account for token_1 + pub token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Token program 2022 + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// Lp token mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, +} + +/// `deposit` CPI instruction. +pub struct DepositCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Pays to mint the position + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Owner lp token account + pub owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// The payer's token account for token_0 + pub token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The payer's token account for token_1 + pub token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Token program 2022 + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// Lp token mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: DepositInstructionArgs, +} + +impl<'a, 'b> DepositCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: DepositCpiAccounts<'a, 'b>, + args: DepositInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + owner_lp_token: accounts.owner_lp_token, + token0_account: accounts.token0_account, + token1_account: accounts.token1_account, + token0_vault: accounts.token0_vault, + token1_vault: accounts.token1_vault, + token_program: accounts.token_program, + token_program2022: accounts.token_program2022, + vault0_mint: accounts.vault0_mint, + vault1_mint: accounts.vault1_mint, + lp_mint: accounts.lp_mint, + __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.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.owner_lp_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program2022.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault0_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault1_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.lp_mint.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 = DepositInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(14 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.owner_lp_token.clone()); + account_infos.push(self.token0_account.clone()); + account_infos.push(self.token1_account.clone()); + account_infos.push(self.token0_vault.clone()); + account_infos.push(self.token1_vault.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.token_program2022.clone()); + account_infos.push(self.vault0_mint.clone()); + account_infos.push(self.vault1_mint.clone()); + account_infos.push(self.lp_mint.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 `Deposit` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[writable]` owner_lp_token +/// 4. `[writable]` token0_account +/// 5. `[writable]` token1_account +/// 6. `[writable]` token0_vault +/// 7. `[writable]` token1_vault +/// 8. `[]` token_program +/// 9. `[]` token_program2022 +/// 10. `[]` vault0_mint +/// 11. `[]` vault1_mint +/// 12. `[writable]` lp_mint +#[derive(Clone, Debug)] +pub struct DepositCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> DepositCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_account: &'b solana_account_info::AccountInfo<'a>, + token1_account: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + lp_token_amount: u64, + maximum_token0_amount: u64, + maximum_token1_amount: u64, + ) -> Self { + let instruction = Box::new(DepositCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program, + token_program2022, + vault0_mint, + vault1_mint, + lp_mint, + lp_token_amount, + maximum_token0_amount, + maximum_token1_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 = DepositInstructionArgs { + lp_token_amount: self.instruction.lp_token_amount.clone(), + maximum_token0_amount: self.instruction.maximum_token0_amount.clone(), + maximum_token1_amount: self.instruction.maximum_token1_amount.clone(), + }; + let instruction = DepositCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + owner_lp_token: self.instruction.owner_lp_token, + token0_account: self.instruction.token0_account, + token1_account: self.instruction.token1_account, + token0_vault: self.instruction.token0_vault, + token1_vault: self.instruction.token1_vault, + token_program: self.instruction.token_program, + token_program2022: self.instruction.token_program2022, + vault0_mint: self.instruction.vault0_mint, + vault1_mint: self.instruction.vault1_mint, + lp_mint: self.instruction.lp_mint, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct DepositCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_account: &'b solana_account_info::AccountInfo<'a>, + token1_account: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + lp_token_amount: u64, + maximum_token0_amount: u64, + maximum_token1_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/raydium-cpmm/src/generated/instructions/initialize.rs b/e2e/raydium-cpmm/src/generated/instructions/initialize.rs new file mode 100644 index 0000000..6eb5c78 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/initialize.rs @@ -0,0 +1,948 @@ +//! 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 INITIALIZE_DISCRIMINATOR: [u8; 8] = [175, 175, 109, 31, 13, 152, 155, 237]; + +/// Accounts. +#[derive(Debug)] +pub struct Initialize { + /// Address paying to create the pool. Can be anyone + pub creator: solana_address::Address, + /// Which config the pool belongs to. + pub amm_config: solana_address::Address, + /// pool vault and lp mint authority + pub authority: solana_address::Address, + /// PDA account: + /// seeds = [ + /// POOL_SEED.as_bytes(), + /// amm_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// + /// Or random account: must be signed by cli + pub pool_state: solana_address::Address, + /// Token_0 mint, the key must smaller than token_1 mint. + pub token0_mint: solana_address::Address, + /// Token_1 mint, the key must grater then token_0 mint. + pub token1_mint: solana_address::Address, + /// pool lp mint + pub lp_mint: solana_address::Address, + /// payer token0 account + pub creator_token0: solana_address::Address, + /// creator token1 account + pub creator_token1: solana_address::Address, + /// creator lp token account + pub creator_lp_token: solana_address::Address, + + pub token0_vault: solana_address::Address, + + pub token1_vault: solana_address::Address, + /// create pool fee account + pub create_pool_fee: solana_address::Address, + /// an account to store oracle observations + pub observation_state: solana_address::Address, + /// Program to create mint account and mint tokens + pub token_program: solana_address::Address, + /// Spl token program or token program 2022 + pub token0_program: solana_address::Address, + /// Spl token program or token program 2022 + pub token1_program: solana_address::Address, + /// Program to create an ATA for receiving position NFT + pub associated_token_program: solana_address::Address, + /// To create a new program account + pub system_program: solana_address::Address, + /// Sysvar for program account + pub rent: solana_address::Address, +} + +impl Initialize { + pub fn instruction(&self, args: InitializeInstructionArgs) -> 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: InitializeInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(20 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.creator, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token0_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token1_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.lp_mint, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.creator_token0, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.creator_token1, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.creator_lp_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.create_pool_fee, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.observation_state, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token0_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token1_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.associated_token_program, + false, + )); + 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 = InitializeInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InitializeInstructionData { + discriminator: [u8; 8], +} + +impl InitializeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [175, 175, 109, 31, 13, 152, 155, 237], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for InitializeInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InitializeInstructionArgs { + pub init_amount0: u64, + pub init_amount1: u64, + pub open_time: u64, +} + +impl InitializeInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `Initialize`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` creator +/// 1. `[]` amm_config +/// 2. `[optional]` authority (default to PDA derived from 'authority') +/// 3. `[writable]` pool_state +/// 4. `[]` token0_mint +/// 5. `[]` token1_mint +/// 6. `[writable, optional]` lp_mint (default to PDA derived from 'lpMint') +/// 7. `[writable]` creator_token0 +/// 8. `[writable]` creator_token1 +/// 9. `[writable, optional]` creator_lp_token (default to PDA derived from 'creatorLpToken') +/// 10. `[writable, optional]` token0_vault (default to PDA derived from 'token0Vault') +/// 11. `[writable, optional]` token1_vault (default to PDA derived from 'token1Vault') +/// 12. `[writable, optional]` create_pool_fee (default to `DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8`) +/// 13. `[writable, optional]` observation_state (default to PDA derived from 'observationState') +/// 14. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 15. `[]` token0_program +/// 16. `[]` token1_program +/// 17. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) +/// 18. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 19. `[optional]` rent (default to `SysvarRent111111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct InitializeBuilder { + creator: solana_address::Address, + amm_config: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + token0_mint: solana_address::Address, + token1_mint: solana_address::Address, + lp_mint: Option, + creator_token0: solana_address::Address, + creator_token1: solana_address::Address, + creator_lp_token: Option, + token0_vault: Option, + token1_vault: Option, + create_pool_fee: Option, + observation_state: Option, + token_program: Option, + token0_program: solana_address::Address, + token1_program: solana_address::Address, + associated_token_program: Option, + system_program: Option, + rent: Option, + init_amount0: u64, + init_amount1: u64, + open_time: u64, + __remaining_accounts: Vec, +} + +impl InitializeBuilder { + pub fn new( + creator: solana_address::Address, + amm_config: solana_address::Address, + pool_state: solana_address::Address, + token0_mint: solana_address::Address, + token1_mint: solana_address::Address, + creator_token0: solana_address::Address, + creator_token1: solana_address::Address, + token0_program: solana_address::Address, + token1_program: solana_address::Address, + init_amount0: u64, + init_amount1: u64, + open_time: u64, + ) -> Self { + Self { + creator, + amm_config, + authority: None, + pool_state, + token0_mint, + token1_mint, + lp_mint: None, + creator_token0, + creator_token1, + creator_lp_token: None, + token0_vault: None, + token1_vault: None, + create_pool_fee: None, + observation_state: None, + token_program: None, + token0_program, + token1_program, + associated_token_program: None, + system_program: None, + rent: None, + init_amount0, + init_amount1, + open_time, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// pool vault and lp mint authority + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'lpMint']` + /// pool lp mint + #[inline(always)] + pub fn lp_mint(&mut self, lp_mint: solana_address::Address) -> &mut Self { + self.lp_mint = Some(lp_mint); + self + } + /// `[optional account, default to PDA derived from 'creatorLpToken']` + /// creator lp token account + #[inline(always)] + pub fn creator_lp_token(&mut self, creator_lp_token: solana_address::Address) -> &mut Self { + self.creator_lp_token = Some(creator_lp_token); + self + } + /// `[optional account, default to PDA derived from 'token0Vault']` + #[inline(always)] + pub fn token0_vault(&mut self, token0_vault: solana_address::Address) -> &mut Self { + self.token0_vault = Some(token0_vault); + self + } + /// `[optional account, default to PDA derived from 'token1Vault']` + #[inline(always)] + pub fn token1_vault(&mut self, token1_vault: solana_address::Address) -> &mut Self { + self.token1_vault = Some(token1_vault); + self + } + /// `[optional account, default to 'DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8']` + /// create pool fee account + #[inline(always)] + pub fn create_pool_fee(&mut self, create_pool_fee: solana_address::Address) -> &mut Self { + self.create_pool_fee = Some(create_pool_fee); + self + } + /// `[optional account, default to PDA derived from 'observationState']` + /// an account to store oracle observations + #[inline(always)] + pub fn observation_state(&mut self, observation_state: solana_address::Address) -> &mut Self { + self.observation_state = Some(observation_state); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// Program to create mint account and mint tokens + #[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 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` + /// Program to create an ATA for receiving position NFT + #[inline(always)] + pub fn associated_token_program( + &mut self, + associated_token_program: solana_address::Address, + ) -> &mut Self { + self.associated_token_program = Some(associated_token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// To create a new program account + #[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']` + /// Sysvar for program account + #[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 creator = self.creator; + let amm_config = self.amm_config; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let token0_mint = self.token0_mint; + let token1_mint = self.token1_mint; + let lp_mint = self + .lp_mint + .unwrap_or_else(|| crate::pdas::find_lp_mint_pda(&self.pool_state).0); + let creator_token0 = self.creator_token0; + let creator_token1 = self.creator_token1; + let creator_lp_token = self.creator_lp_token.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.creator.as_ref(), + &[ + 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, + 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, + 169, + ], + lp_mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + let token0_vault = self.token0_vault.unwrap_or_else(|| { + crate::pdas::find_token0_vault_pda(&self.pool_state, &self.token0_mint).0 + }); + let token1_vault = self.token1_vault.unwrap_or_else(|| { + crate::pdas::find_token1_vault_pda(&self.pool_state, &self.token1_mint).0 + }); + let create_pool_fee = self.create_pool_fee.unwrap_or(solana_address::address!( + "DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8" + )); + let observation_state = self + .observation_state + .unwrap_or_else(|| crate::pdas::find_observation_state_pda(&self.pool_state).0); + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let token0_program = self.token0_program; + let token1_program = self.token1_program; + let associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let rent = self.rent.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let accounts = Initialize { + creator, + amm_config, + authority, + pool_state, + token0_mint, + token1_mint, + lp_mint, + creator_token0, + creator_token1, + creator_lp_token, + token0_vault, + token1_vault, + create_pool_fee, + observation_state, + token_program, + token0_program, + token1_program, + associated_token_program, + system_program, + rent, + }; + let args = InitializeInstructionArgs { + init_amount0: self.init_amount0.clone(), + init_amount1: self.init_amount1.clone(), + open_time: self.open_time.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `initialize` CPI accounts. +pub struct InitializeCpiAccounts<'a, 'b> { + /// Address paying to create the pool. Can be anyone + pub creator: &'b solana_account_info::AccountInfo<'a>, + /// Which config the pool belongs to. + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// pool vault and lp mint authority + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// PDA account: + /// seeds = [ + /// POOL_SEED.as_bytes(), + /// amm_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// + /// Or random account: must be signed by cli + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Token_0 mint, the key must smaller than token_1 mint. + pub token0_mint: &'b solana_account_info::AccountInfo<'a>, + /// Token_1 mint, the key must grater then token_0 mint. + pub token1_mint: &'b solana_account_info::AccountInfo<'a>, + /// pool lp mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, + /// payer token0 account + pub creator_token0: &'b solana_account_info::AccountInfo<'a>, + /// creator token1 account + pub creator_token1: &'b solana_account_info::AccountInfo<'a>, + /// creator lp token account + pub creator_lp_token: &'b solana_account_info::AccountInfo<'a>, + + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// create pool fee account + pub create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + /// an account to store oracle observations + pub observation_state: &'b solana_account_info::AccountInfo<'a>, + /// Program to create mint account and mint tokens + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Spl token program or token program 2022 + pub token0_program: &'b solana_account_info::AccountInfo<'a>, + /// Spl token program or token program 2022 + pub token1_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving position NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// To create a new program account + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Sysvar for program account + pub rent: &'b solana_account_info::AccountInfo<'a>, +} + +/// `initialize` CPI instruction. +pub struct InitializeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Address paying to create the pool. Can be anyone + pub creator: &'b solana_account_info::AccountInfo<'a>, + /// Which config the pool belongs to. + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// pool vault and lp mint authority + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// PDA account: + /// seeds = [ + /// POOL_SEED.as_bytes(), + /// amm_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// + /// Or random account: must be signed by cli + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Token_0 mint, the key must smaller than token_1 mint. + pub token0_mint: &'b solana_account_info::AccountInfo<'a>, + /// Token_1 mint, the key must grater then token_0 mint. + pub token1_mint: &'b solana_account_info::AccountInfo<'a>, + /// pool lp mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, + /// payer token0 account + pub creator_token0: &'b solana_account_info::AccountInfo<'a>, + /// creator token1 account + pub creator_token1: &'b solana_account_info::AccountInfo<'a>, + /// creator lp token account + pub creator_lp_token: &'b solana_account_info::AccountInfo<'a>, + + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// create pool fee account + pub create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + /// an account to store oracle observations + pub observation_state: &'b solana_account_info::AccountInfo<'a>, + /// Program to create mint account and mint tokens + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Spl token program or token program 2022 + pub token0_program: &'b solana_account_info::AccountInfo<'a>, + /// Spl token program or token program 2022 + pub token1_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving position NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// To create a new program account + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Sysvar for program account + pub rent: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InitializeInstructionArgs, +} + +impl<'a, 'b> InitializeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: InitializeCpiAccounts<'a, 'b>, + args: InitializeInstructionArgs, + ) -> Self { + Self { + __program: program, + creator: accounts.creator, + amm_config: accounts.amm_config, + authority: accounts.authority, + pool_state: accounts.pool_state, + token0_mint: accounts.token0_mint, + token1_mint: accounts.token1_mint, + lp_mint: accounts.lp_mint, + creator_token0: accounts.creator_token0, + creator_token1: accounts.creator_token1, + creator_lp_token: accounts.creator_lp_token, + token0_vault: accounts.token0_vault, + token1_vault: accounts.token1_vault, + create_pool_fee: accounts.create_pool_fee, + observation_state: accounts.observation_state, + token_program: accounts.token_program, + token0_program: accounts.token0_program, + token1_program: accounts.token1_program, + associated_token_program: accounts.associated_token_program, + 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(20 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.creator.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token0_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token1_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.lp_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.creator_token0.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.creator_token1.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.creator_lp_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.create_pool_fee.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.observation_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token0_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token1_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.associated_token_program.key, + false, + )); + 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 = InitializeInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(21 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.creator.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.token0_mint.clone()); + account_infos.push(self.token1_mint.clone()); + account_infos.push(self.lp_mint.clone()); + account_infos.push(self.creator_token0.clone()); + account_infos.push(self.creator_token1.clone()); + account_infos.push(self.creator_lp_token.clone()); + account_infos.push(self.token0_vault.clone()); + account_infos.push(self.token1_vault.clone()); + account_infos.push(self.create_pool_fee.clone()); + account_infos.push(self.observation_state.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.token0_program.clone()); + account_infos.push(self.token1_program.clone()); + account_infos.push(self.associated_token_program.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 `Initialize` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` creator +/// 1. `[]` amm_config +/// 2. `[]` authority +/// 3. `[writable]` pool_state +/// 4. `[]` token0_mint +/// 5. `[]` token1_mint +/// 6. `[writable]` lp_mint +/// 7. `[writable]` creator_token0 +/// 8. `[writable]` creator_token1 +/// 9. `[writable]` creator_lp_token +/// 10. `[writable]` token0_vault +/// 11. `[writable]` token1_vault +/// 12. `[writable]` create_pool_fee +/// 13. `[writable]` observation_state +/// 14. `[]` token_program +/// 15. `[]` token0_program +/// 16. `[]` token1_program +/// 17. `[]` associated_token_program +/// 18. `[]` system_program +/// 19. `[]` rent +#[derive(Clone, Debug)] +pub struct InitializeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + token0_mint: &'b solana_account_info::AccountInfo<'a>, + token1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + creator_token0: &'b solana_account_info::AccountInfo<'a>, + creator_token1: &'b solana_account_info::AccountInfo<'a>, + creator_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token0_program: &'b solana_account_info::AccountInfo<'a>, + token1_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + init_amount0: u64, + init_amount1: u64, + open_time: u64, + ) -> Self { + let instruction = Box::new(InitializeCpiBuilderInstruction { + __program, + creator, + amm_config, + authority, + pool_state, + token0_mint, + token1_mint, + lp_mint, + creator_token0, + creator_token1, + creator_lp_token, + token0_vault, + token1_vault, + create_pool_fee, + observation_state, + token_program, + token0_program, + token1_program, + associated_token_program, + system_program, + rent, + init_amount0, + init_amount1, + open_time, + __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 = InitializeInstructionArgs { + init_amount0: self.instruction.init_amount0.clone(), + init_amount1: self.instruction.init_amount1.clone(), + open_time: self.instruction.open_time.clone(), + }; + let instruction = InitializeCpi { + __program: self.instruction.__program, + creator: self.instruction.creator, + amm_config: self.instruction.amm_config, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + token0_mint: self.instruction.token0_mint, + token1_mint: self.instruction.token1_mint, + lp_mint: self.instruction.lp_mint, + creator_token0: self.instruction.creator_token0, + creator_token1: self.instruction.creator_token1, + creator_lp_token: self.instruction.creator_lp_token, + token0_vault: self.instruction.token0_vault, + token1_vault: self.instruction.token1_vault, + create_pool_fee: self.instruction.create_pool_fee, + observation_state: self.instruction.observation_state, + token_program: self.instruction.token_program, + token0_program: self.instruction.token0_program, + token1_program: self.instruction.token1_program, + associated_token_program: self.instruction.associated_token_program, + 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 InitializeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + token0_mint: &'b solana_account_info::AccountInfo<'a>, + token1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + creator_token0: &'b solana_account_info::AccountInfo<'a>, + creator_token1: &'b solana_account_info::AccountInfo<'a>, + creator_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token0_program: &'b solana_account_info::AccountInfo<'a>, + token1_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent: &'b solana_account_info::AccountInfo<'a>, + init_amount0: u64, + init_amount1: u64, + open_time: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/mod.rs b/e2e/raydium-cpmm/src/generated/instructions/mod.rs new file mode 100644 index 0000000..3520d1a --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/mod.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. +//! +//! +//! + +pub(crate) mod r#collect_fund_fee; +pub(crate) mod r#collect_protocol_fee; +pub(crate) mod r#create_amm_config; +pub(crate) mod r#deposit; +pub(crate) mod r#initialize; +pub(crate) mod r#swap_base_input; +pub(crate) mod r#swap_base_output; +pub(crate) mod r#update_amm_config; +pub(crate) mod r#update_pool_status; +pub(crate) mod r#withdraw; + +pub use self::r#collect_fund_fee::*; +pub use self::r#collect_protocol_fee::*; +pub use self::r#create_amm_config::*; +pub use self::r#deposit::*; +pub use self::r#initialize::*; +pub use self::r#swap_base_input::*; +pub use self::r#swap_base_output::*; +pub use self::r#update_amm_config::*; +pub use self::r#update_pool_status::*; +pub use self::r#withdraw::*; diff --git a/e2e/raydium-cpmm/src/generated/instructions/swap_base_input.rs b/e2e/raydium-cpmm/src/generated/instructions/swap_base_input.rs new file mode 100644 index 0000000..4d8dcb5 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/swap_base_input.rs @@ -0,0 +1,639 @@ +//! 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 SWAP_BASE_INPUT_DISCRIMINATOR: [u8; 8] = [143, 190, 90, 218, 196, 30, 51, 222]; + +/// Accounts. +#[derive(Debug)] +pub struct SwapBaseInput { + /// The user performing the swap + pub payer: solana_address::Address, + + pub authority: solana_address::Address, + /// The factory state to read protocol fees + pub amm_config: solana_address::Address, + /// The program account of the pool in which the swap will be performed + pub pool_state: solana_address::Address, + /// The user token account for input token + pub input_token_account: solana_address::Address, + /// The user token account for output token + pub output_token_account: solana_address::Address, + /// The vault token account for input token + pub input_vault: solana_address::Address, + /// The vault token account for output token + pub output_vault: solana_address::Address, + /// SPL program for input token transfers + pub input_token_program: solana_address::Address, + /// SPL program for output token transfers + pub output_token_program: solana_address::Address, + /// The mint of input token + pub input_token_mint: solana_address::Address, + /// The mint of output token + pub output_token_mint: solana_address::Address, + /// The program account for the most recent oracle observation + pub observation_state: solana_address::Address, +} + +impl SwapBaseInput { + pub fn instruction( + &self, + args: SwapBaseInputInstructionArgs, + ) -> 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: SwapBaseInputInstructionArgs, + 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.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.input_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.output_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.input_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.output_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.input_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.output_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.input_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.output_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.observation_state, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SwapBaseInputInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SwapBaseInputInstructionData { + discriminator: [u8; 8], +} + +impl SwapBaseInputInstructionData { + pub fn new() -> Self { + Self { + discriminator: [143, 190, 90, 218, 196, 30, 51, 222], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SwapBaseInputInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SwapBaseInputInstructionArgs { + pub amount_in: u64, + pub minimum_amount_out: u64, +} + +impl SwapBaseInputInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SwapBaseInput`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` amm_config +/// 3. `[writable]` pool_state +/// 4. `[writable]` input_token_account +/// 5. `[writable]` output_token_account +/// 6. `[writable]` input_vault +/// 7. `[writable]` output_vault +/// 8. `[]` input_token_program +/// 9. `[]` output_token_program +/// 10. `[]` input_token_mint +/// 11. `[]` output_token_mint +/// 12. `[writable]` observation_state +#[derive(Clone, Debug)] +pub struct SwapBaseInputBuilder { + payer: solana_address::Address, + authority: Option, + amm_config: solana_address::Address, + pool_state: solana_address::Address, + input_token_account: solana_address::Address, + output_token_account: solana_address::Address, + input_vault: solana_address::Address, + output_vault: solana_address::Address, + input_token_program: solana_address::Address, + output_token_program: solana_address::Address, + input_token_mint: solana_address::Address, + output_token_mint: solana_address::Address, + observation_state: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + __remaining_accounts: Vec, +} + +impl SwapBaseInputBuilder { + pub fn new( + payer: solana_address::Address, + amm_config: solana_address::Address, + pool_state: solana_address::Address, + input_token_account: solana_address::Address, + output_token_account: solana_address::Address, + input_vault: solana_address::Address, + output_vault: solana_address::Address, + input_token_program: solana_address::Address, + output_token_program: solana_address::Address, + input_token_mint: solana_address::Address, + output_token_mint: solana_address::Address, + observation_state: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + ) -> Self { + Self { + payer, + authority: None, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + amount_in, + minimum_amount_out, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let amm_config = self.amm_config; + let pool_state = self.pool_state; + let input_token_account = self.input_token_account; + let output_token_account = self.output_token_account; + let input_vault = self.input_vault; + let output_vault = self.output_vault; + let input_token_program = self.input_token_program; + let output_token_program = self.output_token_program; + let input_token_mint = self.input_token_mint; + let output_token_mint = self.output_token_mint; + let observation_state = self.observation_state; + let accounts = SwapBaseInput { + payer, + authority, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + }; + let args = SwapBaseInputInstructionArgs { + amount_in: self.amount_in.clone(), + minimum_amount_out: self.minimum_amount_out.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `swap_base_input` CPI accounts. +pub struct SwapBaseInputCpiAccounts<'a, 'b> { + /// The user performing the swap + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// The factory state to read protocol fees + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The program account of the pool in which the swap will be performed + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for input token + pub input_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for output token + pub output_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for input token + pub input_vault: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for output token + pub output_vault: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub input_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for output token transfers + pub output_token_program: &'b solana_account_info::AccountInfo<'a>, + /// The mint of input token + pub input_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of output token + pub output_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The program account for the most recent oracle observation + pub observation_state: &'b solana_account_info::AccountInfo<'a>, +} + +/// `swap_base_input` CPI instruction. +pub struct SwapBaseInputCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// The factory state to read protocol fees + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The program account of the pool in which the swap will be performed + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for input token + pub input_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for output token + pub output_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for input token + pub input_vault: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for output token + pub output_vault: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub input_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for output token transfers + pub output_token_program: &'b solana_account_info::AccountInfo<'a>, + /// The mint of input token + pub input_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of output token + pub output_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The program account for the most recent oracle observation + pub observation_state: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SwapBaseInputInstructionArgs, +} + +impl<'a, 'b> SwapBaseInputCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SwapBaseInputCpiAccounts<'a, 'b>, + args: SwapBaseInputInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + amm_config: accounts.amm_config, + pool_state: accounts.pool_state, + input_token_account: accounts.input_token_account, + output_token_account: accounts.output_token_account, + input_vault: accounts.input_vault, + output_vault: accounts.output_vault, + input_token_program: accounts.input_token_program, + output_token_program: accounts.output_token_program, + input_token_mint: accounts.input_token_mint, + output_token_mint: accounts.output_token_mint, + observation_state: accounts.observation_state, + __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.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.input_token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.output_token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.input_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.output_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.input_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.output_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.input_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.output_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.observation_state.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 = SwapBaseInputInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(14 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.input_token_account.clone()); + account_infos.push(self.output_token_account.clone()); + account_infos.push(self.input_vault.clone()); + account_infos.push(self.output_vault.clone()); + account_infos.push(self.input_token_program.clone()); + account_infos.push(self.output_token_program.clone()); + account_infos.push(self.input_token_mint.clone()); + account_infos.push(self.output_token_mint.clone()); + account_infos.push(self.observation_state.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 `SwapBaseInput` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` amm_config +/// 3. `[writable]` pool_state +/// 4. `[writable]` input_token_account +/// 5. `[writable]` output_token_account +/// 6. `[writable]` input_vault +/// 7. `[writable]` output_vault +/// 8. `[]` input_token_program +/// 9. `[]` output_token_program +/// 10. `[]` input_token_mint +/// 11. `[]` output_token_mint +/// 12. `[writable]` observation_state +#[derive(Clone, Debug)] +pub struct SwapBaseInputCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SwapBaseInputCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + input_token_account: &'b solana_account_info::AccountInfo<'a>, + output_token_account: &'b solana_account_info::AccountInfo<'a>, + input_vault: &'b solana_account_info::AccountInfo<'a>, + output_vault: &'b solana_account_info::AccountInfo<'a>, + input_token_program: &'b solana_account_info::AccountInfo<'a>, + output_token_program: &'b solana_account_info::AccountInfo<'a>, + input_token_mint: &'b solana_account_info::AccountInfo<'a>, + output_token_mint: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + ) -> Self { + let instruction = Box::new(SwapBaseInputCpiBuilderInstruction { + __program, + payer, + authority, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + amount_in, + minimum_amount_out, + __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 = SwapBaseInputInstructionArgs { + amount_in: self.instruction.amount_in.clone(), + minimum_amount_out: self.instruction.minimum_amount_out.clone(), + }; + let instruction = SwapBaseInputCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + amm_config: self.instruction.amm_config, + pool_state: self.instruction.pool_state, + input_token_account: self.instruction.input_token_account, + output_token_account: self.instruction.output_token_account, + input_vault: self.instruction.input_vault, + output_vault: self.instruction.output_vault, + input_token_program: self.instruction.input_token_program, + output_token_program: self.instruction.output_token_program, + input_token_mint: self.instruction.input_token_mint, + output_token_mint: self.instruction.output_token_mint, + observation_state: self.instruction.observation_state, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SwapBaseInputCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + input_token_account: &'b solana_account_info::AccountInfo<'a>, + output_token_account: &'b solana_account_info::AccountInfo<'a>, + input_vault: &'b solana_account_info::AccountInfo<'a>, + output_vault: &'b solana_account_info::AccountInfo<'a>, + input_token_program: &'b solana_account_info::AccountInfo<'a>, + output_token_program: &'b solana_account_info::AccountInfo<'a>, + input_token_mint: &'b solana_account_info::AccountInfo<'a>, + output_token_mint: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/swap_base_output.rs b/e2e/raydium-cpmm/src/generated/instructions/swap_base_output.rs new file mode 100644 index 0000000..ebda03e --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/swap_base_output.rs @@ -0,0 +1,639 @@ +//! 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 SWAP_BASE_OUTPUT_DISCRIMINATOR: [u8; 8] = [55, 217, 98, 86, 163, 74, 180, 173]; + +/// Accounts. +#[derive(Debug)] +pub struct SwapBaseOutput { + /// The user performing the swap + pub payer: solana_address::Address, + + pub authority: solana_address::Address, + /// The factory state to read protocol fees + pub amm_config: solana_address::Address, + /// The program account of the pool in which the swap will be performed + pub pool_state: solana_address::Address, + /// The user token account for input token + pub input_token_account: solana_address::Address, + /// The user token account for output token + pub output_token_account: solana_address::Address, + /// The vault token account for input token + pub input_vault: solana_address::Address, + /// The vault token account for output token + pub output_vault: solana_address::Address, + /// SPL program for input token transfers + pub input_token_program: solana_address::Address, + /// SPL program for output token transfers + pub output_token_program: solana_address::Address, + /// The mint of input token + pub input_token_mint: solana_address::Address, + /// The mint of output token + pub output_token_mint: solana_address::Address, + /// The program account for the most recent oracle observation + pub observation_state: solana_address::Address, +} + +impl SwapBaseOutput { + pub fn instruction( + &self, + args: SwapBaseOutputInstructionArgs, + ) -> 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: SwapBaseOutputInstructionArgs, + 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.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.input_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.output_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.input_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.output_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.input_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.output_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.input_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.output_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.observation_state, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SwapBaseOutputInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SwapBaseOutputInstructionData { + discriminator: [u8; 8], +} + +impl SwapBaseOutputInstructionData { + pub fn new() -> Self { + Self { + discriminator: [55, 217, 98, 86, 163, 74, 180, 173], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SwapBaseOutputInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SwapBaseOutputInstructionArgs { + pub max_amount_in: u64, + pub amount_out: u64, +} + +impl SwapBaseOutputInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SwapBaseOutput`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` amm_config +/// 3. `[writable]` pool_state +/// 4. `[writable]` input_token_account +/// 5. `[writable]` output_token_account +/// 6. `[writable]` input_vault +/// 7. `[writable]` output_vault +/// 8. `[]` input_token_program +/// 9. `[]` output_token_program +/// 10. `[]` input_token_mint +/// 11. `[]` output_token_mint +/// 12. `[writable]` observation_state +#[derive(Clone, Debug)] +pub struct SwapBaseOutputBuilder { + payer: solana_address::Address, + authority: Option, + amm_config: solana_address::Address, + pool_state: solana_address::Address, + input_token_account: solana_address::Address, + output_token_account: solana_address::Address, + input_vault: solana_address::Address, + output_vault: solana_address::Address, + input_token_program: solana_address::Address, + output_token_program: solana_address::Address, + input_token_mint: solana_address::Address, + output_token_mint: solana_address::Address, + observation_state: solana_address::Address, + max_amount_in: u64, + amount_out: u64, + __remaining_accounts: Vec, +} + +impl SwapBaseOutputBuilder { + pub fn new( + payer: solana_address::Address, + amm_config: solana_address::Address, + pool_state: solana_address::Address, + input_token_account: solana_address::Address, + output_token_account: solana_address::Address, + input_vault: solana_address::Address, + output_vault: solana_address::Address, + input_token_program: solana_address::Address, + output_token_program: solana_address::Address, + input_token_mint: solana_address::Address, + output_token_mint: solana_address::Address, + observation_state: solana_address::Address, + max_amount_in: u64, + amount_out: u64, + ) -> Self { + Self { + payer, + authority: None, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + max_amount_in, + amount_out, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let amm_config = self.amm_config; + let pool_state = self.pool_state; + let input_token_account = self.input_token_account; + let output_token_account = self.output_token_account; + let input_vault = self.input_vault; + let output_vault = self.output_vault; + let input_token_program = self.input_token_program; + let output_token_program = self.output_token_program; + let input_token_mint = self.input_token_mint; + let output_token_mint = self.output_token_mint; + let observation_state = self.observation_state; + let accounts = SwapBaseOutput { + payer, + authority, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + }; + let args = SwapBaseOutputInstructionArgs { + max_amount_in: self.max_amount_in.clone(), + amount_out: self.amount_out.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `swap_base_output` CPI accounts. +pub struct SwapBaseOutputCpiAccounts<'a, 'b> { + /// The user performing the swap + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// The factory state to read protocol fees + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The program account of the pool in which the swap will be performed + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for input token + pub input_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for output token + pub output_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for input token + pub input_vault: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for output token + pub output_vault: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub input_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for output token transfers + pub output_token_program: &'b solana_account_info::AccountInfo<'a>, + /// The mint of input token + pub input_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of output token + pub output_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The program account for the most recent oracle observation + pub observation_state: &'b solana_account_info::AccountInfo<'a>, +} + +/// `swap_base_output` CPI instruction. +pub struct SwapBaseOutputCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// The factory state to read protocol fees + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The program account of the pool in which the swap will be performed + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for input token + pub input_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The user token account for output token + pub output_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for input token + pub input_vault: &'b solana_account_info::AccountInfo<'a>, + /// The vault token account for output token + pub output_vault: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub input_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for output token transfers + pub output_token_program: &'b solana_account_info::AccountInfo<'a>, + /// The mint of input token + pub input_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of output token + pub output_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The program account for the most recent oracle observation + pub observation_state: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SwapBaseOutputInstructionArgs, +} + +impl<'a, 'b> SwapBaseOutputCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SwapBaseOutputCpiAccounts<'a, 'b>, + args: SwapBaseOutputInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + amm_config: accounts.amm_config, + pool_state: accounts.pool_state, + input_token_account: accounts.input_token_account, + output_token_account: accounts.output_token_account, + input_vault: accounts.input_vault, + output_vault: accounts.output_vault, + input_token_program: accounts.input_token_program, + output_token_program: accounts.output_token_program, + input_token_mint: accounts.input_token_mint, + output_token_mint: accounts.output_token_mint, + observation_state: accounts.observation_state, + __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.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.input_token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.output_token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.input_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.output_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.input_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.output_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.input_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.output_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.observation_state.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 = SwapBaseOutputInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(14 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.input_token_account.clone()); + account_infos.push(self.output_token_account.clone()); + account_infos.push(self.input_vault.clone()); + account_infos.push(self.output_vault.clone()); + account_infos.push(self.input_token_program.clone()); + account_infos.push(self.output_token_program.clone()); + account_infos.push(self.input_token_mint.clone()); + account_infos.push(self.output_token_mint.clone()); + account_infos.push(self.observation_state.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 `SwapBaseOutput` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` amm_config +/// 3. `[writable]` pool_state +/// 4. `[writable]` input_token_account +/// 5. `[writable]` output_token_account +/// 6. `[writable]` input_vault +/// 7. `[writable]` output_vault +/// 8. `[]` input_token_program +/// 9. `[]` output_token_program +/// 10. `[]` input_token_mint +/// 11. `[]` output_token_mint +/// 12. `[writable]` observation_state +#[derive(Clone, Debug)] +pub struct SwapBaseOutputCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SwapBaseOutputCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + input_token_account: &'b solana_account_info::AccountInfo<'a>, + output_token_account: &'b solana_account_info::AccountInfo<'a>, + input_vault: &'b solana_account_info::AccountInfo<'a>, + output_vault: &'b solana_account_info::AccountInfo<'a>, + input_token_program: &'b solana_account_info::AccountInfo<'a>, + output_token_program: &'b solana_account_info::AccountInfo<'a>, + input_token_mint: &'b solana_account_info::AccountInfo<'a>, + output_token_mint: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + max_amount_in: u64, + amount_out: u64, + ) -> Self { + let instruction = Box::new(SwapBaseOutputCpiBuilderInstruction { + __program, + payer, + authority, + amm_config, + pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program, + output_token_program, + input_token_mint, + output_token_mint, + observation_state, + max_amount_in, + amount_out, + __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 = SwapBaseOutputInstructionArgs { + max_amount_in: self.instruction.max_amount_in.clone(), + amount_out: self.instruction.amount_out.clone(), + }; + let instruction = SwapBaseOutputCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + amm_config: self.instruction.amm_config, + pool_state: self.instruction.pool_state, + input_token_account: self.instruction.input_token_account, + output_token_account: self.instruction.output_token_account, + input_vault: self.instruction.input_vault, + output_vault: self.instruction.output_vault, + input_token_program: self.instruction.input_token_program, + output_token_program: self.instruction.output_token_program, + input_token_mint: self.instruction.input_token_mint, + output_token_mint: self.instruction.output_token_mint, + observation_state: self.instruction.observation_state, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SwapBaseOutputCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + input_token_account: &'b solana_account_info::AccountInfo<'a>, + output_token_account: &'b solana_account_info::AccountInfo<'a>, + input_vault: &'b solana_account_info::AccountInfo<'a>, + output_vault: &'b solana_account_info::AccountInfo<'a>, + input_token_program: &'b solana_account_info::AccountInfo<'a>, + output_token_program: &'b solana_account_info::AccountInfo<'a>, + input_token_mint: &'b solana_account_info::AccountInfo<'a>, + output_token_mint: &'b solana_account_info::AccountInfo<'a>, + observation_state: &'b solana_account_info::AccountInfo<'a>, + max_amount_in: u64, + amount_out: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/update_amm_config.rs b/e2e/raydium-cpmm/src/generated/instructions/update_amm_config.rs new file mode 100644 index 0000000..b69c751 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/update_amm_config.rs @@ -0,0 +1,338 @@ +//! 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_AMM_CONFIG_DISCRIMINATOR: [u8; 8] = [49, 60, 174, 136, 154, 28, 116, 200]; + +/// Accounts. +#[derive(Debug)] +pub struct UpdateAmmConfig { + /// The amm config owner or admin + pub owner: solana_address::Address, + /// Amm config account to be changed + pub amm_config: solana_address::Address, +} + +impl UpdateAmmConfig { + pub fn instruction( + &self, + args: UpdateAmmConfigInstructionArgs, + ) -> 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: UpdateAmmConfigInstructionArgs, + 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(self.amm_config, false)); + accounts.extend_from_slice(remaining_accounts); + let mut data = UpdateAmmConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdateAmmConfigInstructionData { + discriminator: [u8; 8], +} + +impl UpdateAmmConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [49, 60, 174, 136, 154, 28, 116, 200], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for UpdateAmmConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdateAmmConfigInstructionArgs { + pub param: u8, + pub value: u64, +} + +impl UpdateAmmConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `UpdateAmmConfig`. +/// +/// ### Accounts: +/// +/// 0. `[signer, optional]` owner (default to `GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ`) +/// 1. `[writable]` amm_config +#[derive(Clone, Debug)] +pub struct UpdateAmmConfigBuilder { + owner: Option, + amm_config: solana_address::Address, + param: u8, + value: u64, + __remaining_accounts: Vec, +} + +impl UpdateAmmConfigBuilder { + pub fn new(amm_config: solana_address::Address, param: u8, value: u64) -> Self { + Self { + owner: None, + amm_config, + param, + value, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ']` + /// The amm config owner or admin + #[inline(always)] + pub fn owner(&mut self, owner: solana_address::Address) -> &mut Self { + self.owner = Some(owner); + 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.unwrap_or(solana_address::address!( + "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + )); + let amm_config = self.amm_config; + let accounts = UpdateAmmConfig { owner, amm_config }; + let args = UpdateAmmConfigInstructionArgs { + param: self.param.clone(), + value: self.value.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_amm_config` CPI accounts. +pub struct UpdateAmmConfigCpiAccounts<'a, 'b> { + /// The amm config owner or admin + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account to be changed + pub amm_config: &'b solana_account_info::AccountInfo<'a>, +} + +/// `update_amm_config` CPI instruction. +pub struct UpdateAmmConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The amm config owner or admin + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Amm config account to be changed + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdateAmmConfigInstructionArgs, +} + +impl<'a, 'b> UpdateAmmConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: UpdateAmmConfigCpiAccounts<'a, 'b>, + args: UpdateAmmConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + amm_config: accounts.amm_config, + __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.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_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 mut data = UpdateAmmConfigInstructionData::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::RAYDIUM_CP_SWAP_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.amm_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 `UpdateAmmConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[writable]` amm_config +#[derive(Clone, Debug)] +pub struct UpdateAmmConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateAmmConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + param: u8, + value: u64, + ) -> Self { + let instruction = Box::new(UpdateAmmConfigCpiBuilderInstruction { + __program, + owner, + amm_config, + param, + value, + __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 = UpdateAmmConfigInstructionArgs { + param: self.instruction.param.clone(), + value: self.instruction.value.clone(), + }; + let instruction = UpdateAmmConfigCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + amm_config: self.instruction.amm_config, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct UpdateAmmConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + param: u8, + value: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/update_pool_status.rs b/e2e/raydium-cpmm/src/generated/instructions/update_pool_status.rs new file mode 100644 index 0000000..19f57c4 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/update_pool_status.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_POOL_STATUS_DISCRIMINATOR: [u8; 8] = [130, 87, 108, 6, 46, 224, 117, 123]; + +/// Accounts. +#[derive(Debug)] +pub struct UpdatePoolStatus { + pub authority: solana_address::Address, + + pub pool_state: solana_address::Address, +} + +impl UpdatePoolStatus { + pub fn instruction( + &self, + args: UpdatePoolStatusInstructionArgs, + ) -> 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: UpdatePoolStatusInstructionArgs, + 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.authority, + true, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.extend_from_slice(remaining_accounts); + let mut data = UpdatePoolStatusInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdatePoolStatusInstructionData { + discriminator: [u8; 8], +} + +impl UpdatePoolStatusInstructionData { + pub fn new() -> Self { + Self { + discriminator: [130, 87, 108, 6, 46, 224, 117, 123], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for UpdatePoolStatusInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdatePoolStatusInstructionArgs { + pub status: u8, +} + +impl UpdatePoolStatusInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `UpdatePoolStatus`. +/// +/// ### Accounts: +/// +/// 0. `[signer, optional]` authority (default to `GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ`) +/// 1. `[writable]` pool_state +#[derive(Clone, Debug)] +pub struct UpdatePoolStatusBuilder { + authority: Option, + pool_state: solana_address::Address, + status: u8, + __remaining_accounts: Vec, +} + +impl UpdatePoolStatusBuilder { + pub fn new(pool_state: solana_address::Address, status: u8) -> Self { + Self { + authority: None, + pool_state, + status, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(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 authority = self.authority.unwrap_or(solana_address::address!( + "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + )); + let pool_state = self.pool_state; + let accounts = UpdatePoolStatus { + authority, + pool_state, + }; + let args = UpdatePoolStatusInstructionArgs { + status: self.status.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_pool_status` CPI accounts. +pub struct UpdatePoolStatusCpiAccounts<'a, 'b> { + pub authority: &'b solana_account_info::AccountInfo<'a>, + + pub pool_state: &'b solana_account_info::AccountInfo<'a>, +} + +/// `update_pool_status` CPI instruction. +pub struct UpdatePoolStatusCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdatePoolStatusInstructionArgs, +} + +impl<'a, 'b> UpdatePoolStatusCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: UpdatePoolStatusCpiAccounts<'a, 'b>, + args: UpdatePoolStatusInstructionArgs, + ) -> Self { + Self { + __program: program, + authority: accounts.authority, + pool_state: accounts.pool_state, + __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.authority.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.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 = UpdatePoolStatusInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(3 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.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 `UpdatePoolStatus` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` authority +/// 1. `[writable]` pool_state +#[derive(Clone, Debug)] +pub struct UpdatePoolStatusCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdatePoolStatusCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + status: u8, + ) -> Self { + let instruction = Box::new(UpdatePoolStatusCpiBuilderInstruction { + __program, + authority, + pool_state, + status, + __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 = UpdatePoolStatusInstructionArgs { + status: self.instruction.status.clone(), + }; + let instruction = UpdatePoolStatusCpi { + __program: self.instruction.__program, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct UpdatePoolStatusCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + status: u8, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-cpmm/src/generated/instructions/withdraw.rs b/e2e/raydium-cpmm/src/generated/instructions/withdraw.rs new file mode 100644 index 0000000..830049d --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/instructions/withdraw.rs @@ -0,0 +1,693 @@ +//! 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_DISCRIMINATOR: [u8; 8] = [183, 18, 70, 156, 148, 109, 161, 34]; + +/// Accounts. +#[derive(Debug)] +pub struct Withdraw { + /// Pays to mint the position + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + /// Pool state account + pub pool_state: solana_address::Address, + /// Owner lp token account + pub owner_lp_token: solana_address::Address, + /// The token account for receive token_0, + pub token0_account: solana_address::Address, + /// The token account for receive token_1 + pub token1_account: solana_address::Address, + /// The address that holds pool tokens for token_0 + pub token0_vault: solana_address::Address, + /// The address that holds pool tokens for token_1 + pub token1_vault: solana_address::Address, + /// token Program + pub token_program: solana_address::Address, + /// Token program 2022 + pub token_program2022: solana_address::Address, + /// The mint of token_0 vault + pub vault0_mint: solana_address::Address, + /// The mint of token_1 vault + pub vault1_mint: solana_address::Address, + /// Pool lp token mint + pub lp_mint: solana_address::Address, + /// memo program + pub memo_program: solana_address::Address, +} + +impl Withdraw { + pub fn instruction(&self, args: WithdrawInstructionArgs) -> 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: WithdrawInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(14 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.owner_lp_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token0_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.token1_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program2022, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault0_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.vault1_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.lp_mint, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.memo_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = WithdrawInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_CP_SWAP_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct WithdrawInstructionData { + discriminator: [u8; 8], +} + +impl WithdrawInstructionData { + pub fn new() -> Self { + Self { + discriminator: [183, 18, 70, 156, 148, 109, 161, 34], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for WithdrawInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct WithdrawInstructionArgs { + pub lp_token_amount: u64, + pub minimum_token0_amount: u64, + pub minimum_token1_amount: u64, +} + +impl WithdrawInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `Withdraw`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[writable]` owner_lp_token +/// 4. `[writable]` token0_account +/// 5. `[writable]` token1_account +/// 6. `[writable]` token0_vault +/// 7. `[writable]` token1_vault +/// 8. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 9. `[optional]` token_program2022 (default to `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`) +/// 10. `[]` vault0_mint +/// 11. `[]` vault1_mint +/// 12. `[writable]` lp_mint +/// 13. `[optional]` memo_program (default to `MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr`) +#[derive(Clone, Debug)] +pub struct WithdrawBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + owner_lp_token: solana_address::Address, + token0_account: solana_address::Address, + token1_account: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + token_program: Option, + token_program2022: Option, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + lp_mint: solana_address::Address, + memo_program: Option, + lp_token_amount: u64, + minimum_token0_amount: u64, + minimum_token1_amount: u64, + __remaining_accounts: Vec, +} + +impl WithdrawBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + owner_lp_token: solana_address::Address, + token0_account: solana_address::Address, + token1_account: solana_address::Address, + token0_vault: solana_address::Address, + token1_vault: solana_address::Address, + vault0_mint: solana_address::Address, + vault1_mint: solana_address::Address, + lp_mint: solana_address::Address, + lp_token_amount: u64, + minimum_token0_amount: u64, + minimum_token1_amount: u64, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program: None, + token_program2022: None, + vault0_mint, + vault1_mint, + lp_mint, + memo_program: None, + lp_token_amount, + minimum_token0_amount, + minimum_token1_amount, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// 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 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb']` + /// Token program 2022 + #[inline(always)] + pub fn token_program2022(&mut self, token_program2022: solana_address::Address) -> &mut Self { + self.token_program2022 = Some(token_program2022); + self + } + /// `[optional account, default to 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr']` + /// memo program + #[inline(always)] + pub fn memo_program(&mut self, memo_program: solana_address::Address) -> &mut Self { + self.memo_program = Some(memo_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 authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let owner_lp_token = self.owner_lp_token; + let token0_account = self.token0_account; + let token1_account = self.token1_account; + let token0_vault = self.token0_vault; + let token1_vault = self.token1_vault; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let token_program2022 = self.token_program2022.unwrap_or(solana_address::address!( + "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" + )); + let vault0_mint = self.vault0_mint; + let vault1_mint = self.vault1_mint; + let lp_mint = self.lp_mint; + let memo_program = self.memo_program.unwrap_or(solana_address::address!( + "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr" + )); + let accounts = Withdraw { + owner, + authority, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program, + token_program2022, + vault0_mint, + vault1_mint, + lp_mint, + memo_program, + }; + let args = WithdrawInstructionArgs { + lp_token_amount: self.lp_token_amount.clone(), + minimum_token0_amount: self.minimum_token0_amount.clone(), + minimum_token1_amount: self.minimum_token1_amount.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `withdraw` CPI accounts. +pub struct WithdrawCpiAccounts<'a, 'b> { + /// Pays to mint the position + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state account + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Owner lp token account + pub owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// The token account for receive token_0, + pub token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The token account for receive token_1 + pub token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Token program 2022 + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// Pool lp token mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, + /// memo program + pub memo_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `withdraw` CPI instruction. +pub struct WithdrawCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Pays to mint the position + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state account + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Owner lp token account + pub owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// The token account for receive token_0, + pub token0_account: &'b solana_account_info::AccountInfo<'a>, + /// The token account for receive token_1 + pub token1_account: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_0 + pub token0_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for token_1 + pub token1_vault: &'b solana_account_info::AccountInfo<'a>, + /// token Program + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Token program 2022 + pub token_program2022: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_0 vault + pub vault0_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of token_1 vault + pub vault1_mint: &'b solana_account_info::AccountInfo<'a>, + /// Pool lp token mint + pub lp_mint: &'b solana_account_info::AccountInfo<'a>, + /// memo program + pub memo_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: WithdrawInstructionArgs, +} + +impl<'a, 'b> WithdrawCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: WithdrawCpiAccounts<'a, 'b>, + args: WithdrawInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + owner_lp_token: accounts.owner_lp_token, + token0_account: accounts.token0_account, + token1_account: accounts.token1_account, + token0_vault: accounts.token0_vault, + token1_vault: accounts.token1_vault, + token_program: accounts.token_program, + token_program2022: accounts.token_program2022, + vault0_mint: accounts.vault0_mint, + vault1_mint: accounts.vault1_mint, + lp_mint: accounts.lp_mint, + memo_program: accounts.memo_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(14 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.owner_lp_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token0_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.token1_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.token_program2022.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault0_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.vault1_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.lp_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.memo_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 = WithdrawInstructionData::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::RAYDIUM_CP_SWAP_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(15 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.owner_lp_token.clone()); + account_infos.push(self.token0_account.clone()); + account_infos.push(self.token1_account.clone()); + account_infos.push(self.token0_vault.clone()); + account_infos.push(self.token1_vault.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.token_program2022.clone()); + account_infos.push(self.vault0_mint.clone()); + account_infos.push(self.vault1_mint.clone()); + account_infos.push(self.lp_mint.clone()); + account_infos.push(self.memo_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 `Withdraw` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[writable]` owner_lp_token +/// 4. `[writable]` token0_account +/// 5. `[writable]` token1_account +/// 6. `[writable]` token0_vault +/// 7. `[writable]` token1_vault +/// 8. `[]` token_program +/// 9. `[]` token_program2022 +/// 10. `[]` vault0_mint +/// 11. `[]` vault1_mint +/// 12. `[writable]` lp_mint +/// 13. `[]` memo_program +#[derive(Clone, Debug)] +pub struct WithdrawCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> WithdrawCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_account: &'b solana_account_info::AccountInfo<'a>, + token1_account: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + memo_program: &'b solana_account_info::AccountInfo<'a>, + lp_token_amount: u64, + minimum_token0_amount: u64, + minimum_token1_amount: u64, + ) -> Self { + let instruction = Box::new(WithdrawCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + owner_lp_token, + token0_account, + token1_account, + token0_vault, + token1_vault, + token_program, + token_program2022, + vault0_mint, + vault1_mint, + lp_mint, + memo_program, + lp_token_amount, + minimum_token0_amount, + minimum_token1_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 = WithdrawInstructionArgs { + lp_token_amount: self.instruction.lp_token_amount.clone(), + minimum_token0_amount: self.instruction.minimum_token0_amount.clone(), + minimum_token1_amount: self.instruction.minimum_token1_amount.clone(), + }; + let instruction = WithdrawCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + owner_lp_token: self.instruction.owner_lp_token, + token0_account: self.instruction.token0_account, + token1_account: self.instruction.token1_account, + token0_vault: self.instruction.token0_vault, + token1_vault: self.instruction.token1_vault, + token_program: self.instruction.token_program, + token_program2022: self.instruction.token_program2022, + vault0_mint: self.instruction.vault0_mint, + vault1_mint: self.instruction.vault1_mint, + lp_mint: self.instruction.lp_mint, + memo_program: self.instruction.memo_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct WithdrawCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + owner_lp_token: &'b solana_account_info::AccountInfo<'a>, + token0_account: &'b solana_account_info::AccountInfo<'a>, + token1_account: &'b solana_account_info::AccountInfo<'a>, + token0_vault: &'b solana_account_info::AccountInfo<'a>, + token1_vault: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + token_program2022: &'b solana_account_info::AccountInfo<'a>, + vault0_mint: &'b solana_account_info::AccountInfo<'a>, + vault1_mint: &'b solana_account_info::AccountInfo<'a>, + lp_mint: &'b solana_account_info::AccountInfo<'a>, + memo_program: &'b solana_account_info::AccountInfo<'a>, + lp_token_amount: u64, + minimum_token0_amount: u64, + minimum_token1_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/raydium-cpmm/src/generated/mod.rs b/e2e/raydium-cpmm/src/generated/mod.rs new file mode 100644 index 0000000..726a6f0 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/mod.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. +//! +//! +//! + +pub mod accounts; +pub mod errors; +pub mod events; +pub mod instructions; +pub mod pdas; +pub mod programs; +pub mod shared; +pub mod types; + +pub(crate) use programs::*; diff --git a/e2e/raydium-cpmm/src/generated/pdas/amm_config.rs b/e2e/raydium-cpmm/src/generated/pdas/amm_config.rs new file mode 100644 index 0000000..e49d2ad --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/amm_config.rs @@ -0,0 +1,25 @@ +//! 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::RAYDIUM_CP_SWAP_ID; + +pub const AMM_CONFIG_SEED: &'static [u8] = &[97, 109, 109, 95, 99, 111, 110, 102, 105, 103]; +pub fn create_amm_config_pda( + index: u16, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[AMM_CONFIG_SEED, index.to_string().as_ref(), &[bump]], + &RAYDIUM_CP_SWAP_ID, + ) +} +pub fn find_amm_config_pda(index: u16) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[AMM_CONFIG_SEED, index.to_string().as_ref()], + &RAYDIUM_CP_SWAP_ID, + ) +} diff --git a/e2e/raydium-cpmm/src/generated/pdas/authority.rs b/e2e/raydium-cpmm/src/generated/pdas/authority.rs new file mode 100644 index 0000000..1bba5a1 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/authority.rs @@ -0,0 +1,24 @@ +//! 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::RAYDIUM_CP_SWAP_ID; + +pub const AUTHORITY_SEED: &'static [u8] = &[ + 118, 97, 117, 108, 116, 95, 97, 110, 100, 95, 108, 112, 95, 109, 105, 110, 116, 95, 97, 117, + 116, 104, 95, 115, 101, 101, 100, +]; + +pub const AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("GpMZbSM2GgvTKHJirzeGfMFoaZ8UR2X7F4v8vHTvxFbL"); +pub fn create_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address(&[AUTHORITY_SEED, &[bump]], &RAYDIUM_CP_SWAP_ID) +} +pub fn find_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address(&[AUTHORITY_SEED], &RAYDIUM_CP_SWAP_ID) +} diff --git a/e2e/raydium-cpmm/src/generated/pdas/lp_mint.rs b/e2e/raydium-cpmm/src/generated/pdas/lp_mint.rs new file mode 100644 index 0000000..c47b416 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/lp_mint.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 solana_address::Address; + +use crate::RAYDIUM_CP_SWAP_ID; + +pub const LP_MINT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 108, 112, 95, 109, 105, 110, 116]; +pub fn create_lp_mint_pda( + pool_state: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[LP_MINT_SEED, pool_state.as_ref(), &[bump]], + &RAYDIUM_CP_SWAP_ID, + ) +} +pub fn find_lp_mint_pda(pool_state: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[LP_MINT_SEED, pool_state.as_ref()], + &RAYDIUM_CP_SWAP_ID, + ) +} diff --git a/e2e/raydium-cpmm/src/generated/pdas/mod.rs b/e2e/raydium-cpmm/src/generated/pdas/mod.rs new file mode 100644 index 0000000..546108a --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/mod.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. +//! +//! +//! + +pub mod amm_config; +pub mod authority; +pub mod lp_mint; +pub mod observation_state; +pub mod token0_vault; +pub mod token1_vault; + +pub use self::amm_config::*; +pub use self::authority::*; +pub use self::lp_mint::*; +pub use self::observation_state::*; +pub use self::token0_vault::*; +pub use self::token1_vault::*; diff --git a/e2e/raydium-cpmm/src/generated/pdas/observation_state.rs b/e2e/raydium-cpmm/src/generated/pdas/observation_state.rs new file mode 100644 index 0000000..1523dac --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/observation_state.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 solana_address::Address; + +use crate::RAYDIUM_CP_SWAP_ID; + +pub const OBSERVATION_STATE_SEED: &'static [u8] = + &[111, 98, 115, 101, 114, 118, 97, 116, 105, 111, 110]; +pub fn create_observation_state_pda( + pool_state: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[OBSERVATION_STATE_SEED, pool_state.as_ref(), &[bump]], + &RAYDIUM_CP_SWAP_ID, + ) +} +pub fn find_observation_state_pda(pool_state: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[OBSERVATION_STATE_SEED, pool_state.as_ref()], + &RAYDIUM_CP_SWAP_ID, + ) +} diff --git a/e2e/raydium-cpmm/src/generated/pdas/token0_vault.rs b/e2e/raydium-cpmm/src/generated/pdas/token0_vault.rs new file mode 100644 index 0000000..5a0dc23 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/token0_vault.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::RAYDIUM_CP_SWAP_ID; + +pub const TOKEN0_VAULT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; +pub fn create_token0_vault_pda( + pool_state: Address, + token0_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + TOKEN0_VAULT_SEED, + pool_state.as_ref(), + token0_mint.as_ref(), + &[bump], + ], + &RAYDIUM_CP_SWAP_ID, + ) +} +pub fn find_token0_vault_pda( + pool_state: &Address, + token0_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[TOKEN0_VAULT_SEED, pool_state.as_ref(), token0_mint.as_ref()], + &RAYDIUM_CP_SWAP_ID, + ) +} diff --git a/e2e/raydium-cpmm/src/generated/pdas/token1_vault.rs b/e2e/raydium-cpmm/src/generated/pdas/token1_vault.rs new file mode 100644 index 0000000..f114cfa --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/pdas/token1_vault.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::RAYDIUM_CP_SWAP_ID; + +pub const TOKEN1_VAULT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; +pub fn create_token1_vault_pda( + pool_state: Address, + token1_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + TOKEN1_VAULT_SEED, + pool_state.as_ref(), + token1_mint.as_ref(), + &[bump], + ], + &RAYDIUM_CP_SWAP_ID, + ) +} +pub fn find_token1_vault_pda( + pool_state: &Address, + token1_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[TOKEN1_VAULT_SEED, pool_state.as_ref(), token1_mint.as_ref()], + &RAYDIUM_CP_SWAP_ID, + ) +} diff --git a/e2e/raydium-cpmm/src/generated/programs.rs b/e2e/raydium-cpmm/src/generated/programs.rs new file mode 100644 index 0000000..69d4d08 --- /dev/null +++ b/e2e/raydium-cpmm/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}; + +/// `raydium_cp_swap` program ID. +pub const RAYDIUM_CP_SWAP_ID: Address = address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); diff --git a/e2e/raydium-cpmm/src/generated/shared.rs b/e2e/raydium-cpmm/src/generated/shared.rs new file mode 100644 index 0000000..42eae7f --- /dev/null +++ b/e2e/raydium-cpmm/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/raydium-cpmm/src/generated/types/mod.rs b/e2e/raydium-cpmm/src/generated/types/mod.rs new file mode 100644 index 0000000..86bb676 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/types/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 r#observation; + +pub use self::r#observation::*; diff --git a/e2e/raydium-cpmm/src/generated/types/observation.rs b/e2e/raydium-cpmm/src/generated/types/observation.rs new file mode 100644 index 0000000..ce27025 --- /dev/null +++ b/e2e/raydium-cpmm/src/generated/types/observation.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// The element of observations in ObservationState +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct Observation { + /// The block timestamp of the observation + pub block_timestamp: u64, + /// the cumulative of token0 price during the duration time, Q32.32, the remaining 64 bit for overflow + pub cumulative_token0_price_x32: u128, + /// the cumulative of token1 price during the duration time, Q32.32, the remaining 64 bit for overflow + pub cumulative_token1_price_x32: u128, +} diff --git a/e2e/raydium-cpmm/src/lib.rs b/e2e/raydium-cpmm/src/lib.rs new file mode 100644 index 0000000..39f6b55 --- /dev/null +++ b/e2e/raydium-cpmm/src/lib.rs @@ -0,0 +1,4 @@ +mod generated; + +pub use generated::programs::RAYDIUM_CP_SWAP_ID as ID; +pub use generated::*; diff --git a/e2e/raydium-launchpad/Cargo.toml b/e2e/raydium-launchpad/Cargo.toml new file mode 100644 index 0000000..d1fe91c --- /dev/null +++ b/e2e/raydium-launchpad/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "codama-renderers-rust-e2e-raydium-launchpad" +version = "0.0.0" +edition = "2021" + +[features] +anchor = ["dep:anchor-lang"] +anchor-idl-build = ["anchor", "anchor-lang?/idl-build"] +test-sbf = [] +fetch = ["dep:solana-rpc-client"] + +[dependencies] +anchor-lang = { workspace = true, optional = true } +borsh = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } +solana-account = { workspace = true } +solana-account-info = { workspace = true } +solana-address = { workspace = true, features = ["borsh", "copy", "curve25519", "decode"] } +solana-rpc-client = { workspace = true, optional = true } +solana-cpi = { workspace = true } +solana-instruction = { workspace = true } +solana-program-error = { workspace = true } +thiserror = { workspace = true } diff --git a/e2e/raydium-launchpad/idl.json b/e2e/raydium-launchpad/idl.json new file mode 100644 index 0000000..a1737e6 --- /dev/null +++ b/e2e/raydium-launchpad/idl.json @@ -0,0 +1,4304 @@ +{ + "address": "LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj", + "metadata": { + "name": "raydium_launchpad", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "buy_exact_in", + "docs": [ + "Use the given amount of quote tokens to purchase base tokens.", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_in` - Amount of quote token to purchase", + "* `minimum_amount_out` - Minimum amount of base token to receive (slippage protection)", + "* `share_fee_rate` - Fee rate for the share", + "" + ], + "discriminator": [ + 250, + 234, + 13, + 123, + 213, + 156, + 19, + 236 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap operation", + "Must sign the transaction and pay for fees" + ], + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global configuration account containing protocol-wide settings", + "Used to read protocol fee rates and curve type" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform-wide settings", + "Used to read platform fee rate" + ] + }, + { + "name": "pool_state", + "docs": [ + "The pool state account where the swap will be performed", + "Contains current pool parameters and balances" + ], + "writable": true + }, + { + "name": "user_base_token", + "docs": [ + "The user's token account for base tokens (tokens being bought)", + "Will receive the output tokens after the swap" + ], + "writable": true + }, + { + "name": "user_quote_token", + "docs": [ + "The user's token account for quote tokens (tokens being sold)", + "Will be debited for the input amount" + ], + "writable": true + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be debited to send tokens to the user" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will receive the input tokens from the user" + ], + "writable": true + }, + { + "name": "base_token_mint", + "docs": [ + "The mint of the base token", + "Used for transfer fee calculations if applicable" + ] + }, + { + "name": "quote_token_mint", + "docs": [ + "The mint of the quote token" + ] + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for base token transfers" + ] + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for quote token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount_in", + "type": "u64" + }, + { + "name": "minimum_amount_out", + "type": "u64" + }, + { + "name": "share_fee_rate", + "type": "u64" + } + ] + }, + { + "name": "buy_exact_out", + "docs": [ + "Use quote tokens to purchase the given amount of base tokens.", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_out` - Amount of base token to receive", + "* `maximum_amount_in` - Maximum amount of quote token to purchase (slippage protection)", + "* `share_fee_rate` - Fee rate for the share" + ], + "discriminator": [ + 24, + 211, + 116, + 40, + 105, + 3, + 153, + 56 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap operation", + "Must sign the transaction and pay for fees" + ], + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global configuration account containing protocol-wide settings", + "Used to read protocol fee rates and curve type" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform-wide settings", + "Used to read platform fee rate" + ] + }, + { + "name": "pool_state", + "docs": [ + "The pool state account where the swap will be performed", + "Contains current pool parameters and balances" + ], + "writable": true + }, + { + "name": "user_base_token", + "docs": [ + "The user's token account for base tokens (tokens being bought)", + "Will receive the output tokens after the swap" + ], + "writable": true + }, + { + "name": "user_quote_token", + "docs": [ + "The user's token account for quote tokens (tokens being sold)", + "Will be debited for the input amount" + ], + "writable": true + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be debited to send tokens to the user" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will receive the input tokens from the user" + ], + "writable": true + }, + { + "name": "base_token_mint", + "docs": [ + "The mint of the base token", + "Used for transfer fee calculations if applicable" + ] + }, + { + "name": "quote_token_mint", + "docs": [ + "The mint of the quote token" + ] + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for base token transfers" + ] + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for quote token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount_out", + "type": "u64" + }, + { + "name": "maximum_amount_in", + "type": "u64" + }, + { + "name": "share_fee_rate", + "type": "u64" + } + ] + }, + { + "name": "claim_platform_fee", + "docs": [ + "Claim platform fee", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "" + ], + "discriminator": [ + 156, + 39, + 208, + 135, + 76, + 237, + 61, + 72 + ], + "accounts": [ + { + "name": "platform_fee_wallet", + "docs": [ + "Only the wallet stored in platform_config can collect platform fees" + ], + "writable": true, + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault and mint operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Account that stores the pool's state and parameters", + "PDA generated using POOL_SEED and both token mints" + ], + "writable": true + }, + { + "name": "platform_config", + "docs": [ + "The platform config account" + ] + }, + { + "name": "quote_vault", + "writable": true + }, + { + "name": "recipient_token_account", + "docs": [ + "The address that receives the collected quote token fees" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "platform_fee_wallet" + }, + { + "kind": "const", + "value": [ + 6, + 221, + 246, + 225, + 215, + 101, + 161, + 147, + 217, + 203, + 225, + 70, + 206, + 235, + 121, + 172, + 28, + 180, + 133, + 237, + 95, + 91, + 55, + 145, + 58, + 140, + 245, + 133, + 126, + 255, + 0, + 169 + ] + }, + { + "kind": "account", + "path": "quote_mint" + } + ], + "program": { + "kind": "const", + "value": [ + 140, + 151, + 37, + 143, + 78, + 36, + 137, + 241, + 187, + 61, + 16, + 41, + 20, + 142, + 13, + 131, + 11, + 90, + 19, + 153, + 218, + 255, + 16, + 132, + 4, + 142, + 123, + 216, + 219, + 233, + 248, + 89 + ] + } + } + }, + { + "name": "quote_mint", + "docs": [ + "The mint of quote token vault" + ] + }, + { + "name": "token_program", + "docs": [ + "SPL program for input token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "docs": [ + "Required for associated token program" + ], + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + } + ], + "args": [] + }, + { + "name": "claim_vested_token", + "docs": [ + "Claim vested token", + "# Arguments" + ], + "discriminator": [ + 49, + 33, + 104, + 30, + 189, + 157, + 79, + 35 + ], + "accounts": [ + { + "name": "beneficiary", + "docs": [ + "The beneficiary of the vesting account" + ], + "writable": true, + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault and mint operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Account that stores the pool's state and parameters", + "PDA generated using POOL_SEED and both token mints" + ], + "writable": true + }, + { + "name": "vesting_record", + "docs": [ + "The vesting record account" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 101, + 115, + 116, + 105, + 110, + 103 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "beneficiary" + } + ] + } + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be debited to send tokens to the user" + ], + "writable": true + }, + { + "name": "user_base_token", + "writable": true, + "signer": true + }, + { + "name": "base_token_mint", + "docs": [ + "The mint for the base token (token being sold)", + "Created in this instruction with specified decimals" + ] + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for the base token", + "Must be the standard Token program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "docs": [ + "Required for associated token program" + ], + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + } + ], + "args": [] + }, + { + "name": "collect_fee", + "docs": [ + "Collects accumulated fees from the pool", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "" + ], + "discriminator": [ + 60, + 173, + 247, + 103, + 4, + 93, + 130, + 48 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Only protocol_fee_owner saved in global_config can collect protocol fee now" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Pool state stores accumulated protocol fee amount" + ], + "writable": true + }, + { + "name": "global_config", + "docs": [ + "Global config account stores owner" + ] + }, + { + "name": "quote_vault", + "docs": [ + "The address that holds pool tokens for quote token" + ], + "writable": true + }, + { + "name": "quote_mint", + "docs": [ + "The mint of quote token vault" + ] + }, + { + "name": "recipient_token_account", + "docs": [ + "The address that receives the collected quote token fees" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "SPL program for input token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [] + }, + { + "name": "collect_migrate_fee", + "docs": [ + "Collects migrate fees from the pool", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "" + ], + "discriminator": [ + 255, + 186, + 150, + 223, + 235, + 118, + 201, + 186 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "Only migrate_fee_owner saved in global_config can collect migrate fee now" + ], + "signer": true + }, + { + "name": "authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Pool state stores accumulated protocol fee amount" + ], + "writable": true + }, + { + "name": "global_config", + "docs": [ + "Global config account stores owner" + ] + }, + { + "name": "quote_vault", + "docs": [ + "The address that holds pool tokens for quote token" + ], + "writable": true + }, + { + "name": "quote_mint", + "docs": [ + "The mint of quote token vault" + ] + }, + { + "name": "recipient_token_account", + "docs": [ + "The address that receives the collected quote token fees" + ], + "writable": true + }, + { + "name": "token_program", + "docs": [ + "SPL program for input token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "args": [] + }, + { + "name": "create_config", + "docs": [ + "Creates a new configuration", + "# Arguments", + "", + "* `ctx` - The accounts needed by instruction", + "* `curve_type` - The type of bonding curve (0: ConstantProduct)", + "* `index` - The index of config, there may be multiple config with the same curve type.", + "* `trade_fee_rate` - Trade fee rate, must be less than RATE_DENOMINATOR_VALUE", + "" + ], + "discriminator": [ + 201, + 207, + 243, + 114, + 75, + 111, + 47, + 189 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "The protocol owner/admin account", + "Must match the predefined admin address", + "Has authority to create and modify protocol configurations" + ], + "writable": true, + "signer": true, + "address": "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + }, + { + "name": "global_config", + "docs": [ + "Global configuration account that stores protocol-wide settings", + "PDA generated using GLOBAL_CONFIG_SEED, quote token mint, and curve type", + "Stores fee rates and protocol parameters" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "account", + "path": "quote_token_mint" + }, + { + "kind": "arg", + "path": "curve_type" + }, + { + "kind": "arg", + "path": "index" + } + ] + } + }, + { + "name": "quote_token_mint", + "docs": [ + "The mint address of the quote token (token used for buying)", + "This will be the standard token used for all pools with this config" + ] + }, + { + "name": "protocol_fee_owner", + "docs": [ + "Account that will receive protocol fees" + ] + }, + { + "name": "migrate_fee_owner", + "docs": [ + "Account that will receive migrate fees" + ] + }, + { + "name": "migrate_to_amm_wallet", + "docs": [ + "The control wallet address for migrating to amm" + ] + }, + { + "name": "migrate_to_cpswap_wallet", + "docs": [ + "The control wallet address for migrating to cpswap" + ] + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "curve_type", + "type": "u8" + }, + { + "name": "index", + "type": "u16" + }, + { + "name": "migrate_fee", + "type": "u64" + }, + { + "name": "trade_fee_rate", + "type": "u64" + } + ] + }, + { + "name": "create_platform_config", + "docs": [ + "Create platform config account", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "# Fields", + "* `fee_rate` - Fee rate of the platform", + "* `name` - Name of the platform", + "* `web` - Website of the platform", + "* `img` - Image link of the platform", + "" + ], + "discriminator": [ + 176, + 90, + 196, + 175, + 253, + 113, + 220, + 20 + ], + "accounts": [ + { + "name": "platform_admin", + "docs": [ + "The account paying for the initialization costs" + ], + "writable": true, + "signer": true + }, + { + "name": "platform_fee_wallet" + }, + { + "name": "platform_nft_wallet" + }, + { + "name": "platform_config", + "docs": [ + "The platform config account" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 108, + 97, + 116, + 102, + 111, + 114, + 109, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "account", + "path": "platform_admin" + } + ] + } + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "platform_params", + "type": { + "defined": { + "name": "PlatformParams" + } + } + } + ] + }, + { + "name": "create_vesting_account", + "docs": [ + "Create vesting account", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `share` - The share amount of base token to be vested", + "" + ], + "discriminator": [ + 129, + 178, + 2, + 13, + 217, + 172, + 230, + 218 + ], + "accounts": [ + { + "name": "creator", + "docs": [ + "The account paying for the initialization costs", + "This can be any account with sufficient SOL to cover the transaction" + ], + "writable": true, + "signer": true + }, + { + "name": "beneficiary", + "writable": true + }, + { + "name": "pool_state", + "docs": [ + "The pool state account" + ], + "writable": true + }, + { + "name": "vesting_record", + "docs": [ + "The vesting record account" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 101, + 115, + 116, + 105, + 110, + 103 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "beneficiary" + } + ] + } + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "share_amount", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "docs": [ + "Initializes a new trading pool", + "# Arguments", + "", + "* `ctx` - The context of accounts containing pool and token information", + "" + ], + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The account paying for the initialization costs", + "This can be any account with sufficient SOL to cover the transaction" + ], + "writable": true, + "signer": true + }, + { + "name": "creator" + }, + { + "name": "global_config", + "docs": [ + "Global configuration account containing protocol-wide settings", + "Includes settings like quote token mint and fee parameters" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform info", + "Includes settings like the fee_rate, name, web, img of the platform" + ] + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault and mint operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Account that stores the pool's state and parameters", + "PDA generated using POOL_SEED and both token mints" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108 + ] + }, + { + "kind": "account", + "path": "base_mint" + }, + { + "kind": "account", + "path": "quote_mint" + } + ] + } + }, + { + "name": "base_mint", + "docs": [ + "The mint for the base token (token being sold)", + "Created in this instruction with specified decimals" + ], + "writable": true, + "signer": true + }, + { + "name": "quote_mint", + "docs": [ + "The mint for the quote token (token used to buy)", + "Must match the quote_mint specified in global config" + ] + }, + { + "name": "base_vault", + "docs": [ + "Token account that holds the pool's base tokens", + "PDA generated using POOL_VAULT_SEED" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "base_mint" + } + ] + } + }, + { + "name": "quote_vault", + "docs": [ + "Token account that holds the pool's quote tokens", + "PDA generated using POOL_VAULT_SEED" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "pool_state" + }, + { + "kind": "account", + "path": "quote_mint" + } + ] + } + }, + { + "name": "metadata_account", + "docs": [ + "Account to store the base token's metadata", + "Created using Metaplex metadata program" + ], + "writable": true + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for the base token", + "Must be the standard Token program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for the quote token" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "metadata_program", + "docs": [ + "Metaplex Token Metadata program", + "Used to create metadata for the base token" + ], + "address": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "rent_program", + "docs": [ + "Required for rent exempt calculations" + ], + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "base_mint_param", + "type": { + "defined": { + "name": "MintParams" + } + } + }, + { + "name": "curve_param", + "type": { + "defined": { + "name": "CurveParams" + } + } + }, + { + "name": "vesting_param", + "type": { + "defined": { + "name": "VestingParams" + } + } + } + ] + }, + { + "name": "migrate_to_amm", + "docs": [ + "# Arguments", + "", + "* `ctx` - The context of accounts", + "" + ], + "discriminator": [ + 207, + 82, + 192, + 145, + 254, + 207, + 145, + 223 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "Only migrate_to_amm_wallet can migrate to cpswap pool", + "This signer must match the migrate_to_amm_wallet saved in global_config" + ], + "writable": true, + "signer": true + }, + { + "name": "base_mint", + "docs": [ + "The mint for the base token (token being sold)" + ] + }, + { + "name": "quote_mint", + "docs": [ + "The mint for the quote token (token used to buy)" + ] + }, + { + "name": "openbook_program", + "address": "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX" + }, + { + "name": "market", + "docs": [ + "Account created and asigned to openbook_program but not been initialized" + ], + "writable": true + }, + { + "name": "request_queue", + "docs": [ + "Account created and asigned to openbook_program but not been initialized" + ], + "writable": true + }, + { + "name": "event_queue", + "docs": [ + "Account created and asigned to openbook_program but not been initialized" + ], + "writable": true + }, + { + "name": "bids", + "docs": [ + "Account created and asigned to openbook_program but not been initialized" + ], + "writable": true + }, + { + "name": "asks", + "docs": [ + "Account created and asigned to openbook_program but not been initialized" + ], + "writable": true + }, + { + "name": "market_vault_signer" + }, + { + "name": "market_base_vault", + "docs": [ + "Token account that holds the market's base tokens" + ], + "writable": true + }, + { + "name": "market_quote_vault", + "docs": [ + "Token account that holds the market's quote tokens" + ], + "writable": true + }, + { + "name": "amm_program", + "address": "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8" + }, + { + "name": "amm_pool", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 97, + 109, + 109, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 97, + 109, + 109, + 32, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_open_orders", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 111, + 112, + 101, + 110, + 95, + 111, + 114, + 100, + 101, + 114, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_lp_mint", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_base_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 99, + 111, + 105, + 110, + 95, + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_quote_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 112, + 99, + 95, + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_target_orders", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "amm_program" + }, + { + "kind": "account", + "path": "market" + }, + { + "kind": "const", + "value": [ + 116, + 97, + 114, + 103, + 101, + 116, + 95, + 97, + 115, + 115, + 111, + 99, + 105, + 97, + 116, + 101, + 100, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_config", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 97, + 109, + 109, + 95, + 99, + 111, + 110, + 102, + 105, + 103, + 95, + 97, + 99, + 99, + 111, + 117, + 110, + 116, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "amm_program" + } + } + }, + { + "name": "amm_create_fee_destination", + "writable": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Account that stores the pool's state and parameters", + "PDA generated using POOL_SEED and both token mints" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108 + ] + }, + { + "kind": "account", + "path": "base_mint" + }, + { + "kind": "account", + "path": "quote_mint" + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global config account stores owner" + ] + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be fully drained during migration" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will be fully drained during migration" + ], + "writable": true + }, + { + "name": "pool_lp_token", + "writable": true + }, + { + "name": "spl_token_program", + "docs": [ + "SPL Token program for the base token", + "Must be the standard Token program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "associated_token_program", + "docs": [ + "Program to create an ATA for receiving fee NFT" + ], + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "rent_program", + "docs": [ + "Required for rent exempt calculations" + ], + "address": "SysvarRent111111111111111111111111111111111" + } + ], + "args": [ + { + "name": "base_lot_size", + "type": "u64" + }, + { + "name": "quote_lot_size", + "type": "u64" + }, + { + "name": "market_vault_signer_nonce", + "type": "u8" + } + ] + }, + { + "name": "migrate_to_cpswap", + "docs": [ + "# Arguments", + "", + "* `ctx` - The context of accounts", + "" + ], + "discriminator": [ + 136, + 92, + 200, + 103, + 28, + 218, + 144, + 140 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "Only migrate_to_cpswap_wallet can migrate to cpswap pool", + "This signer must match the migrate_to_cpswap_wallet saved in global_config" + ], + "writable": true, + "signer": true + }, + { + "name": "base_mint", + "docs": [ + "The mint for the base token (token being sold)" + ] + }, + { + "name": "quote_mint", + "docs": [ + "The mint for the quote token (token used to buy)" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform-wide settings", + "Used to read platform fee rate" + ] + }, + { + "name": "cpswap_program", + "address": "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C" + }, + { + "name": "cpswap_pool", + "docs": [ + "PDA account:", + "seeds = [", + "b\"pool\",", + "cpswap_config.key().as_ref(),", + "token_0_mint.key().as_ref(),", + "token_1_mint.key().as_ref(),", + "],", + "seeds::program = cpswap_program,", + "", + "Or random account: must be signed by cli" + ], + "writable": true + }, + { + "name": "cpswap_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 110, + 100, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "cpswap_program" + } + } + }, + { + "name": "cpswap_lp_mint", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 108, + 112, + 95, + 109, + 105, + 110, + 116 + ] + }, + { + "kind": "account", + "path": "cpswap_pool" + } + ], + "program": { + "kind": "account", + "path": "cpswap_program" + } + } + }, + { + "name": "cpswap_base_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "cpswap_pool" + }, + { + "kind": "account", + "path": "base_mint" + } + ], + "program": { + "kind": "account", + "path": "cpswap_program" + } + } + }, + { + "name": "cpswap_quote_vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108, + 95, + 118, + 97, + 117, + 108, + 116 + ] + }, + { + "kind": "account", + "path": "cpswap_pool" + }, + { + "kind": "account", + "path": "quote_mint" + } + ], + "program": { + "kind": "account", + "path": "cpswap_program" + } + } + }, + { + "name": "cpswap_config" + }, + { + "name": "cpswap_create_pool_fee", + "writable": true + }, + { + "name": "cpswap_observation", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 111, + 98, + 115, + 101, + 114, + 118, + 97, + 116, + 105, + 111, + 110 + ] + }, + { + "kind": "account", + "path": "cpswap_pool" + } + ], + "program": { + "kind": "account", + "path": "cpswap_program" + } + } + }, + { + "name": "lock_program", + "address": "LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE" + }, + { + "name": "lock_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 108, + 111, + 99, + 107, + 95, + 99, + 112, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121, + 95, + 115, + 101, + 101, + 100 + ] + } + ], + "program": { + "kind": "account", + "path": "lock_program" + } + } + }, + { + "name": "lock_lp_vault", + "writable": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "pool_state", + "docs": [ + "Account that stores the pool's state and parameters", + "PDA generated using POOL_SEED and both token mints" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 111, + 111, + 108 + ] + }, + { + "kind": "account", + "path": "base_mint" + }, + { + "kind": "account", + "path": "quote_mint" + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global config account stores owner" + ] + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be fully drained during migration" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will be fully drained during migration" + ], + "writable": true + }, + { + "name": "pool_lp_token", + "writable": true + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for the base token", + "Must be the standard Token program" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for the quote token" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "associated_token_program", + "docs": [ + "Program to create an ATA for receiving fee NFT" + ], + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "system_program", + "docs": [ + "Required for account creation" + ], + "address": "11111111111111111111111111111111" + }, + { + "name": "rent_program", + "docs": [ + "Required for rent exempt calculations" + ], + "address": "SysvarRent111111111111111111111111111111111" + }, + { + "name": "metadata_program", + "docs": [ + "Program to create NFT metadata accunt" + ], + "address": "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + } + ], + "args": [] + }, + { + "name": "sell_exact_in", + "docs": [ + "Use the given amount of base tokens to sell for quote tokens.", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_in` - Amount of base token to sell", + "* `minimum_amount_out` - Minimum amount of quote token to receive (slippage protection)", + "* `share_fee_rate` - Fee rate for the share", + "" + ], + "discriminator": [ + 149, + 39, + 222, + 155, + 211, + 124, + 152, + 26 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap operation", + "Must sign the transaction and pay for fees" + ], + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global configuration account containing protocol-wide settings", + "Used to read protocol fee rates and curve type" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform-wide settings", + "Used to read platform fee rate" + ] + }, + { + "name": "pool_state", + "docs": [ + "The pool state account where the swap will be performed", + "Contains current pool parameters and balances" + ], + "writable": true + }, + { + "name": "user_base_token", + "docs": [ + "The user's token account for base tokens (tokens being bought)", + "Will receive the output tokens after the swap" + ], + "writable": true + }, + { + "name": "user_quote_token", + "docs": [ + "The user's token account for quote tokens (tokens being sold)", + "Will be debited for the input amount" + ], + "writable": true + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be debited to send tokens to the user" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will receive the input tokens from the user" + ], + "writable": true + }, + { + "name": "base_token_mint", + "docs": [ + "The mint of the base token", + "Used for transfer fee calculations if applicable" + ] + }, + { + "name": "quote_token_mint", + "docs": [ + "The mint of the quote token" + ] + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for base token transfers" + ] + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for quote token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount_in", + "type": "u64" + }, + { + "name": "minimum_amount_out", + "type": "u64" + }, + { + "name": "share_fee_rate", + "type": "u64" + } + ] + }, + { + "name": "sell_exact_out", + "docs": [ + "Sell base tokens for the given amount of quote tokens.", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `amount_out` - Amount of quote token to receive", + "* `maximum_amount_in` - Maximum amount of base token to purchase (slippage protection)", + "* `share_fee_rate` - Fee rate for the share", + "" + ], + "discriminator": [ + 95, + 200, + 71, + 34, + 8, + 9, + 11, + 166 + ], + "accounts": [ + { + "name": "payer", + "docs": [ + "The user performing the swap operation", + "Must sign the transaction and pay for fees" + ], + "signer": true + }, + { + "name": "authority", + "docs": [ + "PDA that acts as the authority for pool vault operations", + "Generated using AUTH_SEED" + ], + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116, + 95, + 97, + 117, + 116, + 104, + 95, + 115, + 101, + 101, + 100 + ] + } + ] + } + }, + { + "name": "global_config", + "docs": [ + "Global configuration account containing protocol-wide settings", + "Used to read protocol fee rates and curve type" + ] + }, + { + "name": "platform_config", + "docs": [ + "Platform configuration account containing platform-wide settings", + "Used to read platform fee rate" + ] + }, + { + "name": "pool_state", + "docs": [ + "The pool state account where the swap will be performed", + "Contains current pool parameters and balances" + ], + "writable": true + }, + { + "name": "user_base_token", + "docs": [ + "The user's token account for base tokens (tokens being bought)", + "Will receive the output tokens after the swap" + ], + "writable": true + }, + { + "name": "user_quote_token", + "docs": [ + "The user's token account for quote tokens (tokens being sold)", + "Will be debited for the input amount" + ], + "writable": true + }, + { + "name": "base_vault", + "docs": [ + "The pool's vault for base tokens", + "Will be debited to send tokens to the user" + ], + "writable": true + }, + { + "name": "quote_vault", + "docs": [ + "The pool's vault for quote tokens", + "Will receive the input tokens from the user" + ], + "writable": true + }, + { + "name": "base_token_mint", + "docs": [ + "The mint of the base token", + "Used for transfer fee calculations if applicable" + ] + }, + { + "name": "quote_token_mint", + "docs": [ + "The mint of the quote token" + ] + }, + { + "name": "base_token_program", + "docs": [ + "SPL Token program for base token transfers" + ] + }, + { + "name": "quote_token_program", + "docs": [ + "SPL Token program for quote token transfers" + ], + "address": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + }, + { + "name": "event_authority", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 95, + 95, + 101, + 118, + 101, + 110, + 116, + 95, + 97, + 117, + 116, + 104, + 111, + 114, + 105, + 116, + 121 + ] + } + ] + } + }, + { + "name": "program" + } + ], + "args": [ + { + "name": "amount_out", + "type": "u64" + }, + { + "name": "maximum_amount_in", + "type": "u64" + }, + { + "name": "share_fee_rate", + "type": "u64" + } + ] + }, + { + "name": "update_config", + "docs": [ + "Updates configuration parameters", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `param` - Parameter to update:", + "- 0: Update trade_fee_rate", + "- 1: Update fee owner", + "* `value` - New value for the selected parameter", + "" + ], + "discriminator": [ + 29, + 158, + 252, + 191, + 10, + 83, + 219, + 99 + ], + "accounts": [ + { + "name": "owner", + "docs": [ + "The global config owner or admin" + ], + "signer": true, + "address": "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + }, + { + "name": "global_config", + "docs": [ + "Global config account to be changed" + ], + "writable": true + } + ], + "args": [ + { + "name": "param", + "type": "u8" + }, + { + "name": "value", + "type": "u64" + } + ] + }, + { + "name": "update_platform_config", + "docs": [ + "Update platform config", + "# Arguments", + "", + "* `ctx` - The context of accounts", + "* `param` - Parameter to update", + "" + ], + "discriminator": [ + 195, + 60, + 76, + 129, + 146, + 45, + 67, + 143 + ], + "accounts": [ + { + "name": "platform_admin", + "docs": [ + "The account paying for the initialization costs" + ], + "signer": true + }, + { + "name": "platform_config", + "docs": [ + "Platform config account to be changed" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 112, + 108, + 97, + 116, + 102, + 111, + 114, + 109, + 95, + 99, + 111, + 110, + 102, + 105, + 103 + ] + }, + { + "kind": "account", + "path": "platform_admin" + } + ] + } + } + ], + "args": [ + { + "name": "param", + "type": { + "defined": { + "name": "PlatformConfigParam" + } + } + } + ] + } + ], + "accounts": [ + { + "name": "GlobalConfig", + "discriminator": [ + 149, + 8, + 156, + 202, + 160, + 252, + 176, + 217 + ] + }, + { + "name": "PlatformConfig", + "discriminator": [ + 160, + 78, + 128, + 0, + 248, + 83, + 230, + 160 + ] + }, + { + "name": "PoolState", + "discriminator": [ + 247, + 237, + 227, + 245, + 215, + 195, + 222, + 70 + ] + }, + { + "name": "VestingRecord", + "discriminator": [ + 106, + 243, + 221, + 205, + 230, + 126, + 85, + 83 + ] + } + ], + "events": [ + { + "name": "ClaimVestedEvent", + "discriminator": [ + 21, + 194, + 114, + 87, + 120, + 211, + 226, + 32 + ] + }, + { + "name": "CreateVestingEvent", + "discriminator": [ + 150, + 152, + 11, + 179, + 52, + 210, + 191, + 125 + ] + }, + { + "name": "PoolCreateEvent", + "discriminator": [ + 151, + 215, + 226, + 9, + 118, + 161, + 115, + 174 + ] + }, + { + "name": "TradeEvent", + "discriminator": [ + 189, + 219, + 127, + 211, + 78, + 230, + 97, + 238 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "NotApproved", + "msg": "Not approved" + }, + { + "code": 6001, + "name": "InvalidOwner", + "msg": "Input account owner is not the program address" + }, + { + "code": 6002, + "name": "InvalidInput", + "msg": "InvalidInput" + }, + { + "code": 6003, + "name": "InputNotMatchCurveConfig", + "msg": "The input params are not match with curve type in config" + }, + { + "code": 6004, + "name": "ExceededSlippage", + "msg": "Exceeds desired slippage limit" + }, + { + "code": 6005, + "name": "PoolFunding", + "msg": "Pool funding" + }, + { + "code": 6006, + "name": "PoolMigrated", + "msg": "Pool migrated" + }, + { + "code": 6007, + "name": "MigrateTypeNotMatch", + "msg": "Migrate type not match" + }, + { + "code": 6008, + "name": "MathOverflow", + "msg": "Math overflow" + }, + { + "code": 6009, + "name": "NoAssetsToCollect", + "msg": "No assets to collect" + }, + { + "code": 6010, + "name": "VestingRatioTooHigh", + "msg": "Vesting ratio too high" + }, + { + "code": 6011, + "name": "VestingSettingEnded", + "msg": "Vesting setting ended" + }, + { + "code": 6012, + "name": "VestingNotStarted", + "msg": "Vesting not started" + }, + { + "code": 6013, + "name": "NoVestingSchedule", + "msg": "No vesting schedule" + }, + { + "code": 6014, + "name": "InvalidPlatformInfo", + "msg": "The platform info input is invalid" + }, + { + "code": 6015, + "name": "PoolNotMigrated", + "msg": "Pool not migrated" + } + ], + "types": [ + { + "name": "ClaimVestedEvent", + "docs": [ + "Emitted when vesting token claimed by beneficiary" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_state", + "type": "pubkey" + }, + { + "name": "beneficiary", + "type": "pubkey" + }, + { + "name": "claim_amount", + "type": "u64" + } + ] + } + }, + { + "name": "ConstantCurve", + "type": { + "kind": "struct", + "fields": [ + { + "name": "supply", + "type": "u64" + }, + { + "name": "total_base_sell", + "type": "u64" + }, + { + "name": "total_quote_fund_raising", + "type": "u64" + }, + { + "name": "migrate_type", + "type": "u8" + } + ] + } + }, + { + "name": "CreateVestingEvent", + "docs": [ + "Emitted when vest_account created" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_state", + "type": "pubkey" + }, + { + "name": "beneficiary", + "type": "pubkey" + }, + { + "name": "share_amount", + "type": "u64" + } + ] + } + }, + { + "name": "CurveParams", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Constant", + "fields": [ + { + "name": "data", + "type": { + "defined": { + "name": "ConstantCurve" + } + } + } + ] + }, + { + "name": "Fixed", + "fields": [ + { + "name": "data", + "type": { + "defined": { + "name": "FixedCurve" + } + } + } + ] + }, + { + "name": "Linear", + "fields": [ + { + "name": "data", + "type": { + "defined": { + "name": "LinearCurve" + } + } + } + ] + } + ] + } + }, + { + "name": "FixedCurve", + "type": { + "kind": "struct", + "fields": [ + { + "name": "supply", + "type": "u64" + }, + { + "name": "total_quote_fund_raising", + "type": "u64" + }, + { + "name": "migrate_type", + "type": "u8" + } + ] + } + }, + { + "name": "GlobalConfig", + "docs": [ + "Holds the current owner of the factory" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "epoch", + "docs": [ + "Account update epoch" + ], + "type": "u64" + }, + { + "name": "curve_type", + "docs": [ + "0: Constant Product Curve", + "1: Fixed Price Curve", + "2: Linear Price Curve" + ], + "type": "u8" + }, + { + "name": "index", + "docs": [ + "Config index" + ], + "type": "u16" + }, + { + "name": "migrate_fee", + "docs": [ + "The fee of migrate to amm" + ], + "type": "u64" + }, + { + "name": "trade_fee_rate", + "docs": [ + "The trade fee rate, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "max_share_fee_rate", + "docs": [ + "The maximum share fee rate, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "min_base_supply", + "docs": [ + "The minimum base supply, the value without decimals" + ], + "type": "u64" + }, + { + "name": "max_lock_rate", + "docs": [ + "The maximum lock rate, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "min_base_sell_rate", + "docs": [ + "The minimum base sell rate, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "min_base_migrate_rate", + "docs": [ + "The minimum base migrate rate, denominated in hundredths of a bip (10^-6)" + ], + "type": "u64" + }, + { + "name": "min_quote_fund_raising", + "docs": [ + "The minimum quote fund raising, the value with decimals" + ], + "type": "u64" + }, + { + "name": "quote_mint", + "docs": [ + "Mint information for quote token" + ], + "type": "pubkey" + }, + { + "name": "protocol_fee_owner", + "docs": [ + "Protocol Fee owner" + ], + "type": "pubkey" + }, + { + "name": "migrate_fee_owner", + "docs": [ + "Migrate Fee owner" + ], + "type": "pubkey" + }, + { + "name": "migrate_to_amm_wallet", + "docs": [ + "Migrate to amm control wallet" + ], + "type": "pubkey" + }, + { + "name": "migrate_to_cpswap_wallet", + "docs": [ + "Migrate to cpswap wallet" + ], + "type": "pubkey" + }, + { + "name": "padding", + "docs": [ + "padding for future updates" + ], + "type": { + "array": [ + "u64", + 16 + ] + } + } + ] + } + }, + { + "name": "LinearCurve", + "type": { + "kind": "struct", + "fields": [ + { + "name": "supply", + "type": "u64" + }, + { + "name": "total_quote_fund_raising", + "type": "u64" + }, + { + "name": "migrate_type", + "type": "u8" + } + ] + } + }, + { + "name": "MigrateNftInfo", + "docs": [ + "Represents the parameters for initializing a platform config account(Only support MigrateType::CPSWAP)", + "# Fields", + "* `platform_scale` - Scale of the platform liquidity quantity rights will be converted into NFT", + "* `creator_scale` - Scale of the token creator liquidity quantity rights will be converted into NFT", + "* `burn_scale` - Scale of liquidity directly to burn", + "", + "* platform_scale + creator_scale + burn_scale = RATE_DENOMINATOR_VALUE" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "platform_scale", + "type": "u64" + }, + { + "name": "creator_scale", + "type": "u64" + }, + { + "name": "burn_scale", + "type": "u64" + } + ] + } + }, + { + "name": "MintParams", + "docs": [ + "Represents the parameters for initializing a new token mint", + "# Fields", + "* `decimals` - Number of decimal places for the token", + "* `name` - Name of the token", + "* `symbol` - Symbol/ticker of the token", + "* `uri` - URI pointing to token metadata" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "decimals", + "type": "u8" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "symbol", + "type": "string" + }, + { + "name": "uri", + "type": "string" + } + ] + } + }, + { + "name": "PlatformConfig", + "type": { + "kind": "struct", + "fields": [ + { + "name": "epoch", + "docs": [ + "The epoch for update interval" + ], + "type": "u64" + }, + { + "name": "platform_fee_wallet", + "docs": [ + "The platform fee wallet" + ], + "type": "pubkey" + }, + { + "name": "platform_nft_wallet", + "docs": [ + "The platform nft wallet to receive the platform NFT after migration if platform_scale is not 0(Only support MigrateType::CPSWAP)" + ], + "type": "pubkey" + }, + { + "name": "platform_scale", + "docs": [ + "Scale of the platform liquidity quantity rights will be converted into NFT(Only support MigrateType::CPSWAP)" + ], + "type": "u64" + }, + { + "name": "creator_scale", + "docs": [ + "Scale of the token creator liquidity quantity rights will be converted into NFT(Only support MigrateType::CPSWAP)" + ], + "type": "u64" + }, + { + "name": "burn_scale", + "docs": [ + "Scale of liquidity directly to burn" + ], + "type": "u64" + }, + { + "name": "fee_rate", + "docs": [ + "The platform fee rate" + ], + "type": "u64" + }, + { + "name": "name", + "docs": [ + "The platform name" + ], + "type": { + "array": [ + "u8", + 64 + ] + } + }, + { + "name": "web", + "docs": [ + "The platform website" + ], + "type": { + "array": [ + "u8", + 256 + ] + } + }, + { + "name": "img", + "docs": [ + "The platform img link" + ], + "type": { + "array": [ + "u8", + 256 + ] + } + }, + { + "name": "padding", + "docs": [ + "padding for future updates" + ], + "type": { + "array": [ + "u8", + 256 + ] + } + } + ] + } + }, + { + "name": "PlatformConfigParam", + "type": { + "kind": "enum", + "variants": [ + { + "name": "FeeWallet", + "fields": [ + "pubkey" + ] + }, + { + "name": "NFTWallet", + "fields": [ + "pubkey" + ] + }, + { + "name": "MigrateNftInfo", + "fields": [ + { + "defined": { + "name": "MigrateNftInfo" + } + } + ] + }, + { + "name": "FeeRate", + "fields": [ + "u64" + ] + }, + { + "name": "Name", + "fields": [ + "string" + ] + }, + { + "name": "Web", + "fields": [ + "string" + ] + }, + { + "name": "Img", + "fields": [ + "string" + ] + } + ] + } + }, + { + "name": "PlatformParams", + "docs": [ + "Represents the parameters for initializing a platform config account", + "# Fields", + "* `migrate_nft_info` - The platform configures liquidity info during migration(Only support MigrateType::CPSWAP)", + "* `fee_rate` - Fee rate of the platform", + "* `name` - Name of the platform", + "* `web` - Website of the platform", + "* `img` - Image link of the platform" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "migrate_nft_info", + "type": { + "defined": { + "name": "MigrateNftInfo" + } + } + }, + { + "name": "fee_rate", + "type": "u64" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "web", + "type": "string" + }, + { + "name": "img", + "type": "string" + } + ] + } + }, + { + "name": "PoolCreateEvent", + "docs": [ + "Emitted when pool created" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_state", + "type": "pubkey" + }, + { + "name": "creator", + "type": "pubkey" + }, + { + "name": "config", + "type": "pubkey" + }, + { + "name": "base_mint_param", + "type": { + "defined": { + "name": "MintParams" + } + } + }, + { + "name": "curve_param", + "type": { + "defined": { + "name": "CurveParams" + } + } + }, + { + "name": "vesting_param", + "type": { + "defined": { + "name": "VestingParams" + } + } + } + ] + } + }, + { + "name": "PoolState", + "docs": [ + "Represents the state of a trading pool in the protocol", + "Stores all essential information about pool balances, fees, and configuration" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "epoch", + "docs": [ + "Account update epoch" + ], + "type": "u64" + }, + { + "name": "auth_bump", + "docs": [ + "Bump seed used for PDA address derivation" + ], + "type": "u8" + }, + { + "name": "status", + "docs": [ + "Current status of the pool", + "* 0: Pool is funding", + "* 1: Pool funding is end, waiting for migration", + "* 2: Pool migration is done" + ], + "type": "u8" + }, + { + "name": "base_decimals", + "docs": [ + "Decimals of the pool base token" + ], + "type": "u8" + }, + { + "name": "quote_decimals", + "docs": [ + "Decimals of the pool quote token" + ], + "type": "u8" + }, + { + "name": "migrate_type", + "docs": [ + "Migrate to AMM or CpSwap" + ], + "type": "u8" + }, + { + "name": "supply", + "docs": [ + "Supply of the pool base token" + ], + "type": "u64" + }, + { + "name": "total_base_sell", + "docs": [ + "Total sell amount of the base token" + ], + "type": "u64" + }, + { + "name": "virtual_base", + "docs": [ + "For different curves, virtual_base and virtual_quote have different meanings", + "For constant product curve, virtual_base and virtual_quote are virtual liquidity, virtual_quote/virtual_base is the initial price", + "For linear price curve, virtual_base is the price slope parameter a, virtual_quote has no effect", + "For fixed price curve, virtual_quote/virtual_base is the initial price" + ], + "type": "u64" + }, + { + "name": "virtual_quote", + "type": "u64" + }, + { + "name": "real_base", + "docs": [ + "Actual base token amount in the pool", + "Represents the real tokens available for trading" + ], + "type": "u64" + }, + { + "name": "real_quote", + "docs": [ + "Actual quote token amount in the pool", + "Represents the real tokens available for trading" + ], + "type": "u64" + }, + { + "name": "total_quote_fund_raising", + "docs": [ + "The total quote fund raising of the pool" + ], + "type": "u64" + }, + { + "name": "quote_protocol_fee", + "docs": [ + "Accumulated trading fees in quote tokens", + "Can be collected by the protocol fee owner" + ], + "type": "u64" + }, + { + "name": "platform_fee", + "docs": [ + "Accumulated platform fees in quote tokens", + "Can be collected by the platform wallet stored in platform config" + ], + "type": "u64" + }, + { + "name": "migrate_fee", + "docs": [ + "The fee of migrate to amm" + ], + "type": "u64" + }, + { + "name": "vesting_schedule", + "docs": [ + "Vesting schedule for the base token" + ], + "type": { + "defined": { + "name": "VestingSchedule" + } + } + }, + { + "name": "global_config", + "docs": [ + "Public key of the global configuration account", + "Contains protocol-wide settings this pool adheres to" + ], + "type": "pubkey" + }, + { + "name": "platform_config", + "docs": [ + "Public key of the platform configuration account", + "Contains platform-wide settings this pool adheres to" + ], + "type": "pubkey" + }, + { + "name": "base_mint", + "docs": [ + "Public key of the base mint address" + ], + "type": "pubkey" + }, + { + "name": "quote_mint", + "docs": [ + "Public key of the quote mint address" + ], + "type": "pubkey" + }, + { + "name": "base_vault", + "docs": [ + "Public key of the base token vault", + "Holds the actual base tokens owned by the pool" + ], + "type": "pubkey" + }, + { + "name": "quote_vault", + "docs": [ + "Public key of the quote token vault", + "Holds the actual quote tokens owned by the pool" + ], + "type": "pubkey" + }, + { + "name": "creator", + "docs": [ + "The creator of base token" + ], + "type": "pubkey" + }, + { + "name": "padding", + "docs": [ + "padding for future updates" + ], + "type": { + "array": [ + "u64", + 8 + ] + } + } + ] + } + }, + { + "name": "PoolStatus", + "docs": [ + "Represents the different states a pool can be in", + "* Fund - Initial state where pool is accepting funds", + "* Migrate - Pool funding has ended and waiting for migration", + "* Trade - Pool migration is complete and amm trading is enabled" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Fund" + }, + { + "name": "Migrate" + }, + { + "name": "Trade" + } + ] + } + }, + { + "name": "TradeDirection", + "docs": [ + "Specifies the direction of a trade in the bonding curve", + "This is important because curves can treat tokens differently through weights or offsets" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Buy" + }, + { + "name": "Sell" + } + ] + } + }, + { + "name": "TradeEvent", + "docs": [ + "Emitted when trade process" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "pool_state", + "type": "pubkey" + }, + { + "name": "total_base_sell", + "type": "u64" + }, + { + "name": "virtual_base", + "type": "u64" + }, + { + "name": "virtual_quote", + "type": "u64" + }, + { + "name": "real_base_before", + "type": "u64" + }, + { + "name": "real_quote_before", + "type": "u64" + }, + { + "name": "real_base_after", + "type": "u64" + }, + { + "name": "real_quote_after", + "type": "u64" + }, + { + "name": "amount_in", + "type": "u64" + }, + { + "name": "amount_out", + "type": "u64" + }, + { + "name": "protocol_fee", + "type": "u64" + }, + { + "name": "platform_fee", + "type": "u64" + }, + { + "name": "share_fee", + "type": "u64" + }, + { + "name": "trade_direction", + "type": { + "defined": { + "name": "TradeDirection" + } + } + }, + { + "name": "pool_status", + "type": { + "defined": { + "name": "PoolStatus" + } + } + } + ] + } + }, + { + "name": "VestingParams", + "type": { + "kind": "struct", + "fields": [ + { + "name": "total_locked_amount", + "type": "u64" + }, + { + "name": "cliff_period", + "type": "u64" + }, + { + "name": "unlock_period", + "type": "u64" + } + ] + } + }, + { + "name": "VestingRecord", + "type": { + "kind": "struct", + "fields": [ + { + "name": "epoch", + "docs": [ + "Account update epoch" + ], + "type": "u64" + }, + { + "name": "pool", + "docs": [ + "The pool state account" + ], + "type": "pubkey" + }, + { + "name": "beneficiary", + "docs": [ + "The beneficiary of the vesting account" + ], + "type": "pubkey" + }, + { + "name": "claimed_amount", + "docs": [ + "The amount of tokens claimed" + ], + "type": "u64" + }, + { + "name": "token_share_amount", + "docs": [ + "The share amount of the token to be vested" + ], + "type": "u64" + }, + { + "name": "padding", + "docs": [ + "padding for future updates" + ], + "type": { + "array": [ + "u64", + 8 + ] + } + } + ] + } + }, + { + "name": "VestingSchedule", + "type": { + "kind": "struct", + "fields": [ + { + "name": "total_locked_amount", + "type": "u64" + }, + { + "name": "cliff_period", + "type": "u64" + }, + { + "name": "unlock_period", + "type": "u64" + }, + { + "name": "start_time", + "type": "u64" + }, + { + "name": "allocated_share_amount", + "docs": [ + "Total allocated share amount of the base token, not greater than total_locked_amount" + ], + "type": "u64" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/e2e/raydium-launchpad/src/generated/accounts/global_config.rs b/e2e/raydium-launchpad/src/generated/accounts/global_config.rs new file mode 100644 index 0000000..6128119 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/accounts/global_config.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct GlobalConfig { + pub discriminator: [u8; 8], + /// Account update epoch + pub epoch: u64, + /// 0: Constant Product Curve + /// 1: Fixed Price Curve + /// 2: Linear Price Curve + pub curve_type: u8, + /// Config index + pub index: u16, + /// The fee of migrate to amm + pub migrate_fee: u64, + /// The trade fee rate, denominated in hundredths of a bip (10^-6) + pub trade_fee_rate: u64, + /// The maximum share fee rate, denominated in hundredths of a bip (10^-6) + pub max_share_fee_rate: u64, + /// The minimum base supply, the value without decimals + pub min_base_supply: u64, + /// The maximum lock rate, denominated in hundredths of a bip (10^-6) + pub max_lock_rate: u64, + /// The minimum base sell rate, denominated in hundredths of a bip (10^-6) + pub min_base_sell_rate: u64, + /// The minimum base migrate rate, denominated in hundredths of a bip (10^-6) + pub min_base_migrate_rate: u64, + /// The minimum quote fund raising, the value with decimals + pub min_quote_fund_raising: u64, + /// Mint information for quote token + pub quote_mint: Address, + /// Protocol Fee owner + pub protocol_fee_owner: Address, + /// Migrate Fee owner + pub migrate_fee_owner: Address, + /// Migrate to amm control wallet + pub migrate_to_amm_wallet: Address, + /// Migrate to cpswap wallet + pub migrate_to_cpswap_wallet: Address, + /// padding for future updates + pub padding: [u64; 16], +} + +pub const GLOBAL_CONFIG_DISCRIMINATOR: [u8; 8] = [149, 8, 156, 202, 160, 252, 176, 217]; + +impl GlobalConfig { + pub const LEN: usize = 371; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..GLOBAL_CONFIG_DISCRIMINATOR.len()) != Some(&GLOBAL_CONFIG_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for GlobalConfig { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_LAUNCHPAD_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_global_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_global_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_global_config( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GlobalConfig::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_global_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_global_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_global_config( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = GlobalConfig::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 GlobalConfig { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < GLOBAL_CONFIG_DISCRIMINATOR.len() + || buf[..GLOBAL_CONFIG_DISCRIMINATOR.len()] != GLOBAL_CONFIG_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for GlobalConfig {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for GlobalConfig { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_LAUNCHPAD_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for GlobalConfig {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for GlobalConfig { + const DISCRIMINATOR: &[u8] = &GLOBAL_CONFIG_DISCRIMINATOR; +} diff --git a/e2e/raydium-launchpad/src/generated/accounts/mod.rs b/e2e/raydium-launchpad/src/generated/accounts/mod.rs new file mode 100644 index 0000000..1ea8d75 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/accounts/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(crate) mod r#global_config; +pub(crate) mod r#platform_config; +pub(crate) mod r#pool_state; +pub(crate) mod r#vesting_record; + +pub use self::r#global_config::*; +pub use self::r#platform_config::*; +pub use self::r#pool_state::*; +pub use self::r#vesting_record::*; diff --git a/e2e/raydium-launchpad/src/generated/accounts/platform_config.rs b/e2e/raydium-launchpad/src/generated/accounts/platform_config.rs new file mode 100644 index 0000000..cdcd80f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/accounts/platform_config.rs @@ -0,0 +1,185 @@ +//! 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 PlatformConfig { + pub discriminator: [u8; 8], + /// The epoch for update interval + pub epoch: u64, + /// The platform fee wallet + pub platform_fee_wallet: Address, + /// The platform nft wallet to receive the platform NFT after migration if platform_scale is not 0(Only support MigrateType::CPSWAP) + pub platform_nft_wallet: Address, + /// Scale of the platform liquidity quantity rights will be converted into NFT(Only support MigrateType::CPSWAP) + pub platform_scale: u64, + /// Scale of the token creator liquidity quantity rights will be converted into NFT(Only support MigrateType::CPSWAP) + pub creator_scale: u64, + /// Scale of liquidity directly to burn + pub burn_scale: u64, + /// The platform fee rate + pub fee_rate: u64, + /// The platform name + pub name: [u8; 64], + /// The platform website + pub web: [u8; 256], + /// The platform img link + pub img: [u8; 256], + /// padding for future updates + pub padding: [u8; 256], +} + +pub const PLATFORM_CONFIG_DISCRIMINATOR: [u8; 8] = [160, 78, 128, 0, 248, 83, 230, 160]; + +impl PlatformConfig { + pub const LEN: usize = 944; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..PLATFORM_CONFIG_DISCRIMINATOR.len()) + != Some(&PLATFORM_CONFIG_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for PlatformConfig { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_LAUNCHPAD_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_platform_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_platform_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_platform_config( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PlatformConfig::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_platform_config( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_platform_config(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_platform_config( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PlatformConfig::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 PlatformConfig { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < PLATFORM_CONFIG_DISCRIMINATOR.len() + || buf[..PLATFORM_CONFIG_DISCRIMINATOR.len()] != PLATFORM_CONFIG_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for PlatformConfig {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for PlatformConfig { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_LAUNCHPAD_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for PlatformConfig {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for PlatformConfig { + const DISCRIMINATOR: &[u8] = &PLATFORM_CONFIG_DISCRIMINATOR; +} diff --git a/e2e/raydium-launchpad/src/generated/accounts/pool_state.rs b/e2e/raydium-launchpad/src/generated/accounts/pool_state.rs new file mode 100644 index 0000000..9cf430e --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/accounts/pool_state.rs @@ -0,0 +1,225 @@ +//! 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::VestingSchedule; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct PoolState { + pub discriminator: [u8; 8], + /// Account update epoch + pub epoch: u64, + /// Bump seed used for PDA address derivation + pub auth_bump: u8, + /// Current status of the pool + /// * 0: Pool is funding + /// * 1: Pool funding is end, waiting for migration + /// * 2: Pool migration is done + pub status: u8, + /// Decimals of the pool base token + pub base_decimals: u8, + /// Decimals of the pool quote token + pub quote_decimals: u8, + /// Migrate to AMM or CpSwap + pub migrate_type: u8, + /// Supply of the pool base token + pub supply: u64, + /// Total sell amount of the base token + pub total_base_sell: u64, + /// For different curves, virtual_base and virtual_quote have different meanings + /// For constant product curve, virtual_base and virtual_quote are virtual liquidity, virtual_quote/virtual_base is the initial price + /// For linear price curve, virtual_base is the price slope parameter a, virtual_quote has no effect + /// For fixed price curve, virtual_quote/virtual_base is the initial price + pub virtual_base: u64, + pub virtual_quote: u64, + /// Actual base token amount in the pool + /// Represents the real tokens available for trading + pub real_base: u64, + /// Actual quote token amount in the pool + /// Represents the real tokens available for trading + pub real_quote: u64, + /// The total quote fund raising of the pool + pub total_quote_fund_raising: u64, + /// Accumulated trading fees in quote tokens + /// Can be collected by the protocol fee owner + pub quote_protocol_fee: u64, + /// Accumulated platform fees in quote tokens + /// Can be collected by the platform wallet stored in platform config + pub platform_fee: u64, + /// The fee of migrate to amm + pub migrate_fee: u64, + /// Vesting schedule for the base token + pub vesting_schedule: VestingSchedule, + /// Public key of the global configuration account + /// Contains protocol-wide settings this pool adheres to + pub global_config: Address, + /// Public key of the platform configuration account + /// Contains platform-wide settings this pool adheres to + pub platform_config: Address, + /// Public key of the base mint address + pub base_mint: Address, + /// Public key of the quote mint address + pub quote_mint: Address, + /// Public key of the base token vault + /// Holds the actual base tokens owned by the pool + pub base_vault: Address, + /// Public key of the quote token vault + /// Holds the actual quote tokens owned by the pool + pub quote_vault: Address, + /// The creator of base token + pub creator: Address, + /// padding for future updates + pub padding: [u64; 8], +} + +pub const POOL_STATE_DISCRIMINATOR: [u8; 8] = [247, 237, 227, 245, 215, 195, 222, 70]; + +impl PoolState { + pub const LEN: usize = 429; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..POOL_STATE_DISCRIMINATOR.len()) != Some(&POOL_STATE_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for PoolState { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_LAUNCHPAD_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_pool_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_pool_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_pool_state( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PoolState::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_pool_state( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_pool_state(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_pool_state( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = PoolState::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 PoolState { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < POOL_STATE_DISCRIMINATOR.len() + || buf[..POOL_STATE_DISCRIMINATOR.len()] != POOL_STATE_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for PoolState {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for PoolState { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_LAUNCHPAD_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for PoolState {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for PoolState { + const DISCRIMINATOR: &[u8] = &POOL_STATE_DISCRIMINATOR; +} diff --git a/e2e/raydium-launchpad/src/generated/accounts/vesting_record.rs b/e2e/raydium-launchpad/src/generated/accounts/vesting_record.rs new file mode 100644 index 0000000..3d28466 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/accounts/vesting_record.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct VestingRecord { + pub discriminator: [u8; 8], + /// Account update epoch + pub epoch: u64, + /// The pool state account + pub pool: Address, + /// The beneficiary of the vesting account + pub beneficiary: Address, + /// The amount of tokens claimed + pub claimed_amount: u64, + /// The share amount of the token to be vested + pub token_share_amount: u64, + /// padding for future updates + pub padding: [u64; 8], +} + +pub const VESTING_RECORD_DISCRIMINATOR: [u8; 8] = [106, 243, 221, 205, 230, 126, 85, 83]; + +impl VestingRecord { + pub const LEN: usize = 160; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..VESTING_RECORD_DISCRIMINATOR.len()) != Some(&VESTING_RECORD_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid account discriminator", + )); + } + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_account_info::AccountInfo<'a>> for VestingRecord { + type Error = std::io::Error; + + fn try_from(account_info: &solana_account_info::AccountInfo<'a>) -> Result { + if account_info.owner != &crate::RAYDIUM_LAUNCHPAD_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_vesting_record( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_vesting_record(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_vesting_record( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VestingRecord::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_vesting_record( + rpc: &solana_rpc_client::rpc_client::RpcClient, + address: &solana_address::Address, +) -> Result, std::io::Error> { + let accounts = fetch_all_maybe_vesting_record(rpc, &[*address])?; + Ok(accounts[0].clone()) +} + +#[cfg(feature = "fetch")] +pub fn fetch_all_maybe_vesting_record( + rpc: &solana_rpc_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::RAYDIUM_LAUNCHPAD_ID { + return Err(std::io::Error::other(format!( + "Invalid owner for account: {address}" + ))); + } + let data = VestingRecord::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 VestingRecord { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < VESTING_RECORD_DISCRIMINATOR.len() + || buf[..VESTING_RECORD_DISCRIMINATOR.len()] != VESTING_RECORD_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)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for VestingRecord {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for VestingRecord { + fn owner() -> anchor_lang::solana_program::pubkey::Pubkey { + anchor_lang::solana_program::pubkey::Pubkey::from(crate::RAYDIUM_LAUNCHPAD_ID.to_bytes()) + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for VestingRecord {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for VestingRecord { + const DISCRIMINATOR: &[u8] = &VESTING_RECORD_DISCRIMINATOR; +} diff --git a/e2e/raydium-launchpad/src/generated/errors/mod.rs b/e2e/raydium-launchpad/src/generated/errors/mod.rs new file mode 100644 index 0000000..60a45b0 --- /dev/null +++ b/e2e/raydium-launchpad/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 raydium_launchpad; + +pub use self::raydium_launchpad::RaydiumLaunchpadError; diff --git a/e2e/raydium-launchpad/src/generated/errors/raydium_launchpad.rs b/e2e/raydium-launchpad/src/generated/errors/raydium_launchpad.rs new file mode 100644 index 0000000..f57d1d3 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/errors/raydium_launchpad.rs @@ -0,0 +1,67 @@ +//! 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 RaydiumLaunchpadError { + /// 6000 - Not approved + #[error("Not approved")] + NotApproved = 0x1770, + /// 6001 - Input account owner is not the program address + #[error("Input account owner is not the program address")] + InvalidOwner = 0x1771, + /// 6002 - InvalidInput + #[error("InvalidInput")] + InvalidInput = 0x1772, + /// 6003 - The input params are not match with curve type in config + #[error("The input params are not match with curve type in config")] + InputNotMatchCurveConfig = 0x1773, + /// 6004 - Exceeds desired slippage limit + #[error("Exceeds desired slippage limit")] + ExceededSlippage = 0x1774, + /// 6005 - Pool funding + #[error("Pool funding")] + PoolFunding = 0x1775, + /// 6006 - Pool migrated + #[error("Pool migrated")] + PoolMigrated = 0x1776, + /// 6007 - Migrate type not match + #[error("Migrate type not match")] + MigrateTypeNotMatch = 0x1777, + /// 6008 - Math overflow + #[error("Math overflow")] + MathOverflow = 0x1778, + /// 6009 - No assets to collect + #[error("No assets to collect")] + NoAssetsToCollect = 0x1779, + /// 6010 - Vesting ratio too high + #[error("Vesting ratio too high")] + VestingRatioTooHigh = 0x177A, + /// 6011 - Vesting setting ended + #[error("Vesting setting ended")] + VestingSettingEnded = 0x177B, + /// 6012 - Vesting not started + #[error("Vesting not started")] + VestingNotStarted = 0x177C, + /// 6013 - No vesting schedule + #[error("No vesting schedule")] + NoVestingSchedule = 0x177D, + /// 6014 - The platform info input is invalid + #[error("The platform info input is invalid")] + InvalidPlatformInfo = 0x177E, + /// 6015 - Pool not migrated + #[error("Pool not migrated")] + PoolNotMigrated = 0x177F, +} + +impl From for solana_program_error::ProgramError { + fn from(e: RaydiumLaunchpadError) -> Self { + solana_program_error::ProgramError::Custom(e as u32) + } +} diff --git a/e2e/raydium-launchpad/src/generated/events/claim_vested_event.rs b/e2e/raydium-launchpad/src/generated/events/claim_vested_event.rs new file mode 100644 index 0000000..2fc1577 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/claim_vested_event.rs @@ -0,0 +1,43 @@ +//! 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::events::ANCHOR_EVENT_CPI_DISCRIMINATOR; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ClaimVestedEvent { + pub pool_state: Address, + pub beneficiary: Address, + pub claim_amount: u64, +} + +pub const CLAIM_VESTED_EVENT_DISCRIMINATOR: [u8; 8] = [21, 194, 114, 87, 120, 211, 226, 32]; + +impl ClaimVestedEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) + != Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + if data.get(8..16) != Some(&CLAIM_VESTED_EVENT_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + CLAIM_VESTED_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-launchpad/src/generated/events/create_vesting_event.rs b/e2e/raydium-launchpad/src/generated/events/create_vesting_event.rs new file mode 100644 index 0000000..f38edfe --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/create_vesting_event.rs @@ -0,0 +1,43 @@ +//! 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::events::ANCHOR_EVENT_CPI_DISCRIMINATOR; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateVestingEvent { + pub pool_state: Address, + pub beneficiary: Address, + pub share_amount: u64, +} + +pub const CREATE_VESTING_EVENT_DISCRIMINATOR: [u8; 8] = [150, 152, 11, 179, 52, 210, 191, 125]; + +impl CreateVestingEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) + != Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + if data.get(8..16) != Some(&CREATE_VESTING_EVENT_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + CREATE_VESTING_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-launchpad/src/generated/events/mod.rs b/e2e/raydium-launchpad/src/generated/events/mod.rs new file mode 100644 index 0000000..f6bb9ee --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/mod.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. +//! +//! +//! + +pub(crate) mod r#claim_vested_event; +pub(crate) mod r#create_vesting_event; +pub(crate) mod r#pool_create_event; +pub(crate) mod r#raydium_launchpad_events; +pub(crate) mod r#trade_event; + +pub use self::r#claim_vested_event::*; +pub use self::r#create_vesting_event::*; +pub use self::r#pool_create_event::*; +pub use self::r#raydium_launchpad_events::*; +pub use self::r#trade_event::*; diff --git a/e2e/raydium-launchpad/src/generated/events/pool_create_event.rs b/e2e/raydium-launchpad/src/generated/events/pool_create_event.rs new file mode 100644 index 0000000..e0cd74f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/pool_create_event.rs @@ -0,0 +1,49 @@ +//! 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::events::ANCHOR_EVENT_CPI_DISCRIMINATOR; +use crate::generated::types::CurveParams; +use crate::generated::types::MintParams; +use crate::generated::types::VestingParams; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct PoolCreateEvent { + pub pool_state: Address, + pub creator: Address, + pub config: Address, + pub base_mint_param: MintParams, + pub curve_param: CurveParams, + pub vesting_param: VestingParams, +} + +pub const POOL_CREATE_EVENT_DISCRIMINATOR: [u8; 8] = [151, 215, 226, 9, 118, 161, 115, 174]; + +impl PoolCreateEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) + != Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + if data.get(8..16) != Some(&POOL_CREATE_EVENT_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + POOL_CREATE_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-launchpad/src/generated/events/raydium_launchpad_events.rs b/e2e/raydium-launchpad/src/generated/events/raydium_launchpad_events.rs new file mode 100644 index 0000000..c88b64f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/raydium_launchpad_events.rs @@ -0,0 +1,93 @@ +//! 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::events::ClaimVestedEvent; +use crate::generated::events::CreateVestingEvent; +use crate::generated::events::PoolCreateEvent; +use crate::generated::events::TradeEvent; +use crate::generated::events::CLAIM_VESTED_EVENT_DISCRIMINATOR; +use crate::generated::events::CREATE_VESTING_EVENT_DISCRIMINATOR; +use crate::generated::events::POOL_CREATE_EVENT_DISCRIMINATOR; +use crate::generated::events::TRADE_EVENT_DISCRIMINATOR; +use borsh::BorshDeserialize; + +/// Shared event-framing tag prepended to every framed event emitted by the +/// `raydium_launchpad` program. +pub const ANCHOR_EVENT_CPI_DISCRIMINATOR: [u8; 8] = [228, 69, 165, 46, 81, 203, 154, 29]; + +/// Event kinds for the `raydium_launchpad` program. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum RaydiumLaunchpadEventKind { + ClaimVestedEvent, + CreateVestingEvent, + PoolCreateEvent, + TradeEvent, +} + +/// Identifies a `raydium_launchpad` event from the provided data. +pub fn identify_raydium_launchpad_event(data: &[u8]) -> Option { + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) == Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + && data.get(8..16) == Some(&CLAIM_VESTED_EVENT_DISCRIMINATOR[..]) + { + return Some(RaydiumLaunchpadEventKind::ClaimVestedEvent); + } + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) == Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + && data.get(8..16) == Some(&CREATE_VESTING_EVENT_DISCRIMINATOR[..]) + { + return Some(RaydiumLaunchpadEventKind::CreateVestingEvent); + } + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) == Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + && data.get(8..16) == Some(&POOL_CREATE_EVENT_DISCRIMINATOR[..]) + { + return Some(RaydiumLaunchpadEventKind::PoolCreateEvent); + } + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) == Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + && data.get(8..16) == Some(&TRADE_EVENT_DISCRIMINATOR[..]) + { + return Some(RaydiumLaunchpadEventKind::TradeEvent); + } + None +} + +/// Parsed event variants for the `raydium_launchpad` program. +#[derive(Clone, Debug, PartialEq)] +pub enum RaydiumLaunchpadEvent { + ClaimVestedEvent(ClaimVestedEvent), + CreateVestingEvent(CreateVestingEvent), + PoolCreateEvent(PoolCreateEvent), + TradeEvent(TradeEvent), +} + +/// Tries to parse a `raydium_launchpad` event from the provided data. +pub fn try_parse_raydium_launchpad_event( + data: &[u8], +) -> Option> { + let event_kind = identify_raydium_launchpad_event(data)?; + Some(match event_kind { + RaydiumLaunchpadEventKind::ClaimVestedEvent => { + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + CLAIM_VESTED_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + ClaimVestedEvent::deserialize(&mut data).map(RaydiumLaunchpadEvent::ClaimVestedEvent) + } + RaydiumLaunchpadEventKind::CreateVestingEvent => { + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + CREATE_VESTING_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + CreateVestingEvent::deserialize(&mut data) + .map(RaydiumLaunchpadEvent::CreateVestingEvent) + } + RaydiumLaunchpadEventKind::PoolCreateEvent => { + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + POOL_CREATE_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + PoolCreateEvent::deserialize(&mut data).map(RaydiumLaunchpadEvent::PoolCreateEvent) + } + RaydiumLaunchpadEventKind::TradeEvent => { + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + TRADE_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + TradeEvent::deserialize(&mut data).map(RaydiumLaunchpadEvent::TradeEvent) + } + }) +} diff --git a/e2e/raydium-launchpad/src/generated/events/trade_event.rs b/e2e/raydium-launchpad/src/generated/events/trade_event.rs new file mode 100644 index 0000000..a0f57f6 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/events/trade_event.rs @@ -0,0 +1,57 @@ +//! 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::events::ANCHOR_EVENT_CPI_DISCRIMINATOR; +use crate::generated::types::PoolStatus; +use crate::generated::types::TradeDirection; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct TradeEvent { + pub pool_state: Address, + pub total_base_sell: u64, + pub virtual_base: u64, + pub virtual_quote: u64, + pub real_base_before: u64, + pub real_quote_before: u64, + pub real_base_after: u64, + pub real_quote_after: u64, + pub amount_in: u64, + pub amount_out: u64, + pub protocol_fee: u64, + pub platform_fee: u64, + pub share_fee: u64, + pub trade_direction: TradeDirection, + pub pool_status: PoolStatus, +} + +pub const TRADE_EVENT_DISCRIMINATOR: [u8; 8] = [189, 219, 127, 211, 78, 230, 97, 238]; + +impl TradeEvent { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + if data.get(..ANCHOR_EVENT_CPI_DISCRIMINATOR.len()) + != Some(&ANCHOR_EVENT_CPI_DISCRIMINATOR[..]) + { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + if data.get(8..16) != Some(&TRADE_EVENT_DISCRIMINATOR[..]) { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } + // ANCHOR_EVENT_CPI_DISCRIMINATOR (8) + TRADE_EVENT_DISCRIMINATOR (8) + let mut data = &data[16..]; + Self::deserialize(&mut data) + } +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/buy_exact_in.rs b/e2e/raydium-launchpad/src/generated/instructions/buy_exact_in.rs new file mode 100644 index 0000000..0e58cb4 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/buy_exact_in.rs @@ -0,0 +1,746 @@ +//! 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 BUY_EXACT_IN_DISCRIMINATOR: [u8; 8] = [250, 234, 13, 123, 213, 156, 19, 236]; + +/// Accounts. +#[derive(Debug)] +pub struct BuyExactIn { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: solana_address::Address, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: solana_address::Address, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: solana_address::Address, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: solana_address::Address, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: solana_address::Address, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: solana_address::Address, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: solana_address::Address, + /// The mint of the quote token + pub quote_token_mint: solana_address::Address, + /// SPL Token program for base token transfers + pub base_token_program: solana_address::Address, + /// SPL Token program for quote token transfers + pub quote_token_program: solana_address::Address, + + pub event_authority: solana_address::Address, + + pub program: solana_address::Address, +} + +impl BuyExactIn { + pub fn instruction(&self, args: BuyExactInInstructionArgs) -> 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: BuyExactInInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.user_base_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.user_quote_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.event_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = BuyExactInInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct BuyExactInInstructionData { + discriminator: [u8; 8], +} + +impl BuyExactInInstructionData { + pub fn new() -> Self { + Self { + discriminator: [250, 234, 13, 123, 213, 156, 19, 236], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for BuyExactInInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct BuyExactInInstructionArgs { + pub amount_in: u64, + pub minimum_amount_out: u64, + pub share_fee_rate: u64, +} + +impl BuyExactInInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `BuyExactIn`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 13. `[optional]` event_authority (default to PDA derived from 'eventAuthority') +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct BuyExactInBuilder { + payer: solana_address::Address, + authority: Option, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + quote_token_program: Option, + event_authority: Option, + program: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + __remaining_accounts: Vec, +} + +impl BuyExactInBuilder { + pub fn new( + payer: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + program: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + ) -> Self { + Self { + payer, + authority: None, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program: None, + event_authority: None, + program, + amount_in, + minimum_amount_out, + share_fee_rate, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for quote token transfers + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to PDA derived from 'eventAuthority']` + #[inline(always)] + pub fn event_authority(&mut self, event_authority: solana_address::Address) -> &mut Self { + self.event_authority = Some(event_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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let global_config = self.global_config; + let platform_config = self.platform_config; + let pool_state = self.pool_state; + let user_base_token = self.user_base_token; + let user_quote_token = self.user_quote_token; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let base_token_mint = self.base_token_mint; + let quote_token_mint = self.quote_token_mint; + let base_token_program = self.base_token_program; + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let event_authority = self + .event_authority + .unwrap_or(crate::pdas::EVENT_AUTHORITY_ADDRESS); + let program = self.program; + let accounts = BuyExactIn { + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + }; + let args = BuyExactInInstructionArgs { + amount_in: self.amount_in.clone(), + minimum_amount_out: self.minimum_amount_out.clone(), + share_fee_rate: self.share_fee_rate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `buy_exact_in` CPI accounts. +pub struct BuyExactInCpiAccounts<'a, 'b> { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `buy_exact_in` CPI instruction. +pub struct BuyExactInCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: BuyExactInInstructionArgs, +} + +impl<'a, 'b> BuyExactInCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: BuyExactInCpiAccounts<'a, 'b>, + args: BuyExactInInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + global_config: accounts.global_config, + platform_config: accounts.platform_config, + pool_state: accounts.pool_state, + user_base_token: accounts.user_base_token, + user_quote_token: accounts.user_quote_token, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + base_token_mint: accounts.base_token_mint, + quote_token_mint: accounts.quote_token_mint, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + event_authority: accounts.event_authority, + program: accounts.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(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_base_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_quote_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.event_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *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 mut data = BuyExactInInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(16 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.user_base_token.clone()); + account_infos.push(self.user_quote_token.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.base_token_mint.clone()); + account_infos.push(self.quote_token_mint.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.event_authority.clone()); + 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 `BuyExactIn` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[]` quote_token_program +/// 13. `[]` event_authority +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct BuyExactInCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> BuyExactInCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + ) -> Self { + let instruction = Box::new(BuyExactInCpiBuilderInstruction { + __program, + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + amount_in, + minimum_amount_out, + share_fee_rate, + __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 = BuyExactInInstructionArgs { + amount_in: self.instruction.amount_in.clone(), + minimum_amount_out: self.instruction.minimum_amount_out.clone(), + share_fee_rate: self.instruction.share_fee_rate.clone(), + }; + let instruction = BuyExactInCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + global_config: self.instruction.global_config, + platform_config: self.instruction.platform_config, + pool_state: self.instruction.pool_state, + user_base_token: self.instruction.user_base_token, + user_quote_token: self.instruction.user_quote_token, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + base_token_mint: self.instruction.base_token_mint, + quote_token_mint: self.instruction.quote_token_mint, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + event_authority: self.instruction.event_authority, + program: self.instruction.program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct BuyExactInCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/buy_exact_out.rs b/e2e/raydium-launchpad/src/generated/instructions/buy_exact_out.rs new file mode 100644 index 0000000..b5cda72 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/buy_exact_out.rs @@ -0,0 +1,746 @@ +//! 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 BUY_EXACT_OUT_DISCRIMINATOR: [u8; 8] = [24, 211, 116, 40, 105, 3, 153, 56]; + +/// Accounts. +#[derive(Debug)] +pub struct BuyExactOut { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: solana_address::Address, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: solana_address::Address, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: solana_address::Address, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: solana_address::Address, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: solana_address::Address, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: solana_address::Address, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: solana_address::Address, + /// The mint of the quote token + pub quote_token_mint: solana_address::Address, + /// SPL Token program for base token transfers + pub base_token_program: solana_address::Address, + /// SPL Token program for quote token transfers + pub quote_token_program: solana_address::Address, + + pub event_authority: solana_address::Address, + + pub program: solana_address::Address, +} + +impl BuyExactOut { + pub fn instruction(&self, args: BuyExactOutInstructionArgs) -> 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: BuyExactOutInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.user_base_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.user_quote_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.event_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = BuyExactOutInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct BuyExactOutInstructionData { + discriminator: [u8; 8], +} + +impl BuyExactOutInstructionData { + pub fn new() -> Self { + Self { + discriminator: [24, 211, 116, 40, 105, 3, 153, 56], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for BuyExactOutInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct BuyExactOutInstructionArgs { + pub amount_out: u64, + pub maximum_amount_in: u64, + pub share_fee_rate: u64, +} + +impl BuyExactOutInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `BuyExactOut`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 13. `[optional]` event_authority (default to PDA derived from 'eventAuthority') +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct BuyExactOutBuilder { + payer: solana_address::Address, + authority: Option, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + quote_token_program: Option, + event_authority: Option, + program: solana_address::Address, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + __remaining_accounts: Vec, +} + +impl BuyExactOutBuilder { + pub fn new( + payer: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + program: solana_address::Address, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + ) -> Self { + Self { + payer, + authority: None, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program: None, + event_authority: None, + program, + amount_out, + maximum_amount_in, + share_fee_rate, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for quote token transfers + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to PDA derived from 'eventAuthority']` + #[inline(always)] + pub fn event_authority(&mut self, event_authority: solana_address::Address) -> &mut Self { + self.event_authority = Some(event_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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let global_config = self.global_config; + let platform_config = self.platform_config; + let pool_state = self.pool_state; + let user_base_token = self.user_base_token; + let user_quote_token = self.user_quote_token; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let base_token_mint = self.base_token_mint; + let quote_token_mint = self.quote_token_mint; + let base_token_program = self.base_token_program; + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let event_authority = self + .event_authority + .unwrap_or(crate::pdas::EVENT_AUTHORITY_ADDRESS); + let program = self.program; + let accounts = BuyExactOut { + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + }; + let args = BuyExactOutInstructionArgs { + amount_out: self.amount_out.clone(), + maximum_amount_in: self.maximum_amount_in.clone(), + share_fee_rate: self.share_fee_rate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `buy_exact_out` CPI accounts. +pub struct BuyExactOutCpiAccounts<'a, 'b> { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `buy_exact_out` CPI instruction. +pub struct BuyExactOutCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: BuyExactOutInstructionArgs, +} + +impl<'a, 'b> BuyExactOutCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: BuyExactOutCpiAccounts<'a, 'b>, + args: BuyExactOutInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + global_config: accounts.global_config, + platform_config: accounts.platform_config, + pool_state: accounts.pool_state, + user_base_token: accounts.user_base_token, + user_quote_token: accounts.user_quote_token, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + base_token_mint: accounts.base_token_mint, + quote_token_mint: accounts.quote_token_mint, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + event_authority: accounts.event_authority, + program: accounts.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(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_base_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_quote_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.event_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *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 mut data = BuyExactOutInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(16 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.user_base_token.clone()); + account_infos.push(self.user_quote_token.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.base_token_mint.clone()); + account_infos.push(self.quote_token_mint.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.event_authority.clone()); + 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 `BuyExactOut` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[]` quote_token_program +/// 13. `[]` event_authority +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct BuyExactOutCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> BuyExactOutCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + ) -> Self { + let instruction = Box::new(BuyExactOutCpiBuilderInstruction { + __program, + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + amount_out, + maximum_amount_in, + share_fee_rate, + __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 = BuyExactOutInstructionArgs { + amount_out: self.instruction.amount_out.clone(), + maximum_amount_in: self.instruction.maximum_amount_in.clone(), + share_fee_rate: self.instruction.share_fee_rate.clone(), + }; + let instruction = BuyExactOutCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + global_config: self.instruction.global_config, + platform_config: self.instruction.platform_config, + pool_state: self.instruction.pool_state, + user_base_token: self.instruction.user_base_token, + user_quote_token: self.instruction.user_quote_token, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + base_token_mint: self.instruction.base_token_mint, + quote_token_mint: self.instruction.quote_token_mint, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + event_authority: self.instruction.event_authority, + program: self.instruction.program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct BuyExactOutCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/claim_platform_fee.rs b/e2e/raydium-launchpad/src/generated/instructions/claim_platform_fee.rs new file mode 100644 index 0000000..cd51c1f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/claim_platform_fee.rs @@ -0,0 +1,574 @@ +//! 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 CLAIM_PLATFORM_FEE_DISCRIMINATOR: [u8; 8] = [156, 39, 208, 135, 76, 237, 61, 72]; + +/// Accounts. +#[derive(Debug)] +pub struct ClaimPlatformFee { + /// Only the wallet stored in platform_config can collect platform fees + pub platform_fee_wallet: solana_address::Address, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: solana_address::Address, + /// The platform config account + pub platform_config: solana_address::Address, + + pub quote_vault: solana_address::Address, + /// The address that receives the collected quote token fees + pub recipient_token_account: solana_address::Address, + /// The mint of quote token vault + pub quote_mint: solana_address::Address, + /// SPL program for input token transfers + pub token_program: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, + /// Required for associated token program + pub associated_token_program: solana_address::Address, +} + +impl ClaimPlatformFee { + 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(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + self.platform_fee_wallet, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + 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.associated_token_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = ClaimPlatformFeeInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ClaimPlatformFeeInstructionData { + discriminator: [u8; 8], +} + +impl ClaimPlatformFeeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [156, 39, 208, 135, 76, 237, 61, 72], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for ClaimPlatformFeeInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `ClaimPlatformFee`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` platform_fee_wallet +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[]` platform_config +/// 4. `[writable]` quote_vault +/// 5. `[writable, optional]` recipient_token_account (default to PDA derived from 'recipientTokenAccount') +/// 6. `[]` quote_mint +/// 7. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 8. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 9. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) +#[derive(Clone, Debug)] +pub struct ClaimPlatformFeeBuilder { + platform_fee_wallet: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + platform_config: solana_address::Address, + quote_vault: solana_address::Address, + recipient_token_account: Option, + quote_mint: solana_address::Address, + token_program: Option, + system_program: Option, + associated_token_program: Option, + __remaining_accounts: Vec, +} + +impl ClaimPlatformFeeBuilder { + pub fn new( + platform_fee_wallet: solana_address::Address, + pool_state: solana_address::Address, + platform_config: solana_address::Address, + quote_vault: solana_address::Address, + quote_mint: solana_address::Address, + ) -> Self { + Self { + platform_fee_wallet, + authority: None, + pool_state, + platform_config, + quote_vault, + recipient_token_account: None, + quote_mint, + token_program: None, + system_program: None, + associated_token_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'recipientTokenAccount']` + /// The address that receives the collected quote token fees + #[inline(always)] + pub fn recipient_token_account( + &mut self, + recipient_token_account: solana_address::Address, + ) -> &mut Self { + self.recipient_token_account = Some(recipient_token_account); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL program for input token transfers + #[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']` + /// Required for account creation + #[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 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` + /// Required for associated token program + #[inline(always)] + pub fn associated_token_program( + &mut self, + associated_token_program: solana_address::Address, + ) -> &mut Self { + self.associated_token_program = Some(associated_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 platform_fee_wallet = self.platform_fee_wallet; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let platform_config = self.platform_config; + let quote_vault = self.quote_vault; + let quote_mint = self.quote_mint; + let recipient_token_account = self.recipient_token_account.unwrap_or_else(|| { + solana_address::Address::find_program_address( + &[ + self.platform_fee_wallet.as_ref(), + &[ + 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, + 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, + 169, + ], + self.quote_mint.as_ref(), + ], + &solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"), + ) + .0 + }); + 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 associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let accounts = ClaimPlatformFee { + platform_fee_wallet, + authority, + pool_state, + platform_config, + quote_vault, + recipient_token_account, + quote_mint, + token_program, + system_program, + associated_token_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `claim_platform_fee` CPI accounts. +pub struct ClaimPlatformFeeCpiAccounts<'a, 'b> { + /// Only the wallet stored in platform_config can collect platform fees + pub platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The platform config account + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for associated token program + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `claim_platform_fee` CPI instruction. +pub struct ClaimPlatformFeeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only the wallet stored in platform_config can collect platform fees + pub platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The platform config account + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for associated token program + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> ClaimPlatformFeeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: ClaimPlatformFeeCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + platform_fee_wallet: accounts.platform_fee_wallet, + authority: accounts.authority, + pool_state: accounts.pool_state, + platform_config: accounts.platform_config, + quote_vault: accounts.quote_vault, + recipient_token_account: accounts.recipient_token_account, + quote_mint: accounts.quote_mint, + token_program: accounts.token_program, + system_program: accounts.system_program, + associated_token_program: accounts.associated_token_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(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.platform_fee_wallet.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + 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.associated_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 data = ClaimPlatformFeeInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(11 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.platform_fee_wallet.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.recipient_token_account.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.associated_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 `ClaimPlatformFee` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` platform_fee_wallet +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[]` platform_config +/// 4. `[writable]` quote_vault +/// 5. `[writable]` recipient_token_account +/// 6. `[]` quote_mint +/// 7. `[]` token_program +/// 8. `[]` system_program +/// 9. `[]` associated_token_program +#[derive(Clone, Debug)] +pub struct ClaimPlatformFeeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> ClaimPlatformFeeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(ClaimPlatformFeeCpiBuilderInstruction { + __program, + platform_fee_wallet, + authority, + pool_state, + platform_config, + quote_vault, + recipient_token_account, + quote_mint, + token_program, + system_program, + associated_token_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 = ClaimPlatformFeeCpi { + __program: self.instruction.__program, + platform_fee_wallet: self.instruction.platform_fee_wallet, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + platform_config: self.instruction.platform_config, + quote_vault: self.instruction.quote_vault, + recipient_token_account: self.instruction.recipient_token_account, + quote_mint: self.instruction.quote_mint, + token_program: self.instruction.token_program, + system_program: self.instruction.system_program, + associated_token_program: self.instruction.associated_token_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct ClaimPlatformFeeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_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/raydium-launchpad/src/generated/instructions/claim_vested_token.rs b/e2e/raydium-launchpad/src/generated/instructions/claim_vested_token.rs new file mode 100644 index 0000000..012138f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/claim_vested_token.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CLAIM_VESTED_TOKEN_DISCRIMINATOR: [u8; 8] = [49, 33, 104, 30, 189, 157, 79, 35]; + +/// Accounts. +#[derive(Debug)] +pub struct ClaimVestedToken { + /// The beneficiary of the vesting account + pub beneficiary: solana_address::Address, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: solana_address::Address, + /// The vesting record account + pub vesting_record: solana_address::Address, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: solana_address::Address, + + pub user_base_token: solana_address::Address, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_token_mint: solana_address::Address, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, + /// Required for associated token program + pub associated_token_program: solana_address::Address, +} + +impl ClaimVestedToken { + 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(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.beneficiary, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.vesting_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.user_base_token, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.associated_token_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = ClaimVestedTokenInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ClaimVestedTokenInstructionData { + discriminator: [u8; 8], +} + +impl ClaimVestedTokenInstructionData { + pub fn new() -> Self { + Self { + discriminator: [49, 33, 104, 30, 189, 157, 79, 35], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for ClaimVestedTokenInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `ClaimVestedToken`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` beneficiary +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[writable, optional]` vesting_record (default to PDA derived from 'vestingRecord') +/// 4. `[writable]` base_vault +/// 5. `[writable, signer]` user_base_token +/// 6. `[]` base_token_mint +/// 7. `[optional]` base_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 8. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 9. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) +#[derive(Clone, Debug)] +pub struct ClaimVestedTokenBuilder { + beneficiary: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + vesting_record: Option, + base_vault: solana_address::Address, + user_base_token: solana_address::Address, + base_token_mint: solana_address::Address, + base_token_program: Option, + system_program: Option, + associated_token_program: Option, + __remaining_accounts: Vec, +} + +impl ClaimVestedTokenBuilder { + pub fn new( + beneficiary: solana_address::Address, + pool_state: solana_address::Address, + base_vault: solana_address::Address, + user_base_token: solana_address::Address, + base_token_mint: solana_address::Address, + ) -> Self { + Self { + beneficiary, + authority: None, + pool_state, + vesting_record: None, + base_vault, + user_base_token, + base_token_mint, + base_token_program: None, + system_program: None, + associated_token_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'vestingRecord']` + /// The vesting record account + #[inline(always)] + pub fn vesting_record(&mut self, vesting_record: solana_address::Address) -> &mut Self { + self.vesting_record = Some(vesting_record); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the base token + /// Must be the standard Token program + #[inline(always)] + pub fn base_token_program(&mut self, base_token_program: solana_address::Address) -> &mut Self { + self.base_token_program = Some(base_token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` + /// Required for associated token program + #[inline(always)] + pub fn associated_token_program( + &mut self, + associated_token_program: solana_address::Address, + ) -> &mut Self { + self.associated_token_program = Some(associated_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 beneficiary = self.beneficiary; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let vesting_record = self.vesting_record.unwrap_or_else(|| { + crate::pdas::find_vesting_record_pda(&self.pool_state, &self.beneficiary).0 + }); + let base_vault = self.base_vault; + let user_base_token = self.user_base_token; + let base_token_mint = self.base_token_mint; + let base_token_program = self.base_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let accounts = ClaimVestedToken { + beneficiary, + authority, + pool_state, + vesting_record, + base_vault, + user_base_token, + base_token_mint, + base_token_program, + system_program, + associated_token_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `claim_vested_token` CPI accounts. +pub struct ClaimVestedTokenCpiAccounts<'a, 'b> { + /// The beneficiary of the vesting account + pub beneficiary: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The vesting record account + pub vesting_record: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for associated token program + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `claim_vested_token` CPI instruction. +pub struct ClaimVestedTokenCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The beneficiary of the vesting account + pub beneficiary: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The vesting record account + pub vesting_record: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for associated token program + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> ClaimVestedTokenCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: ClaimVestedTokenCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + beneficiary: accounts.beneficiary, + authority: accounts.authority, + pool_state: accounts.pool_state, + vesting_record: accounts.vesting_record, + base_vault: accounts.base_vault, + user_base_token: accounts.user_base_token, + base_token_mint: accounts.base_token_mint, + base_token_program: accounts.base_token_program, + system_program: accounts.system_program, + associated_token_program: accounts.associated_token_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(10 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.beneficiary.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.vesting_record.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_base_token.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.associated_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 data = ClaimVestedTokenInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(11 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.beneficiary.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.vesting_record.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.user_base_token.clone()); + account_infos.push(self.base_token_mint.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.associated_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 `ClaimVestedToken` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` beneficiary +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[writable]` vesting_record +/// 4. `[writable]` base_vault +/// 5. `[writable, signer]` user_base_token +/// 6. `[]` base_token_mint +/// 7. `[]` base_token_program +/// 8. `[]` system_program +/// 9. `[]` associated_token_program +#[derive(Clone, Debug)] +pub struct ClaimVestedTokenCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> ClaimVestedTokenCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + beneficiary: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + vesting_record: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(ClaimVestedTokenCpiBuilderInstruction { + __program, + beneficiary, + authority, + pool_state, + vesting_record, + base_vault, + user_base_token, + base_token_mint, + base_token_program, + system_program, + associated_token_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 = ClaimVestedTokenCpi { + __program: self.instruction.__program, + beneficiary: self.instruction.beneficiary, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + vesting_record: self.instruction.vesting_record, + base_vault: self.instruction.base_vault, + user_base_token: self.instruction.user_base_token, + base_token_mint: self.instruction.base_token_mint, + base_token_program: self.instruction.base_token_program, + system_program: self.instruction.system_program, + associated_token_program: self.instruction.associated_token_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct ClaimVestedTokenCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + beneficiary: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + vesting_record: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_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/raydium-launchpad/src/generated/instructions/collect_fee.rs b/e2e/raydium-launchpad/src/generated/instructions/collect_fee.rs new file mode 100644 index 0000000..1c469ab --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/collect_fee.rs @@ -0,0 +1,467 @@ +//! 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 COLLECT_FEE_DISCRIMINATOR: [u8; 8] = [60, 173, 247, 103, 4, 93, 130, 48]; + +/// Accounts. +#[derive(Debug)] +pub struct CollectFee { + /// Only protocol_fee_owner saved in global_config can collect protocol fee now + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + /// Pool state stores accumulated protocol fee amount + pub pool_state: solana_address::Address, + /// Global config account stores owner + pub global_config: solana_address::Address, + /// The address that holds pool tokens for quote token + pub quote_vault: solana_address::Address, + /// The mint of quote token vault + pub quote_mint: solana_address::Address, + /// The address that receives the collected quote token fees + pub recipient_token_account: solana_address::Address, + /// SPL program for input token transfers + pub token_program: solana_address::Address, +} + +impl CollectFee { + 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.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CollectFeeInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectFeeInstructionData { + discriminator: [u8; 8], +} + +impl CollectFeeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [60, 173, 247, 103, 4, 93, 130, 48], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CollectFeeInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CollectFee`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[]` global_config +/// 4. `[writable]` quote_vault +/// 5. `[]` quote_mint +/// 6. `[writable]` recipient_token_account +/// 7. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +#[derive(Clone, Debug)] +pub struct CollectFeeBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + global_config: solana_address::Address, + quote_vault: solana_address::Address, + quote_mint: solana_address::Address, + recipient_token_account: solana_address::Address, + token_program: Option, + __remaining_accounts: Vec, +} + +impl CollectFeeBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + global_config: solana_address::Address, + quote_vault: solana_address::Address, + quote_mint: solana_address::Address, + recipient_token_account: solana_address::Address, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL program for input token transfers + #[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 owner = self.owner; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let global_config = self.global_config; + let quote_vault = self.quote_vault; + let quote_mint = self.quote_mint; + let recipient_token_account = self.recipient_token_account; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let accounts = CollectFee { + owner, + authority, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `collect_fee` CPI accounts. +pub struct CollectFeeCpiAccounts<'a, 'b> { + /// Only protocol_fee_owner saved in global_config can collect protocol fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for quote token + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `collect_fee` CPI instruction. +pub struct CollectFeeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only protocol_fee_owner saved in global_config can collect protocol fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for quote token + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CollectFeeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CollectFeeCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + global_config: accounts.global_config, + quote_vault: accounts.quote_vault, + quote_mint: accounts.quote_mint, + recipient_token_account: accounts.recipient_token_account, + token_program: accounts.token_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(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token_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 data = CollectFeeInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.recipient_token_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 `CollectFee` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[]` global_config +/// 4. `[writable]` quote_vault +/// 5. `[]` quote_mint +/// 6. `[writable]` recipient_token_account +/// 7. `[]` token_program +#[derive(Clone, Debug)] +pub struct CollectFeeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CollectFeeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CollectFeeCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_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 = CollectFeeCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + global_config: self.instruction.global_config, + quote_vault: self.instruction.quote_vault, + quote_mint: self.instruction.quote_mint, + recipient_token_account: self.instruction.recipient_token_account, + token_program: self.instruction.token_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CollectFeeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + token_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/raydium-launchpad/src/generated/instructions/collect_migrate_fee.rs b/e2e/raydium-launchpad/src/generated/instructions/collect_migrate_fee.rs new file mode 100644 index 0000000..8553122 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/collect_migrate_fee.rs @@ -0,0 +1,471 @@ +//! 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 COLLECT_MIGRATE_FEE_DISCRIMINATOR: [u8; 8] = [255, 186, 150, 223, 235, 118, 201, 186]; + +/// Accounts. +#[derive(Debug)] +pub struct CollectMigrateFee { + /// Only migrate_fee_owner saved in global_config can collect migrate fee now + pub owner: solana_address::Address, + + pub authority: solana_address::Address, + /// Pool state stores accumulated protocol fee amount + pub pool_state: solana_address::Address, + /// Global config account stores owner + pub global_config: solana_address::Address, + /// The address that holds pool tokens for quote token + pub quote_vault: solana_address::Address, + /// The mint of quote token vault + pub quote_mint: solana_address::Address, + /// The address that receives the collected quote token fees + pub recipient_token_account: solana_address::Address, + /// SPL program for input token transfers + pub token_program: solana_address::Address, +} + +impl CollectMigrateFee { + 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.owner, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.recipient_token_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.token_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = CollectMigrateFeeInstructionData::new() + .try_to_vec() + .unwrap(); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CollectMigrateFeeInstructionData { + discriminator: [u8; 8], +} + +impl CollectMigrateFeeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [255, 186, 150, 223, 235, 118, 201, 186], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CollectMigrateFeeInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `CollectMigrateFee`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[writable]` pool_state +/// 3. `[]` global_config +/// 4. `[writable]` quote_vault +/// 5. `[]` quote_mint +/// 6. `[writable]` recipient_token_account +/// 7. `[optional]` token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +#[derive(Clone, Debug)] +pub struct CollectMigrateFeeBuilder { + owner: solana_address::Address, + authority: Option, + pool_state: solana_address::Address, + global_config: solana_address::Address, + quote_vault: solana_address::Address, + quote_mint: solana_address::Address, + recipient_token_account: solana_address::Address, + token_program: Option, + __remaining_accounts: Vec, +} + +impl CollectMigrateFeeBuilder { + pub fn new( + owner: solana_address::Address, + pool_state: solana_address::Address, + global_config: solana_address::Address, + quote_vault: solana_address::Address, + quote_mint: solana_address::Address, + recipient_token_account: solana_address::Address, + ) -> Self { + Self { + owner, + authority: None, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL program for input token transfers + #[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 owner = self.owner; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state; + let global_config = self.global_config; + let quote_vault = self.quote_vault; + let quote_mint = self.quote_mint; + let recipient_token_account = self.recipient_token_account; + let token_program = self.token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let accounts = CollectMigrateFee { + owner, + authority, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `collect_migrate_fee` CPI accounts. +pub struct CollectMigrateFeeCpiAccounts<'a, 'b> { + /// Only migrate_fee_owner saved in global_config can collect migrate fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for quote token + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `collect_migrate_fee` CPI instruction. +pub struct CollectMigrateFeeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only migrate_fee_owner saved in global_config can collect migrate fee now + pub owner: &'b solana_account_info::AccountInfo<'a>, + + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Pool state stores accumulated protocol fee amount + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The address that holds pool tokens for quote token + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of quote token vault + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// The address that receives the collected quote token fees + pub recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL program for input token transfers + pub token_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> CollectMigrateFeeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CollectMigrateFeeCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + authority: accounts.authority, + pool_state: accounts.pool_state, + global_config: accounts.global_config, + quote_vault: accounts.quote_vault, + quote_mint: accounts.quote_mint, + recipient_token_account: accounts.recipient_token_account, + token_program: accounts.token_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(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.recipient_token_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 data = CollectMigrateFeeInstructionData::new() + .try_to_vec() + .unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.recipient_token_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 `CollectMigrateFee` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[]` authority +/// 2. `[writable]` pool_state +/// 3. `[]` global_config +/// 4. `[writable]` quote_vault +/// 5. `[]` quote_mint +/// 6. `[writable]` recipient_token_account +/// 7. `[]` token_program +#[derive(Clone, Debug)] +pub struct CollectMigrateFeeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CollectMigrateFeeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + token_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(CollectMigrateFeeCpiBuilderInstruction { + __program, + owner, + authority, + pool_state, + global_config, + quote_vault, + quote_mint, + recipient_token_account, + token_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 = CollectMigrateFeeCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + global_config: self.instruction.global_config, + quote_vault: self.instruction.quote_vault, + quote_mint: self.instruction.quote_mint, + recipient_token_account: self.instruction.recipient_token_account, + token_program: self.instruction.token_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CollectMigrateFeeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + recipient_token_account: &'b solana_account_info::AccountInfo<'a>, + token_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/raydium-launchpad/src/generated/instructions/create_config.rs b/e2e/raydium-launchpad/src/generated/instructions/create_config.rs new file mode 100644 index 0000000..67804a2 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/create_config.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_CONFIG_DISCRIMINATOR: [u8; 8] = [201, 207, 243, 114, 75, 111, 47, 189]; + +/// Accounts. +#[derive(Debug)] +pub struct CreateConfig { + /// The protocol owner/admin account + /// Must match the predefined admin address + /// Has authority to create and modify protocol configurations + pub owner: solana_address::Address, + /// Global configuration account that stores protocol-wide settings + /// PDA generated using GLOBAL_CONFIG_SEED, quote token mint, and curve type + /// Stores fee rates and protocol parameters + pub global_config: solana_address::Address, + /// The mint address of the quote token (token used for buying) + /// This will be the standard token used for all pools with this config + pub quote_token_mint: solana_address::Address, + /// Account that will receive protocol fees + pub protocol_fee_owner: solana_address::Address, + /// Account that will receive migrate fees + pub migrate_fee_owner: solana_address::Address, + /// The control wallet address for migrating to amm + pub migrate_to_amm_wallet: solana_address::Address, + /// The control wallet address for migrating to cpswap + pub migrate_to_cpswap_wallet: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, +} + +impl CreateConfig { + pub fn instruction( + &self, + args: CreateConfigInstructionArgs, + ) -> 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: CreateConfigInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.owner, true)); + accounts.push(solana_instruction::AccountMeta::new( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.protocol_fee_owner, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.migrate_fee_owner, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.migrate_to_amm_wallet, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.migrate_to_cpswap_wallet, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateConfigInstructionData { + discriminator: [u8; 8], +} + +impl CreateConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [201, 207, 243, 114, 75, 111, 47, 189], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateConfigInstructionArgs { + pub curve_type: u8, + pub index: u16, + pub migrate_fee: u64, + pub trade_fee_rate: u64, +} + +impl CreateConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateConfig`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer, optional]` owner (default to `GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ`) +/// 1. `[writable, optional]` global_config (default to PDA derived from 'globalConfig') +/// 2. `[]` quote_token_mint +/// 3. `[]` protocol_fee_owner +/// 4. `[]` migrate_fee_owner +/// 5. `[]` migrate_to_amm_wallet +/// 6. `[]` migrate_to_cpswap_wallet +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreateConfigBuilder { + owner: Option, + global_config: Option, + quote_token_mint: solana_address::Address, + protocol_fee_owner: solana_address::Address, + migrate_fee_owner: solana_address::Address, + migrate_to_amm_wallet: solana_address::Address, + migrate_to_cpswap_wallet: solana_address::Address, + system_program: Option, + curve_type: u8, + index: u16, + migrate_fee: u64, + trade_fee_rate: u64, + __remaining_accounts: Vec, +} + +impl CreateConfigBuilder { + pub fn new( + quote_token_mint: solana_address::Address, + protocol_fee_owner: solana_address::Address, + migrate_fee_owner: solana_address::Address, + migrate_to_amm_wallet: solana_address::Address, + migrate_to_cpswap_wallet: solana_address::Address, + curve_type: u8, + index: u16, + migrate_fee: u64, + trade_fee_rate: u64, + ) -> Self { + Self { + owner: None, + global_config: None, + quote_token_mint, + protocol_fee_owner, + migrate_fee_owner, + migrate_to_amm_wallet, + migrate_to_cpswap_wallet, + system_program: None, + curve_type, + index, + migrate_fee, + trade_fee_rate, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ']` + /// The protocol owner/admin account + /// Must match the predefined admin address + /// Has authority to create and modify protocol configurations + #[inline(always)] + pub fn owner(&mut self, owner: solana_address::Address) -> &mut Self { + self.owner = Some(owner); + self + } + /// `[optional account, default to PDA derived from 'globalConfig']` + /// Global configuration account that stores protocol-wide settings + /// PDA generated using GLOBAL_CONFIG_SEED, quote token mint, and curve type + /// Stores fee rates and protocol parameters + #[inline(always)] + pub fn global_config(&mut self, global_config: solana_address::Address) -> &mut Self { + self.global_config = Some(global_config); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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 owner = self.owner.unwrap_or(solana_address::address!( + "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + )); + let quote_token_mint = self.quote_token_mint; + let global_config = self.global_config.unwrap_or_else(|| { + crate::pdas::find_global_config_pda( + &self.quote_token_mint, + self.curve_type.clone(), + self.index.clone(), + ) + .0 + }); + let protocol_fee_owner = self.protocol_fee_owner; + let migrate_fee_owner = self.migrate_fee_owner; + let migrate_to_amm_wallet = self.migrate_to_amm_wallet; + let migrate_to_cpswap_wallet = self.migrate_to_cpswap_wallet; + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreateConfig { + owner, + global_config, + quote_token_mint, + protocol_fee_owner, + migrate_fee_owner, + migrate_to_amm_wallet, + migrate_to_cpswap_wallet, + system_program, + }; + let args = CreateConfigInstructionArgs { + curve_type: self.curve_type.clone(), + index: self.index.clone(), + migrate_fee: self.migrate_fee.clone(), + trade_fee_rate: self.trade_fee_rate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_config` CPI accounts. +pub struct CreateConfigCpiAccounts<'a, 'b> { + /// The protocol owner/admin account + /// Must match the predefined admin address + /// Has authority to create and modify protocol configurations + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account that stores protocol-wide settings + /// PDA generated using GLOBAL_CONFIG_SEED, quote token mint, and curve type + /// Stores fee rates and protocol parameters + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the quote token (token used for buying) + /// This will be the standard token used for all pools with this config + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// Account that will receive protocol fees + pub protocol_fee_owner: &'b solana_account_info::AccountInfo<'a>, + /// Account that will receive migrate fees + pub migrate_fee_owner: &'b solana_account_info::AccountInfo<'a>, + /// The control wallet address for migrating to amm + pub migrate_to_amm_wallet: &'b solana_account_info::AccountInfo<'a>, + /// The control wallet address for migrating to cpswap + pub migrate_to_cpswap_wallet: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_config` CPI instruction. +pub struct CreateConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The protocol owner/admin account + /// Must match the predefined admin address + /// Has authority to create and modify protocol configurations + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account that stores protocol-wide settings + /// PDA generated using GLOBAL_CONFIG_SEED, quote token mint, and curve type + /// Stores fee rates and protocol parameters + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The mint address of the quote token (token used for buying) + /// This will be the standard token used for all pools with this config + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// Account that will receive protocol fees + pub protocol_fee_owner: &'b solana_account_info::AccountInfo<'a>, + /// Account that will receive migrate fees + pub migrate_fee_owner: &'b solana_account_info::AccountInfo<'a>, + /// The control wallet address for migrating to amm + pub migrate_to_amm_wallet: &'b solana_account_info::AccountInfo<'a>, + /// The control wallet address for migrating to cpswap + pub migrate_to_cpswap_wallet: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CreateConfigInstructionArgs, +} + +impl<'a, 'b> CreateConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateConfigCpiAccounts<'a, 'b>, + args: CreateConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + global_config: accounts.global_config, + quote_token_mint: accounts.quote_token_mint, + protocol_fee_owner: accounts.protocol_fee_owner, + migrate_fee_owner: accounts.migrate_fee_owner, + migrate_to_amm_wallet: accounts.migrate_to_amm_wallet, + migrate_to_cpswap_wallet: accounts.migrate_to_cpswap_wallet, + 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(8 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(*self.owner.key, true)); + accounts.push(solana_instruction::AccountMeta::new( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.protocol_fee_owner.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.migrate_fee_owner.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.migrate_to_amm_wallet.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.migrate_to_cpswap_wallet.key, + false, + )); + 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 = CreateConfigInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.owner.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.quote_token_mint.clone()); + account_infos.push(self.protocol_fee_owner.clone()); + account_infos.push(self.migrate_fee_owner.clone()); + account_infos.push(self.migrate_to_amm_wallet.clone()); + account_infos.push(self.migrate_to_cpswap_wallet.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 `CreateConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` owner +/// 1. `[writable]` global_config +/// 2. `[]` quote_token_mint +/// 3. `[]` protocol_fee_owner +/// 4. `[]` migrate_fee_owner +/// 5. `[]` migrate_to_amm_wallet +/// 6. `[]` migrate_to_cpswap_wallet +/// 7. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreateConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + protocol_fee_owner: &'b solana_account_info::AccountInfo<'a>, + migrate_fee_owner: &'b solana_account_info::AccountInfo<'a>, + migrate_to_amm_wallet: &'b solana_account_info::AccountInfo<'a>, + migrate_to_cpswap_wallet: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + curve_type: u8, + index: u16, + migrate_fee: u64, + trade_fee_rate: u64, + ) -> Self { + let instruction = Box::new(CreateConfigCpiBuilderInstruction { + __program, + owner, + global_config, + quote_token_mint, + protocol_fee_owner, + migrate_fee_owner, + migrate_to_amm_wallet, + migrate_to_cpswap_wallet, + system_program, + curve_type, + index, + migrate_fee, + trade_fee_rate, + __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 = CreateConfigInstructionArgs { + curve_type: self.instruction.curve_type.clone(), + index: self.instruction.index.clone(), + migrate_fee: self.instruction.migrate_fee.clone(), + trade_fee_rate: self.instruction.trade_fee_rate.clone(), + }; + let instruction = CreateConfigCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + global_config: self.instruction.global_config, + quote_token_mint: self.instruction.quote_token_mint, + protocol_fee_owner: self.instruction.protocol_fee_owner, + migrate_fee_owner: self.instruction.migrate_fee_owner, + migrate_to_amm_wallet: self.instruction.migrate_to_amm_wallet, + migrate_to_cpswap_wallet: self.instruction.migrate_to_cpswap_wallet, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + protocol_fee_owner: &'b solana_account_info::AccountInfo<'a>, + migrate_fee_owner: &'b solana_account_info::AccountInfo<'a>, + migrate_to_amm_wallet: &'b solana_account_info::AccountInfo<'a>, + migrate_to_cpswap_wallet: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + curve_type: u8, + index: u16, + migrate_fee: u64, + trade_fee_rate: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/create_platform_config.rs b/e2e/raydium-launchpad/src/generated/instructions/create_platform_config.rs new file mode 100644 index 0000000..ac6cb93 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/create_platform_config.rs @@ -0,0 +1,470 @@ +//! 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::MigrateNftInfo; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const CREATE_PLATFORM_CONFIG_DISCRIMINATOR: [u8; 8] = [176, 90, 196, 175, 253, 113, 220, 20]; + +/// Accounts. +#[derive(Debug)] +pub struct CreatePlatformConfig { + /// The account paying for the initialization costs + pub platform_admin: solana_address::Address, + + pub platform_fee_wallet: solana_address::Address, + + pub platform_nft_wallet: solana_address::Address, + /// The platform config account + pub platform_config: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, +} + +impl CreatePlatformConfig { + pub fn instruction( + &self, + args: CreatePlatformConfigInstructionArgs, + ) -> 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: CreatePlatformConfigInstructionArgs, + 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.platform_admin, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_fee_wallet, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_nft_wallet, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CreatePlatformConfigInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreatePlatformConfigInstructionData { + discriminator: [u8; 8], +} + +impl CreatePlatformConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [176, 90, 196, 175, 253, 113, 220, 20], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreatePlatformConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreatePlatformConfigInstructionArgs { + pub migrate_nft_info: MigrateNftInfo, + pub fee_rate: u64, + pub name: String, + pub web: String, + pub img: String, +} + +impl CreatePlatformConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreatePlatformConfig`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` platform_admin +/// 1. `[]` platform_fee_wallet +/// 2. `[]` platform_nft_wallet +/// 3. `[writable, optional]` platform_config (default to PDA derived from 'platformConfig') +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreatePlatformConfigBuilder { + platform_admin: solana_address::Address, + platform_fee_wallet: solana_address::Address, + platform_nft_wallet: solana_address::Address, + platform_config: Option, + system_program: Option, + migrate_nft_info: MigrateNftInfo, + fee_rate: u64, + name: String, + web: String, + img: String, + __remaining_accounts: Vec, +} + +impl CreatePlatformConfigBuilder { + pub fn new( + platform_admin: solana_address::Address, + platform_fee_wallet: solana_address::Address, + platform_nft_wallet: solana_address::Address, + migrate_nft_info: MigrateNftInfo, + fee_rate: u64, + name: String, + web: String, + img: String, + ) -> Self { + Self { + platform_admin, + platform_fee_wallet, + platform_nft_wallet, + platform_config: None, + system_program: None, + migrate_nft_info, + fee_rate, + name, + web, + img, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'platformConfig']` + /// The platform config account + #[inline(always)] + pub fn platform_config(&mut self, platform_config: solana_address::Address) -> &mut Self { + self.platform_config = Some(platform_config); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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 platform_admin = self.platform_admin; + let platform_fee_wallet = self.platform_fee_wallet; + let platform_nft_wallet = self.platform_nft_wallet; + let platform_config = self + .platform_config + .unwrap_or_else(|| crate::pdas::find_platform_config_pda(&self.platform_admin).0); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreatePlatformConfig { + platform_admin, + platform_fee_wallet, + platform_nft_wallet, + platform_config, + system_program, + }; + let args = CreatePlatformConfigInstructionArgs { + migrate_nft_info: self.migrate_nft_info.clone(), + fee_rate: self.fee_rate.clone(), + name: self.name.clone(), + web: self.web.clone(), + img: self.img.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_platform_config` CPI accounts. +pub struct CreatePlatformConfigCpiAccounts<'a, 'b> { + /// The account paying for the initialization costs + pub platform_admin: &'b solana_account_info::AccountInfo<'a>, + + pub platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + + pub platform_nft_wallet: &'b solana_account_info::AccountInfo<'a>, + /// The platform config account + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_platform_config` CPI instruction. +pub struct CreatePlatformConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The account paying for the initialization costs + pub platform_admin: &'b solana_account_info::AccountInfo<'a>, + + pub platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + + pub platform_nft_wallet: &'b solana_account_info::AccountInfo<'a>, + /// The platform config account + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CreatePlatformConfigInstructionArgs, +} + +impl<'a, 'b> CreatePlatformConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreatePlatformConfigCpiAccounts<'a, 'b>, + args: CreatePlatformConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + platform_admin: accounts.platform_admin, + platform_fee_wallet: accounts.platform_fee_wallet, + platform_nft_wallet: accounts.platform_nft_wallet, + platform_config: accounts.platform_config, + 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(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.platform_admin.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_fee_wallet.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_nft_wallet.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.platform_config.key, + false, + )); + 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 = CreatePlatformConfigInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.platform_admin.clone()); + account_infos.push(self.platform_fee_wallet.clone()); + account_infos.push(self.platform_nft_wallet.clone()); + account_infos.push(self.platform_config.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 `CreatePlatformConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` platform_admin +/// 1. `[]` platform_fee_wallet +/// 2. `[]` platform_nft_wallet +/// 3. `[writable]` platform_config +/// 4. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreatePlatformConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreatePlatformConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + platform_admin: &'b solana_account_info::AccountInfo<'a>, + platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + platform_nft_wallet: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + migrate_nft_info: MigrateNftInfo, + fee_rate: u64, + name: String, + web: String, + img: String, + ) -> Self { + let instruction = Box::new(CreatePlatformConfigCpiBuilderInstruction { + __program, + platform_admin, + platform_fee_wallet, + platform_nft_wallet, + platform_config, + system_program, + migrate_nft_info, + fee_rate, + name, + web, + img, + __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 = CreatePlatformConfigInstructionArgs { + migrate_nft_info: self.instruction.migrate_nft_info.clone(), + fee_rate: self.instruction.fee_rate.clone(), + name: self.instruction.name.clone(), + web: self.instruction.web.clone(), + img: self.instruction.img.clone(), + }; + let instruction = CreatePlatformConfigCpi { + __program: self.instruction.__program, + platform_admin: self.instruction.platform_admin, + platform_fee_wallet: self.instruction.platform_fee_wallet, + platform_nft_wallet: self.instruction.platform_nft_wallet, + platform_config: self.instruction.platform_config, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreatePlatformConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + platform_admin: &'b solana_account_info::AccountInfo<'a>, + platform_fee_wallet: &'b solana_account_info::AccountInfo<'a>, + platform_nft_wallet: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + migrate_nft_info: MigrateNftInfo, + fee_rate: u64, + name: String, + web: String, + img: String, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/create_vesting_account.rs b/e2e/raydium-launchpad/src/generated/instructions/create_vesting_account.rs new file mode 100644 index 0000000..438b893 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/create_vesting_account.rs @@ -0,0 +1,430 @@ +//! 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_VESTING_ACCOUNT_DISCRIMINATOR: [u8; 8] = [129, 178, 2, 13, 217, 172, 230, 218]; + +/// Accounts. +#[derive(Debug)] +pub struct CreateVestingAccount { + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub creator: solana_address::Address, + + pub beneficiary: solana_address::Address, + /// The pool state account + pub pool_state: solana_address::Address, + /// The vesting record account + pub vesting_record: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, +} + +impl CreateVestingAccount { + pub fn instruction( + &self, + args: CreateVestingAccountInstructionArgs, + ) -> 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: CreateVestingAccountInstructionArgs, + 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.creator, true)); + accounts.push(solana_instruction::AccountMeta::new( + self.beneficiary, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.vesting_record, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = CreateVestingAccountInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateVestingAccountInstructionData { + discriminator: [u8; 8], +} + +impl CreateVestingAccountInstructionData { + pub fn new() -> Self { + Self { + discriminator: [129, 178, 2, 13, 217, 172, 230, 218], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for CreateVestingAccountInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct CreateVestingAccountInstructionArgs { + pub share_amount: u64, +} + +impl CreateVestingAccountInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `CreateVestingAccount`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` creator +/// 1. `[writable]` beneficiary +/// 2. `[writable]` pool_state +/// 3. `[writable, optional]` vesting_record (default to PDA derived from 'vestingRecord') +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct CreateVestingAccountBuilder { + creator: solana_address::Address, + beneficiary: solana_address::Address, + pool_state: solana_address::Address, + vesting_record: Option, + system_program: Option, + share_amount: u64, + __remaining_accounts: Vec, +} + +impl CreateVestingAccountBuilder { + pub fn new( + creator: solana_address::Address, + beneficiary: solana_address::Address, + pool_state: solana_address::Address, + share_amount: u64, + ) -> Self { + Self { + creator, + beneficiary, + pool_state, + vesting_record: None, + system_program: None, + share_amount, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'vestingRecord']` + /// The vesting record account + #[inline(always)] + pub fn vesting_record(&mut self, vesting_record: solana_address::Address) -> &mut Self { + self.vesting_record = Some(vesting_record); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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 creator = self.creator; + let beneficiary = self.beneficiary; + let pool_state = self.pool_state; + let vesting_record = self.vesting_record.unwrap_or_else(|| { + crate::pdas::find_vesting_record_pda(&self.pool_state, &self.beneficiary).0 + }); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let accounts = CreateVestingAccount { + creator, + beneficiary, + pool_state, + vesting_record, + system_program, + }; + let args = CreateVestingAccountInstructionArgs { + share_amount: self.share_amount.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_vesting_account` CPI accounts. +pub struct CreateVestingAccountCpiAccounts<'a, 'b> { + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub creator: &'b solana_account_info::AccountInfo<'a>, + + pub beneficiary: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The vesting record account + pub vesting_record: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `create_vesting_account` CPI instruction. +pub struct CreateVestingAccountCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub creator: &'b solana_account_info::AccountInfo<'a>, + + pub beneficiary: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The vesting record account + pub vesting_record: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CreateVestingAccountInstructionArgs, +} + +impl<'a, 'b> CreateVestingAccountCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: CreateVestingAccountCpiAccounts<'a, 'b>, + args: CreateVestingAccountInstructionArgs, + ) -> Self { + Self { + __program: program, + creator: accounts.creator, + beneficiary: accounts.beneficiary, + pool_state: accounts.pool_state, + vesting_record: accounts.vesting_record, + 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(5 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new( + *self.creator.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.beneficiary.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.vesting_record.key, + false, + )); + 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 = CreateVestingAccountInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.creator.clone()); + account_infos.push(self.beneficiary.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.vesting_record.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 `CreateVestingAccount` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` creator +/// 1. `[writable]` beneficiary +/// 2. `[writable]` pool_state +/// 3. `[writable]` vesting_record +/// 4. `[]` system_program +#[derive(Clone, Debug)] +pub struct CreateVestingAccountCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateVestingAccountCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + beneficiary: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + vesting_record: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + share_amount: u64, + ) -> Self { + let instruction = Box::new(CreateVestingAccountCpiBuilderInstruction { + __program, + creator, + beneficiary, + pool_state, + vesting_record, + system_program, + share_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 = CreateVestingAccountInstructionArgs { + share_amount: self.instruction.share_amount.clone(), + }; + let instruction = CreateVestingAccountCpi { + __program: self.instruction.__program, + creator: self.instruction.creator, + beneficiary: self.instruction.beneficiary, + pool_state: self.instruction.pool_state, + vesting_record: self.instruction.vesting_record, + system_program: self.instruction.system_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct CreateVestingAccountCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + beneficiary: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + vesting_record: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + share_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/raydium-launchpad/src/generated/instructions/initialize.rs b/e2e/raydium-launchpad/src/generated/instructions/initialize.rs new file mode 100644 index 0000000..7bf935a --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/initialize.rs @@ -0,0 +1,889 @@ +//! 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::CurveParams; +use crate::generated::types::MintParams; +use crate::generated::types::VestingParams; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const INITIALIZE_DISCRIMINATOR: [u8; 8] = [175, 175, 109, 31, 13, 152, 155, 237]; + +/// Accounts. +#[derive(Debug)] +pub struct Initialize { + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub payer: solana_address::Address, + + pub creator: solana_address::Address, + /// Global configuration account containing protocol-wide settings + /// Includes settings like quote token mint and fee parameters + pub global_config: solana_address::Address, + /// Platform configuration account containing platform info + /// Includes settings like the fee_rate, name, web, img of the platform + pub platform_config: solana_address::Address, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: solana_address::Address, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_mint: solana_address::Address, + /// The mint for the quote token (token used to buy) + /// Must match the quote_mint specified in global config + pub quote_mint: solana_address::Address, + /// Token account that holds the pool's base tokens + /// PDA generated using POOL_VAULT_SEED + pub base_vault: solana_address::Address, + /// Token account that holds the pool's quote tokens + /// PDA generated using POOL_VAULT_SEED + pub quote_vault: solana_address::Address, + /// Account to store the base token's metadata + /// Created using Metaplex metadata program + pub metadata_account: solana_address::Address, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: solana_address::Address, + /// SPL Token program for the quote token + pub quote_token_program: solana_address::Address, + /// Metaplex Token Metadata program + /// Used to create metadata for the base token + pub metadata_program: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, + /// Required for rent exempt calculations + pub rent_program: solana_address::Address, + + pub event_authority: solana_address::Address, + + pub program: solana_address::Address, +} + +impl Initialize { + pub fn instruction(&self, args: InitializeInstructionArgs) -> 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: InitializeInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(18 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.payer, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.creator, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new(self.base_mint, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.metadata_account, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.metadata_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.rent_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.event_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = InitializeInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InitializeInstructionData { + discriminator: [u8; 8], +} + +impl InitializeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [175, 175, 109, 31, 13, 152, 155, 237], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for InitializeInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct InitializeInstructionArgs { + pub base_mint_param: MintParams, + pub curve_param: CurveParams, + pub vesting_param: VestingParams, +} + +impl InitializeInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `Initialize`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` creator +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[optional]` authority (default to PDA derived from 'authority') +/// 5. `[writable, optional]` pool_state (default to PDA derived from 'poolState') +/// 6. `[writable, signer]` base_mint +/// 7. `[]` quote_mint +/// 8. `[writable, optional]` base_vault (default to PDA derived from 'baseVault') +/// 9. `[writable, optional]` quote_vault (default to PDA derived from 'quoteVault') +/// 10. `[writable]` metadata_account +/// 11. `[optional]` base_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 12. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 13. `[optional]` metadata_program (default to `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s`) +/// 14. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 15. `[optional]` rent_program (default to `SysvarRent111111111111111111111111111111111`) +/// 16. `[optional]` event_authority (default to PDA derived from 'eventAuthority') +/// 17. `[]` program +#[derive(Clone, Debug)] +pub struct InitializeBuilder { + payer: solana_address::Address, + creator: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + authority: Option, + pool_state: Option, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + base_vault: Option, + quote_vault: Option, + metadata_account: solana_address::Address, + base_token_program: Option, + quote_token_program: Option, + metadata_program: Option, + system_program: Option, + rent_program: Option, + event_authority: Option, + program: solana_address::Address, + base_mint_param: MintParams, + curve_param: CurveParams, + vesting_param: VestingParams, + __remaining_accounts: Vec, +} + +impl InitializeBuilder { + pub fn new( + payer: solana_address::Address, + creator: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + metadata_account: solana_address::Address, + program: solana_address::Address, + base_mint_param: MintParams, + curve_param: CurveParams, + vesting_param: VestingParams, + ) -> Self { + Self { + payer, + creator, + global_config, + platform_config, + authority: None, + pool_state: None, + base_mint, + quote_mint, + base_vault: None, + quote_vault: None, + metadata_account, + base_token_program: None, + quote_token_program: None, + metadata_program: None, + system_program: None, + rent_program: None, + event_authority: None, + program, + base_mint_param, + curve_param, + vesting_param, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'poolState']` + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + #[inline(always)] + pub fn pool_state(&mut self, pool_state: solana_address::Address) -> &mut Self { + self.pool_state = Some(pool_state); + self + } + /// `[optional account, default to PDA derived from 'baseVault']` + /// Token account that holds the pool's base tokens + /// PDA generated using POOL_VAULT_SEED + #[inline(always)] + pub fn base_vault(&mut self, base_vault: solana_address::Address) -> &mut Self { + self.base_vault = Some(base_vault); + self + } + /// `[optional account, default to PDA derived from 'quoteVault']` + /// Token account that holds the pool's quote tokens + /// PDA generated using POOL_VAULT_SEED + #[inline(always)] + pub fn quote_vault(&mut self, quote_vault: solana_address::Address) -> &mut Self { + self.quote_vault = Some(quote_vault); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the base token + /// Must be the standard Token program + #[inline(always)] + pub fn base_token_program(&mut self, base_token_program: solana_address::Address) -> &mut Self { + self.base_token_program = Some(base_token_program); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the quote token + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s']` + /// Metaplex Token Metadata program + /// Used to create metadata for the base token + #[inline(always)] + pub fn metadata_program(&mut self, metadata_program: solana_address::Address) -> &mut Self { + self.metadata_program = Some(metadata_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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']` + /// Required for rent exempt calculations + #[inline(always)] + pub fn rent_program(&mut self, rent_program: solana_address::Address) -> &mut Self { + self.rent_program = Some(rent_program); + self + } + /// `[optional account, default to PDA derived from 'eventAuthority']` + #[inline(always)] + pub fn event_authority(&mut self, event_authority: solana_address::Address) -> &mut Self { + self.event_authority = Some(event_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 payer = self.payer; + let creator = self.creator; + let global_config = self.global_config; + let platform_config = self.platform_config; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let base_mint = self.base_mint; + let quote_mint = self.quote_mint; + let pool_state = self.pool_state.unwrap_or_else(|| { + crate::pdas::find_pool_state_pda(&self.base_mint, &self.quote_mint).0 + }); + let base_vault = self + .base_vault + .unwrap_or_else(|| crate::pdas::find_base_vault_pda(&pool_state, &self.base_mint).0); + let quote_vault = self + .quote_vault + .unwrap_or_else(|| crate::pdas::find_quote_vault_pda(&pool_state, &self.quote_mint).0); + let metadata_account = self.metadata_account; + let base_token_program = self.base_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let metadata_program = self.metadata_program.unwrap_or(solana_address::address!( + "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let rent_program = self.rent_program.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let event_authority = self + .event_authority + .unwrap_or(crate::pdas::EVENT_AUTHORITY_ADDRESS); + let program = self.program; + let accounts = Initialize { + payer, + creator, + global_config, + platform_config, + authority, + pool_state, + base_mint, + quote_mint, + base_vault, + quote_vault, + metadata_account, + base_token_program, + quote_token_program, + metadata_program, + system_program, + rent_program, + event_authority, + program, + }; + let args = InitializeInstructionArgs { + base_mint_param: self.base_mint_param.clone(), + curve_param: self.curve_param.clone(), + vesting_param: self.vesting_param.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `initialize` CPI accounts. +pub struct InitializeCpiAccounts<'a, 'b> { + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub creator: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Includes settings like quote token mint and fee parameters + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform info + /// Includes settings like the fee_rate, name, web, img of the platform + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + /// Must match the quote_mint specified in global config + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the pool's base tokens + /// PDA generated using POOL_VAULT_SEED + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the pool's quote tokens + /// PDA generated using POOL_VAULT_SEED + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// Account to store the base token's metadata + /// Created using Metaplex metadata program + pub metadata_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the quote token + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Metaplex Token Metadata program + /// Used to create metadata for the base token + pub metadata_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `initialize` CPI instruction. +pub struct InitializeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The account paying for the initialization costs + /// This can be any account with sufficient SOL to cover the transaction + pub payer: &'b solana_account_info::AccountInfo<'a>, + + pub creator: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Includes settings like quote token mint and fee parameters + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform info + /// Includes settings like the fee_rate, name, web, img of the platform + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault and mint operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + /// Created in this instruction with specified decimals + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + /// Must match the quote_mint specified in global config + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the pool's base tokens + /// PDA generated using POOL_VAULT_SEED + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the pool's quote tokens + /// PDA generated using POOL_VAULT_SEED + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// Account to store the base token's metadata + /// Created using Metaplex metadata program + pub metadata_account: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the quote token + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Metaplex Token Metadata program + /// Used to create metadata for the base token + pub metadata_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InitializeInstructionArgs, +} + +impl<'a, 'b> InitializeCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: InitializeCpiAccounts<'a, 'b>, + args: InitializeInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + creator: accounts.creator, + global_config: accounts.global_config, + platform_config: accounts.platform_config, + authority: accounts.authority, + pool_state: accounts.pool_state, + base_mint: accounts.base_mint, + quote_mint: accounts.quote_mint, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + metadata_account: accounts.metadata_account, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + metadata_program: accounts.metadata_program, + system_program: accounts.system_program, + rent_program: accounts.rent_program, + event_authority: accounts.event_authority, + program: accounts.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(18 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(*self.payer.key, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.creator.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_mint.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.metadata_account.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.metadata_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.rent_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.event_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *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 mut data = InitializeInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(19 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.creator.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.base_mint.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.metadata_account.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.metadata_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.rent_program.clone()); + account_infos.push(self.event_authority.clone()); + 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 `Initialize` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` creator +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[]` authority +/// 5. `[writable]` pool_state +/// 6. `[writable, signer]` base_mint +/// 7. `[]` quote_mint +/// 8. `[writable]` base_vault +/// 9. `[writable]` quote_vault +/// 10. `[writable]` metadata_account +/// 11. `[]` base_token_program +/// 12. `[]` quote_token_program +/// 13. `[]` metadata_program +/// 14. `[]` system_program +/// 15. `[]` rent_program +/// 16. `[]` event_authority +/// 17. `[]` program +#[derive(Clone, Debug)] +pub struct InitializeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + metadata_account: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + metadata_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + base_mint_param: MintParams, + curve_param: CurveParams, + vesting_param: VestingParams, + ) -> Self { + let instruction = Box::new(InitializeCpiBuilderInstruction { + __program, + payer, + creator, + global_config, + platform_config, + authority, + pool_state, + base_mint, + quote_mint, + base_vault, + quote_vault, + metadata_account, + base_token_program, + quote_token_program, + metadata_program, + system_program, + rent_program, + event_authority, + program, + base_mint_param, + curve_param, + vesting_param, + __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 = InitializeInstructionArgs { + base_mint_param: self.instruction.base_mint_param.clone(), + curve_param: self.instruction.curve_param.clone(), + vesting_param: self.instruction.vesting_param.clone(), + }; + let instruction = InitializeCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + creator: self.instruction.creator, + global_config: self.instruction.global_config, + platform_config: self.instruction.platform_config, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + base_mint: self.instruction.base_mint, + quote_mint: self.instruction.quote_mint, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + metadata_account: self.instruction.metadata_account, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + metadata_program: self.instruction.metadata_program, + system_program: self.instruction.system_program, + rent_program: self.instruction.rent_program, + event_authority: self.instruction.event_authority, + program: self.instruction.program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InitializeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + creator: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + metadata_account: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + metadata_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + base_mint_param: MintParams, + curve_param: CurveParams, + vesting_param: VestingParams, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/migrate_to_amm.rs b/e2e/raydium-launchpad/src/generated/instructions/migrate_to_amm.rs new file mode 100644 index 0000000..e19f5e6 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/migrate_to_amm.rs @@ -0,0 +1,1267 @@ +//! 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 MIGRATE_TO_AMM_DISCRIMINATOR: [u8; 8] = [207, 82, 192, 145, 254, 207, 145, 223]; + +/// Accounts. +#[derive(Debug)] +pub struct MigrateToAmm { + /// Only migrate_to_amm_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_amm_wallet saved in global_config + pub payer: solana_address::Address, + /// The mint for the base token (token being sold) + pub base_mint: solana_address::Address, + /// The mint for the quote token (token used to buy) + pub quote_mint: solana_address::Address, + + pub openbook_program: solana_address::Address, + /// Account created and asigned to openbook_program but not been initialized + pub market: solana_address::Address, + /// Account created and asigned to openbook_program but not been initialized + pub request_queue: solana_address::Address, + /// Account created and asigned to openbook_program but not been initialized + pub event_queue: solana_address::Address, + /// Account created and asigned to openbook_program but not been initialized + pub bids: solana_address::Address, + /// Account created and asigned to openbook_program but not been initialized + pub asks: solana_address::Address, + + pub market_vault_signer: solana_address::Address, + /// Token account that holds the market's base tokens + pub market_base_vault: solana_address::Address, + /// Token account that holds the market's quote tokens + pub market_quote_vault: solana_address::Address, + + pub amm_program: solana_address::Address, + + pub amm_pool: solana_address::Address, + + pub amm_authority: solana_address::Address, + + pub amm_open_orders: solana_address::Address, + + pub amm_lp_mint: solana_address::Address, + + pub amm_base_vault: solana_address::Address, + + pub amm_quote_vault: solana_address::Address, + + pub amm_target_orders: solana_address::Address, + + pub amm_config: solana_address::Address, + + pub amm_create_fee_destination: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: solana_address::Address, + /// Global config account stores owner + pub global_config: solana_address::Address, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: solana_address::Address, + + pub pool_lp_token: solana_address::Address, + /// SPL Token program for the base token + /// Must be the standard Token program + pub spl_token_program: solana_address::Address, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, + /// Required for rent exempt calculations + pub rent_program: solana_address::Address, +} + +impl MigrateToAmm { + pub fn instruction( + &self, + args: MigrateToAmmInstructionArgs, + ) -> 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: MigrateToAmmInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(32 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.payer, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.openbook_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.market, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.request_queue, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.event_queue, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.bids, false)); + accounts.push(solana_instruction::AccountMeta::new(self.asks, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.market_vault_signer, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.market_base_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.market_quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.amm_pool, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_open_orders, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_lp_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_base_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_target_orders, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.amm_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.amm_create_fee_destination, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.authority, false)); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.pool_lp_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.spl_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.associated_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.rent_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = MigrateToAmmInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct MigrateToAmmInstructionData { + discriminator: [u8; 8], +} + +impl MigrateToAmmInstructionData { + pub fn new() -> Self { + Self { + discriminator: [207, 82, 192, 145, 254, 207, 145, 223], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for MigrateToAmmInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct MigrateToAmmInstructionArgs { + pub base_lot_size: u64, + pub quote_lot_size: u64, + pub market_vault_signer_nonce: u8, +} + +impl MigrateToAmmInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `MigrateToAmm`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` base_mint +/// 2. `[]` quote_mint +/// 3. `[optional]` openbook_program (default to `srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX`) +/// 4. `[writable]` market +/// 5. `[writable]` request_queue +/// 6. `[writable]` event_queue +/// 7. `[writable]` bids +/// 8. `[writable]` asks +/// 9. `[]` market_vault_signer +/// 10. `[writable]` market_base_vault +/// 11. `[writable]` market_quote_vault +/// 12. `[optional]` amm_program (default to `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`) +/// 13. `[writable, optional]` amm_pool (default to PDA derived from 'ammPool') +/// 14. `[optional]` amm_authority (default to PDA derived from 'ammAuthority') +/// 15. `[writable, optional]` amm_open_orders (default to PDA derived from 'ammOpenOrders') +/// 16. `[writable, optional]` amm_lp_mint (default to PDA derived from 'ammLpMint') +/// 17. `[writable, optional]` amm_base_vault (default to PDA derived from 'ammBaseVault') +/// 18. `[writable, optional]` amm_quote_vault (default to PDA derived from 'ammQuoteVault') +/// 19. `[writable, optional]` amm_target_orders (default to PDA derived from 'ammTargetOrders') +/// 20. `[optional]` amm_config (default to PDA derived from 'ammConfig') +/// 21. `[writable]` amm_create_fee_destination +/// 22. `[writable, optional]` authority (default to PDA derived from 'authority') +/// 23. `[writable, optional]` pool_state (default to PDA derived from 'poolState') +/// 24. `[]` global_config +/// 25. `[writable]` base_vault +/// 26. `[writable]` quote_vault +/// 27. `[writable]` pool_lp_token +/// 28. `[optional]` spl_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 29. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) +/// 30. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 31. `[optional]` rent_program (default to `SysvarRent111111111111111111111111111111111`) +#[derive(Clone, Debug)] +pub struct MigrateToAmmBuilder { + payer: solana_address::Address, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + openbook_program: Option, + market: solana_address::Address, + request_queue: solana_address::Address, + event_queue: solana_address::Address, + bids: solana_address::Address, + asks: solana_address::Address, + market_vault_signer: solana_address::Address, + market_base_vault: solana_address::Address, + market_quote_vault: solana_address::Address, + amm_program: Option, + amm_pool: Option, + amm_authority: Option, + amm_open_orders: Option, + amm_lp_mint: Option, + amm_base_vault: Option, + amm_quote_vault: Option, + amm_target_orders: Option, + amm_config: Option, + amm_create_fee_destination: solana_address::Address, + authority: Option, + pool_state: Option, + global_config: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + pool_lp_token: solana_address::Address, + spl_token_program: Option, + associated_token_program: Option, + system_program: Option, + rent_program: Option, + base_lot_size: u64, + quote_lot_size: u64, + market_vault_signer_nonce: u8, + __remaining_accounts: Vec, +} + +impl MigrateToAmmBuilder { + pub fn new( + payer: solana_address::Address, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + market: solana_address::Address, + request_queue: solana_address::Address, + event_queue: solana_address::Address, + bids: solana_address::Address, + asks: solana_address::Address, + market_vault_signer: solana_address::Address, + market_base_vault: solana_address::Address, + market_quote_vault: solana_address::Address, + amm_create_fee_destination: solana_address::Address, + global_config: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + pool_lp_token: solana_address::Address, + base_lot_size: u64, + quote_lot_size: u64, + market_vault_signer_nonce: u8, + ) -> Self { + Self { + payer, + base_mint, + quote_mint, + openbook_program: None, + market, + request_queue, + event_queue, + bids, + asks, + market_vault_signer, + market_base_vault, + market_quote_vault, + amm_program: None, + amm_pool: None, + amm_authority: None, + amm_open_orders: None, + amm_lp_mint: None, + amm_base_vault: None, + amm_quote_vault: None, + amm_target_orders: None, + amm_config: None, + amm_create_fee_destination, + authority: None, + pool_state: None, + global_config, + base_vault, + quote_vault, + pool_lp_token, + spl_token_program: None, + associated_token_program: None, + system_program: None, + rent_program: None, + base_lot_size, + quote_lot_size, + market_vault_signer_nonce, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX']` + #[inline(always)] + pub fn openbook_program(&mut self, openbook_program: solana_address::Address) -> &mut Self { + self.openbook_program = Some(openbook_program); + self + } + /// `[optional account, default to '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8']` + #[inline(always)] + pub fn amm_program(&mut self, amm_program: solana_address::Address) -> &mut Self { + self.amm_program = Some(amm_program); + self + } + /// `[optional account, default to PDA derived from 'ammPool']` + #[inline(always)] + pub fn amm_pool(&mut self, amm_pool: solana_address::Address) -> &mut Self { + self.amm_pool = Some(amm_pool); + self + } + /// `[optional account, default to PDA derived from 'ammAuthority']` + #[inline(always)] + pub fn amm_authority(&mut self, amm_authority: solana_address::Address) -> &mut Self { + self.amm_authority = Some(amm_authority); + self + } + /// `[optional account, default to PDA derived from 'ammOpenOrders']` + #[inline(always)] + pub fn amm_open_orders(&mut self, amm_open_orders: solana_address::Address) -> &mut Self { + self.amm_open_orders = Some(amm_open_orders); + self + } + /// `[optional account, default to PDA derived from 'ammLpMint']` + #[inline(always)] + pub fn amm_lp_mint(&mut self, amm_lp_mint: solana_address::Address) -> &mut Self { + self.amm_lp_mint = Some(amm_lp_mint); + self + } + /// `[optional account, default to PDA derived from 'ammBaseVault']` + #[inline(always)] + pub fn amm_base_vault(&mut self, amm_base_vault: solana_address::Address) -> &mut Self { + self.amm_base_vault = Some(amm_base_vault); + self + } + /// `[optional account, default to PDA derived from 'ammQuoteVault']` + #[inline(always)] + pub fn amm_quote_vault(&mut self, amm_quote_vault: solana_address::Address) -> &mut Self { + self.amm_quote_vault = Some(amm_quote_vault); + self + } + /// `[optional account, default to PDA derived from 'ammTargetOrders']` + #[inline(always)] + pub fn amm_target_orders(&mut self, amm_target_orders: solana_address::Address) -> &mut Self { + self.amm_target_orders = Some(amm_target_orders); + self + } + /// `[optional account, default to PDA derived from 'ammConfig']` + #[inline(always)] + pub fn amm_config(&mut self, amm_config: solana_address::Address) -> &mut Self { + self.amm_config = Some(amm_config); + self + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'poolState']` + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + #[inline(always)] + pub fn pool_state(&mut self, pool_state: solana_address::Address) -> &mut Self { + self.pool_state = Some(pool_state); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the base token + /// Must be the standard Token program + #[inline(always)] + pub fn spl_token_program(&mut self, spl_token_program: solana_address::Address) -> &mut Self { + self.spl_token_program = Some(spl_token_program); + self + } + /// `[optional account, default to 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` + /// Program to create an ATA for receiving fee NFT + #[inline(always)] + pub fn associated_token_program( + &mut self, + associated_token_program: solana_address::Address, + ) -> &mut Self { + self.associated_token_program = Some(associated_token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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']` + /// Required for rent exempt calculations + #[inline(always)] + pub fn rent_program(&mut self, rent_program: solana_address::Address) -> &mut Self { + self.rent_program = Some(rent_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 payer = self.payer; + let base_mint = self.base_mint; + let quote_mint = self.quote_mint; + let openbook_program = self.openbook_program.unwrap_or(solana_address::address!( + "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX" + )); + let market = self.market; + let request_queue = self.request_queue; + let event_queue = self.event_queue; + let bids = self.bids; + let asks = self.asks; + let market_vault_signer = self.market_vault_signer; + let market_base_vault = self.market_base_vault; + let market_quote_vault = self.market_quote_vault; + let amm_program = self.amm_program.unwrap_or(solana_address::address!( + "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8" + )); + let amm_pool = self + .amm_pool + .unwrap_or_else(|| crate::pdas::find_amm_pool_pda(&self.market).0); + let amm_authority = self + .amm_authority + .unwrap_or(crate::pdas::AMM_AUTHORITY_ADDRESS); + let amm_open_orders = self + .amm_open_orders + .unwrap_or_else(|| crate::pdas::find_amm_open_orders_pda(&self.market).0); + let amm_lp_mint = self + .amm_lp_mint + .unwrap_or_else(|| crate::pdas::find_amm_lp_mint_pda(&self.market).0); + let amm_base_vault = self + .amm_base_vault + .unwrap_or_else(|| crate::pdas::find_amm_base_vault_pda(&self.market).0); + let amm_quote_vault = self + .amm_quote_vault + .unwrap_or_else(|| crate::pdas::find_amm_quote_vault_pda(&self.market).0); + let amm_target_orders = self + .amm_target_orders + .unwrap_or_else(|| crate::pdas::find_amm_target_orders_pda(&self.market).0); + let amm_config = self.amm_config.unwrap_or(crate::pdas::AMM_CONFIG_ADDRESS); + let amm_create_fee_destination = self.amm_create_fee_destination; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state.unwrap_or_else(|| { + crate::pdas::find_pool_state_pda(&self.base_mint, &self.quote_mint).0 + }); + let global_config = self.global_config; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let pool_lp_token = self.pool_lp_token; + let spl_token_program = self.spl_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let rent_program = self.rent_program.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let accounts = MigrateToAmm { + payer, + base_mint, + quote_mint, + openbook_program, + market, + request_queue, + event_queue, + bids, + asks, + market_vault_signer, + market_base_vault, + market_quote_vault, + amm_program, + amm_pool, + amm_authority, + amm_open_orders, + amm_lp_mint, + amm_base_vault, + amm_quote_vault, + amm_target_orders, + amm_config, + amm_create_fee_destination, + authority, + pool_state, + global_config, + base_vault, + quote_vault, + pool_lp_token, + spl_token_program, + associated_token_program, + system_program, + rent_program, + }; + let args = MigrateToAmmInstructionArgs { + base_lot_size: self.base_lot_size.clone(), + quote_lot_size: self.quote_lot_size.clone(), + market_vault_signer_nonce: self.market_vault_signer_nonce.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `migrate_to_amm` CPI accounts. +pub struct MigrateToAmmCpiAccounts<'a, 'b> { + /// Only migrate_to_amm_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_amm_wallet saved in global_config + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + + pub openbook_program: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub market: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub request_queue: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub event_queue: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub bids: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub asks: &'b solana_account_info::AccountInfo<'a>, + + pub market_vault_signer: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the market's base tokens + pub market_base_vault: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the market's quote tokens + pub market_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_program: &'b solana_account_info::AccountInfo<'a>, + + pub amm_pool: &'b solana_account_info::AccountInfo<'a>, + + pub amm_authority: &'b solana_account_info::AccountInfo<'a>, + + pub amm_open_orders: &'b solana_account_info::AccountInfo<'a>, + + pub amm_lp_mint: &'b solana_account_info::AccountInfo<'a>, + + pub amm_base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_target_orders: &'b solana_account_info::AccountInfo<'a>, + + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + + pub amm_create_fee_destination: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub spl_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `migrate_to_amm` CPI instruction. +pub struct MigrateToAmmCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only migrate_to_amm_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_amm_wallet saved in global_config + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + + pub openbook_program: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub market: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub request_queue: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub event_queue: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub bids: &'b solana_account_info::AccountInfo<'a>, + /// Account created and asigned to openbook_program but not been initialized + pub asks: &'b solana_account_info::AccountInfo<'a>, + + pub market_vault_signer: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the market's base tokens + pub market_base_vault: &'b solana_account_info::AccountInfo<'a>, + /// Token account that holds the market's quote tokens + pub market_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_program: &'b solana_account_info::AccountInfo<'a>, + + pub amm_pool: &'b solana_account_info::AccountInfo<'a>, + + pub amm_authority: &'b solana_account_info::AccountInfo<'a>, + + pub amm_open_orders: &'b solana_account_info::AccountInfo<'a>, + + pub amm_lp_mint: &'b solana_account_info::AccountInfo<'a>, + + pub amm_base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub amm_target_orders: &'b solana_account_info::AccountInfo<'a>, + + pub amm_config: &'b solana_account_info::AccountInfo<'a>, + + pub amm_create_fee_destination: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub spl_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: MigrateToAmmInstructionArgs, +} + +impl<'a, 'b> MigrateToAmmCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: MigrateToAmmCpiAccounts<'a, 'b>, + args: MigrateToAmmInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + base_mint: accounts.base_mint, + quote_mint: accounts.quote_mint, + openbook_program: accounts.openbook_program, + market: accounts.market, + request_queue: accounts.request_queue, + event_queue: accounts.event_queue, + bids: accounts.bids, + asks: accounts.asks, + market_vault_signer: accounts.market_vault_signer, + market_base_vault: accounts.market_base_vault, + market_quote_vault: accounts.market_quote_vault, + amm_program: accounts.amm_program, + amm_pool: accounts.amm_pool, + amm_authority: accounts.amm_authority, + amm_open_orders: accounts.amm_open_orders, + amm_lp_mint: accounts.amm_lp_mint, + amm_base_vault: accounts.amm_base_vault, + amm_quote_vault: accounts.amm_quote_vault, + amm_target_orders: accounts.amm_target_orders, + amm_config: accounts.amm_config, + amm_create_fee_destination: accounts.amm_create_fee_destination, + authority: accounts.authority, + pool_state: accounts.pool_state, + global_config: accounts.global_config, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + pool_lp_token: accounts.pool_lp_token, + spl_token_program: accounts.spl_token_program, + associated_token_program: accounts.associated_token_program, + system_program: accounts.system_program, + rent_program: accounts.rent_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(32 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(*self.payer.key, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.openbook_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.market.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.request_queue.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.event_queue.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(*self.bids.key, false)); + accounts.push(solana_instruction::AccountMeta::new(*self.asks.key, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.market_vault_signer.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.market_base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.market_quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_pool.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_open_orders.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_lp_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_target_orders.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.amm_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.amm_create_fee_destination.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_lp_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.spl_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.associated_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.rent_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 = MigrateToAmmInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(33 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.base_mint.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.openbook_program.clone()); + account_infos.push(self.market.clone()); + account_infos.push(self.request_queue.clone()); + account_infos.push(self.event_queue.clone()); + account_infos.push(self.bids.clone()); + account_infos.push(self.asks.clone()); + account_infos.push(self.market_vault_signer.clone()); + account_infos.push(self.market_base_vault.clone()); + account_infos.push(self.market_quote_vault.clone()); + account_infos.push(self.amm_program.clone()); + account_infos.push(self.amm_pool.clone()); + account_infos.push(self.amm_authority.clone()); + account_infos.push(self.amm_open_orders.clone()); + account_infos.push(self.amm_lp_mint.clone()); + account_infos.push(self.amm_base_vault.clone()); + account_infos.push(self.amm_quote_vault.clone()); + account_infos.push(self.amm_target_orders.clone()); + account_infos.push(self.amm_config.clone()); + account_infos.push(self.amm_create_fee_destination.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.pool_lp_token.clone()); + account_infos.push(self.spl_token_program.clone()); + account_infos.push(self.associated_token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.rent_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 `MigrateToAmm` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` base_mint +/// 2. `[]` quote_mint +/// 3. `[]` openbook_program +/// 4. `[writable]` market +/// 5. `[writable]` request_queue +/// 6. `[writable]` event_queue +/// 7. `[writable]` bids +/// 8. `[writable]` asks +/// 9. `[]` market_vault_signer +/// 10. `[writable]` market_base_vault +/// 11. `[writable]` market_quote_vault +/// 12. `[]` amm_program +/// 13. `[writable]` amm_pool +/// 14. `[]` amm_authority +/// 15. `[writable]` amm_open_orders +/// 16. `[writable]` amm_lp_mint +/// 17. `[writable]` amm_base_vault +/// 18. `[writable]` amm_quote_vault +/// 19. `[writable]` amm_target_orders +/// 20. `[]` amm_config +/// 21. `[writable]` amm_create_fee_destination +/// 22. `[writable]` authority +/// 23. `[writable]` pool_state +/// 24. `[]` global_config +/// 25. `[writable]` base_vault +/// 26. `[writable]` quote_vault +/// 27. `[writable]` pool_lp_token +/// 28. `[]` spl_token_program +/// 29. `[]` associated_token_program +/// 30. `[]` system_program +/// 31. `[]` rent_program +#[derive(Clone, Debug)] +pub struct MigrateToAmmCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> MigrateToAmmCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + openbook_program: &'b solana_account_info::AccountInfo<'a>, + market: &'b solana_account_info::AccountInfo<'a>, + request_queue: &'b solana_account_info::AccountInfo<'a>, + event_queue: &'b solana_account_info::AccountInfo<'a>, + bids: &'b solana_account_info::AccountInfo<'a>, + asks: &'b solana_account_info::AccountInfo<'a>, + market_vault_signer: &'b solana_account_info::AccountInfo<'a>, + market_base_vault: &'b solana_account_info::AccountInfo<'a>, + market_quote_vault: &'b solana_account_info::AccountInfo<'a>, + amm_program: &'b solana_account_info::AccountInfo<'a>, + amm_pool: &'b solana_account_info::AccountInfo<'a>, + amm_authority: &'b solana_account_info::AccountInfo<'a>, + amm_open_orders: &'b solana_account_info::AccountInfo<'a>, + amm_lp_mint: &'b solana_account_info::AccountInfo<'a>, + amm_base_vault: &'b solana_account_info::AccountInfo<'a>, + amm_quote_vault: &'b solana_account_info::AccountInfo<'a>, + amm_target_orders: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + amm_create_fee_destination: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + spl_token_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + base_lot_size: u64, + quote_lot_size: u64, + market_vault_signer_nonce: u8, + ) -> Self { + let instruction = Box::new(MigrateToAmmCpiBuilderInstruction { + __program, + payer, + base_mint, + quote_mint, + openbook_program, + market, + request_queue, + event_queue, + bids, + asks, + market_vault_signer, + market_base_vault, + market_quote_vault, + amm_program, + amm_pool, + amm_authority, + amm_open_orders, + amm_lp_mint, + amm_base_vault, + amm_quote_vault, + amm_target_orders, + amm_config, + amm_create_fee_destination, + authority, + pool_state, + global_config, + base_vault, + quote_vault, + pool_lp_token, + spl_token_program, + associated_token_program, + system_program, + rent_program, + base_lot_size, + quote_lot_size, + market_vault_signer_nonce, + __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 = MigrateToAmmInstructionArgs { + base_lot_size: self.instruction.base_lot_size.clone(), + quote_lot_size: self.instruction.quote_lot_size.clone(), + market_vault_signer_nonce: self.instruction.market_vault_signer_nonce.clone(), + }; + let instruction = MigrateToAmmCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + base_mint: self.instruction.base_mint, + quote_mint: self.instruction.quote_mint, + openbook_program: self.instruction.openbook_program, + market: self.instruction.market, + request_queue: self.instruction.request_queue, + event_queue: self.instruction.event_queue, + bids: self.instruction.bids, + asks: self.instruction.asks, + market_vault_signer: self.instruction.market_vault_signer, + market_base_vault: self.instruction.market_base_vault, + market_quote_vault: self.instruction.market_quote_vault, + amm_program: self.instruction.amm_program, + amm_pool: self.instruction.amm_pool, + amm_authority: self.instruction.amm_authority, + amm_open_orders: self.instruction.amm_open_orders, + amm_lp_mint: self.instruction.amm_lp_mint, + amm_base_vault: self.instruction.amm_base_vault, + amm_quote_vault: self.instruction.amm_quote_vault, + amm_target_orders: self.instruction.amm_target_orders, + amm_config: self.instruction.amm_config, + amm_create_fee_destination: self.instruction.amm_create_fee_destination, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + global_config: self.instruction.global_config, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + pool_lp_token: self.instruction.pool_lp_token, + spl_token_program: self.instruction.spl_token_program, + associated_token_program: self.instruction.associated_token_program, + system_program: self.instruction.system_program, + rent_program: self.instruction.rent_program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct MigrateToAmmCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + openbook_program: &'b solana_account_info::AccountInfo<'a>, + market: &'b solana_account_info::AccountInfo<'a>, + request_queue: &'b solana_account_info::AccountInfo<'a>, + event_queue: &'b solana_account_info::AccountInfo<'a>, + bids: &'b solana_account_info::AccountInfo<'a>, + asks: &'b solana_account_info::AccountInfo<'a>, + market_vault_signer: &'b solana_account_info::AccountInfo<'a>, + market_base_vault: &'b solana_account_info::AccountInfo<'a>, + market_quote_vault: &'b solana_account_info::AccountInfo<'a>, + amm_program: &'b solana_account_info::AccountInfo<'a>, + amm_pool: &'b solana_account_info::AccountInfo<'a>, + amm_authority: &'b solana_account_info::AccountInfo<'a>, + amm_open_orders: &'b solana_account_info::AccountInfo<'a>, + amm_lp_mint: &'b solana_account_info::AccountInfo<'a>, + amm_base_vault: &'b solana_account_info::AccountInfo<'a>, + amm_quote_vault: &'b solana_account_info::AccountInfo<'a>, + amm_target_orders: &'b solana_account_info::AccountInfo<'a>, + amm_config: &'b solana_account_info::AccountInfo<'a>, + amm_create_fee_destination: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + spl_token_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + base_lot_size: u64, + quote_lot_size: u64, + market_vault_signer_nonce: u8, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/migrate_to_cpswap.rs b/e2e/raydium-launchpad/src/generated/instructions/migrate_to_cpswap.rs new file mode 100644 index 0000000..5f5683e --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/migrate_to_cpswap.rs @@ -0,0 +1,1160 @@ +//! 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 MIGRATE_TO_CPSWAP_DISCRIMINATOR: [u8; 8] = [136, 92, 200, 103, 28, 218, 144, 140]; + +/// Accounts. +#[derive(Debug)] +pub struct MigrateToCpswap { + /// Only migrate_to_cpswap_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_cpswap_wallet saved in global_config + pub payer: solana_address::Address, + /// The mint for the base token (token being sold) + pub base_mint: solana_address::Address, + /// The mint for the quote token (token used to buy) + pub quote_mint: solana_address::Address, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: solana_address::Address, + + pub cpswap_program: solana_address::Address, + /// PDA account: + /// seeds = [ + /// b"pool", + /// cpswap_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// seeds::program = cpswap_program, + /// + /// Or random account: must be signed by cli + pub cpswap_pool: solana_address::Address, + + pub cpswap_authority: solana_address::Address, + + pub cpswap_lp_mint: solana_address::Address, + + pub cpswap_base_vault: solana_address::Address, + + pub cpswap_quote_vault: solana_address::Address, + + pub cpswap_config: solana_address::Address, + + pub cpswap_create_pool_fee: solana_address::Address, + + pub cpswap_observation: solana_address::Address, + + pub lock_program: solana_address::Address, + + pub lock_authority: solana_address::Address, + + pub lock_lp_vault: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: solana_address::Address, + /// Global config account stores owner + pub global_config: solana_address::Address, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: solana_address::Address, + + pub pool_lp_token: solana_address::Address, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: solana_address::Address, + /// SPL Token program for the quote token + pub quote_token_program: solana_address::Address, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: solana_address::Address, + /// Required for account creation + pub system_program: solana_address::Address, + /// Required for rent exempt calculations + pub rent_program: solana_address::Address, + /// Program to create NFT metadata accunt + pub metadata_program: solana_address::Address, +} + +impl MigrateToCpswap { + 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(28 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(self.payer, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.cpswap_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_pool, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.cpswap_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_lp_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_base_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.cpswap_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_create_pool_fee, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.cpswap_observation, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.lock_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.lock_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.lock_lp_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.authority, false)); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.pool_lp_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.associated_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.rent_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.metadata_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = MigrateToCpswapInstructionData::new().try_to_vec().unwrap(); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct MigrateToCpswapInstructionData { + discriminator: [u8; 8], +} + +impl MigrateToCpswapInstructionData { + pub fn new() -> Self { + Self { + discriminator: [136, 92, 200, 103, 28, 218, 144, 140], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for MigrateToCpswapInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `MigrateToCpswap`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` base_mint +/// 2. `[]` quote_mint +/// 3. `[]` platform_config +/// 4. `[optional]` cpswap_program (default to `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C`) +/// 5. `[writable]` cpswap_pool +/// 6. `[optional]` cpswap_authority (default to PDA derived from 'cpswapAuthority') +/// 7. `[writable, optional]` cpswap_lp_mint (default to PDA derived from 'cpswapLpMint') +/// 8. `[writable, optional]` cpswap_base_vault (default to PDA derived from 'cpswapBaseVault') +/// 9. `[writable, optional]` cpswap_quote_vault (default to PDA derived from 'cpswapQuoteVault') +/// 10. `[]` cpswap_config +/// 11. `[writable]` cpswap_create_pool_fee +/// 12. `[writable, optional]` cpswap_observation (default to PDA derived from 'cpswapObservation') +/// 13. `[optional]` lock_program (default to `LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE`) +/// 14. `[optional]` lock_authority (default to PDA derived from 'lockAuthority') +/// 15. `[writable]` lock_lp_vault +/// 16. `[writable, optional]` authority (default to PDA derived from 'authority') +/// 17. `[writable, optional]` pool_state (default to PDA derived from 'poolState') +/// 18. `[]` global_config +/// 19. `[writable]` base_vault +/// 20. `[writable]` quote_vault +/// 21. `[writable]` pool_lp_token +/// 22. `[optional]` base_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 23. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 24. `[optional]` associated_token_program (default to `ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL`) +/// 25. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 26. `[optional]` rent_program (default to `SysvarRent111111111111111111111111111111111`) +/// 27. `[optional]` metadata_program (default to `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s`) +#[derive(Clone, Debug)] +pub struct MigrateToCpswapBuilder { + payer: solana_address::Address, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + platform_config: solana_address::Address, + cpswap_program: Option, + cpswap_pool: solana_address::Address, + cpswap_authority: Option, + cpswap_lp_mint: Option, + cpswap_base_vault: Option, + cpswap_quote_vault: Option, + cpswap_config: solana_address::Address, + cpswap_create_pool_fee: solana_address::Address, + cpswap_observation: Option, + lock_program: Option, + lock_authority: Option, + lock_lp_vault: solana_address::Address, + authority: Option, + pool_state: Option, + global_config: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + pool_lp_token: solana_address::Address, + base_token_program: Option, + quote_token_program: Option, + associated_token_program: Option, + system_program: Option, + rent_program: Option, + metadata_program: Option, + __remaining_accounts: Vec, +} + +impl MigrateToCpswapBuilder { + pub fn new( + payer: solana_address::Address, + base_mint: solana_address::Address, + quote_mint: solana_address::Address, + platform_config: solana_address::Address, + cpswap_pool: solana_address::Address, + cpswap_config: solana_address::Address, + cpswap_create_pool_fee: solana_address::Address, + lock_lp_vault: solana_address::Address, + global_config: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + pool_lp_token: solana_address::Address, + ) -> Self { + Self { + payer, + base_mint, + quote_mint, + platform_config, + cpswap_program: None, + cpswap_pool, + cpswap_authority: None, + cpswap_lp_mint: None, + cpswap_base_vault: None, + cpswap_quote_vault: None, + cpswap_config, + cpswap_create_pool_fee, + cpswap_observation: None, + lock_program: None, + lock_authority: None, + lock_lp_vault, + authority: None, + pool_state: None, + global_config, + base_vault, + quote_vault, + pool_lp_token, + base_token_program: None, + quote_token_program: None, + associated_token_program: None, + system_program: None, + rent_program: None, + metadata_program: None, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C']` + #[inline(always)] + pub fn cpswap_program(&mut self, cpswap_program: solana_address::Address) -> &mut Self { + self.cpswap_program = Some(cpswap_program); + self + } + /// `[optional account, default to PDA derived from 'cpswapAuthority']` + #[inline(always)] + pub fn cpswap_authority(&mut self, cpswap_authority: solana_address::Address) -> &mut Self { + self.cpswap_authority = Some(cpswap_authority); + self + } + /// `[optional account, default to PDA derived from 'cpswapLpMint']` + #[inline(always)] + pub fn cpswap_lp_mint(&mut self, cpswap_lp_mint: solana_address::Address) -> &mut Self { + self.cpswap_lp_mint = Some(cpswap_lp_mint); + self + } + /// `[optional account, default to PDA derived from 'cpswapBaseVault']` + #[inline(always)] + pub fn cpswap_base_vault(&mut self, cpswap_base_vault: solana_address::Address) -> &mut Self { + self.cpswap_base_vault = Some(cpswap_base_vault); + self + } + /// `[optional account, default to PDA derived from 'cpswapQuoteVault']` + #[inline(always)] + pub fn cpswap_quote_vault(&mut self, cpswap_quote_vault: solana_address::Address) -> &mut Self { + self.cpswap_quote_vault = Some(cpswap_quote_vault); + self + } + /// `[optional account, default to PDA derived from 'cpswapObservation']` + #[inline(always)] + pub fn cpswap_observation(&mut self, cpswap_observation: solana_address::Address) -> &mut Self { + self.cpswap_observation = Some(cpswap_observation); + self + } + /// `[optional account, default to 'LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE']` + #[inline(always)] + pub fn lock_program(&mut self, lock_program: solana_address::Address) -> &mut Self { + self.lock_program = Some(lock_program); + self + } + /// `[optional account, default to PDA derived from 'lockAuthority']` + #[inline(always)] + pub fn lock_authority(&mut self, lock_authority: solana_address::Address) -> &mut Self { + self.lock_authority = Some(lock_authority); + self + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to PDA derived from 'poolState']` + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + #[inline(always)] + pub fn pool_state(&mut self, pool_state: solana_address::Address) -> &mut Self { + self.pool_state = Some(pool_state); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the base token + /// Must be the standard Token program + #[inline(always)] + pub fn base_token_program(&mut self, base_token_program: solana_address::Address) -> &mut Self { + self.base_token_program = Some(base_token_program); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for the quote token + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL']` + /// Program to create an ATA for receiving fee NFT + #[inline(always)] + pub fn associated_token_program( + &mut self, + associated_token_program: solana_address::Address, + ) -> &mut Self { + self.associated_token_program = Some(associated_token_program); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// Required for account creation + #[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']` + /// Required for rent exempt calculations + #[inline(always)] + pub fn rent_program(&mut self, rent_program: solana_address::Address) -> &mut Self { + self.rent_program = Some(rent_program); + self + } + /// `[optional account, default to 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s']` + /// Program to create NFT metadata accunt + #[inline(always)] + pub fn metadata_program(&mut self, metadata_program: solana_address::Address) -> &mut Self { + self.metadata_program = Some(metadata_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 payer = self.payer; + let base_mint = self.base_mint; + let quote_mint = self.quote_mint; + let platform_config = self.platform_config; + let cpswap_program = self.cpswap_program.unwrap_or(solana_address::address!( + "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C" + )); + let cpswap_pool = self.cpswap_pool; + let cpswap_authority = self + .cpswap_authority + .unwrap_or(crate::pdas::CPSWAP_AUTHORITY_ADDRESS); + let cpswap_lp_mint = self + .cpswap_lp_mint + .unwrap_or_else(|| crate::pdas::find_cpswap_lp_mint_pda(&self.cpswap_pool).0); + let cpswap_base_vault = self.cpswap_base_vault.unwrap_or_else(|| { + crate::pdas::find_cpswap_base_vault_pda(&self.cpswap_pool, &self.base_mint).0 + }); + let cpswap_quote_vault = self.cpswap_quote_vault.unwrap_or_else(|| { + crate::pdas::find_cpswap_quote_vault_pda(&self.cpswap_pool, &self.quote_mint).0 + }); + let cpswap_config = self.cpswap_config; + let cpswap_create_pool_fee = self.cpswap_create_pool_fee; + let cpswap_observation = self + .cpswap_observation + .unwrap_or_else(|| crate::pdas::find_cpswap_observation_pda(&self.cpswap_pool).0); + let lock_program = self.lock_program.unwrap_or(solana_address::address!( + "LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE" + )); + let lock_authority = self + .lock_authority + .unwrap_or(crate::pdas::LOCK_AUTHORITY_ADDRESS); + let lock_lp_vault = self.lock_lp_vault; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let pool_state = self.pool_state.unwrap_or_else(|| { + crate::pdas::find_pool_state_pda(&self.base_mint, &self.quote_mint).0 + }); + let global_config = self.global_config; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let pool_lp_token = self.pool_lp_token; + let base_token_program = self.base_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let associated_token_program = + self.associated_token_program + .unwrap_or(solana_address::address!( + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + )); + let system_program = self + .system_program + .unwrap_or(solana_address::address!("11111111111111111111111111111111")); + let rent_program = self.rent_program.unwrap_or(solana_address::address!( + "SysvarRent111111111111111111111111111111111" + )); + let metadata_program = self.metadata_program.unwrap_or(solana_address::address!( + "metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s" + )); + let accounts = MigrateToCpswap { + payer, + base_mint, + quote_mint, + platform_config, + cpswap_program, + cpswap_pool, + cpswap_authority, + cpswap_lp_mint, + cpswap_base_vault, + cpswap_quote_vault, + cpswap_config, + cpswap_create_pool_fee, + cpswap_observation, + lock_program, + lock_authority, + lock_lp_vault, + authority, + pool_state, + global_config, + base_vault, + quote_vault, + pool_lp_token, + base_token_program, + quote_token_program, + associated_token_program, + system_program, + rent_program, + metadata_program, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `migrate_to_cpswap` CPI accounts. +pub struct MigrateToCpswapCpiAccounts<'a, 'b> { + /// Only migrate_to_cpswap_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_cpswap_wallet saved in global_config + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_program: &'b solana_account_info::AccountInfo<'a>, + /// PDA account: + /// seeds = [ + /// b"pool", + /// cpswap_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// seeds::program = cpswap_program, + /// + /// Or random account: must be signed by cli + pub cpswap_pool: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_authority: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_lp_mint: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_config: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_observation: &'b solana_account_info::AccountInfo<'a>, + + pub lock_program: &'b solana_account_info::AccountInfo<'a>, + + pub lock_authority: &'b solana_account_info::AccountInfo<'a>, + + pub lock_lp_vault: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the quote token + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create NFT metadata accunt + pub metadata_program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `migrate_to_cpswap` CPI instruction. +pub struct MigrateToCpswapCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// Only migrate_to_cpswap_wallet can migrate to cpswap pool + /// This signer must match the migrate_to_cpswap_wallet saved in global_config + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the base token (token being sold) + pub base_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint for the quote token (token used to buy) + pub quote_mint: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_program: &'b solana_account_info::AccountInfo<'a>, + /// PDA account: + /// seeds = [ + /// b"pool", + /// cpswap_config.key().as_ref(), + /// token_0_mint.key().as_ref(), + /// token_1_mint.key().as_ref(), + /// ], + /// seeds::program = cpswap_program, + /// + /// Or random account: must be signed by cli + pub cpswap_pool: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_authority: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_lp_mint: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_base_vault: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_config: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + + pub cpswap_observation: &'b solana_account_info::AccountInfo<'a>, + + pub lock_program: &'b solana_account_info::AccountInfo<'a>, + + pub lock_authority: &'b solana_account_info::AccountInfo<'a>, + + pub lock_lp_vault: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Account that stores the pool's state and parameters + /// PDA generated using POOL_SEED and both token mints + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// Global config account stores owner + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be fully drained during migration + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will be fully drained during migration + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + + pub pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the base token + /// Must be the standard Token program + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for the quote token + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create an ATA for receiving fee NFT + pub associated_token_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for account creation + pub system_program: &'b solana_account_info::AccountInfo<'a>, + /// Required for rent exempt calculations + pub rent_program: &'b solana_account_info::AccountInfo<'a>, + /// Program to create NFT metadata accunt + pub metadata_program: &'b solana_account_info::AccountInfo<'a>, +} + +impl<'a, 'b> MigrateToCpswapCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: MigrateToCpswapCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + base_mint: accounts.base_mint, + quote_mint: accounts.quote_mint, + platform_config: accounts.platform_config, + cpswap_program: accounts.cpswap_program, + cpswap_pool: accounts.cpswap_pool, + cpswap_authority: accounts.cpswap_authority, + cpswap_lp_mint: accounts.cpswap_lp_mint, + cpswap_base_vault: accounts.cpswap_base_vault, + cpswap_quote_vault: accounts.cpswap_quote_vault, + cpswap_config: accounts.cpswap_config, + cpswap_create_pool_fee: accounts.cpswap_create_pool_fee, + cpswap_observation: accounts.cpswap_observation, + lock_program: accounts.lock_program, + lock_authority: accounts.lock_authority, + lock_lp_vault: accounts.lock_lp_vault, + authority: accounts.authority, + pool_state: accounts.pool_state, + global_config: accounts.global_config, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + pool_lp_token: accounts.pool_lp_token, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + associated_token_program: accounts.associated_token_program, + system_program: accounts.system_program, + rent_program: accounts.rent_program, + metadata_program: accounts.metadata_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(28 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new(*self.payer.key, true)); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.cpswap_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_pool.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.cpswap_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_lp_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.cpswap_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_create_pool_fee.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.cpswap_observation.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.lock_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.lock_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.lock_lp_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_lp_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.associated_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.rent_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.metadata_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 = MigrateToCpswapInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(29 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.base_mint.clone()); + account_infos.push(self.quote_mint.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.cpswap_program.clone()); + account_infos.push(self.cpswap_pool.clone()); + account_infos.push(self.cpswap_authority.clone()); + account_infos.push(self.cpswap_lp_mint.clone()); + account_infos.push(self.cpswap_base_vault.clone()); + account_infos.push(self.cpswap_quote_vault.clone()); + account_infos.push(self.cpswap_config.clone()); + account_infos.push(self.cpswap_create_pool_fee.clone()); + account_infos.push(self.cpswap_observation.clone()); + account_infos.push(self.lock_program.clone()); + account_infos.push(self.lock_authority.clone()); + account_infos.push(self.lock_lp_vault.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.pool_lp_token.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.associated_token_program.clone()); + account_infos.push(self.system_program.clone()); + account_infos.push(self.rent_program.clone()); + account_infos.push(self.metadata_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 `MigrateToCpswap` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` payer +/// 1. `[]` base_mint +/// 2. `[]` quote_mint +/// 3. `[]` platform_config +/// 4. `[]` cpswap_program +/// 5. `[writable]` cpswap_pool +/// 6. `[]` cpswap_authority +/// 7. `[writable]` cpswap_lp_mint +/// 8. `[writable]` cpswap_base_vault +/// 9. `[writable]` cpswap_quote_vault +/// 10. `[]` cpswap_config +/// 11. `[writable]` cpswap_create_pool_fee +/// 12. `[writable]` cpswap_observation +/// 13. `[]` lock_program +/// 14. `[]` lock_authority +/// 15. `[writable]` lock_lp_vault +/// 16. `[writable]` authority +/// 17. `[writable]` pool_state +/// 18. `[]` global_config +/// 19. `[writable]` base_vault +/// 20. `[writable]` quote_vault +/// 21. `[writable]` pool_lp_token +/// 22. `[]` base_token_program +/// 23. `[]` quote_token_program +/// 24. `[]` associated_token_program +/// 25. `[]` system_program +/// 26. `[]` rent_program +/// 27. `[]` metadata_program +#[derive(Clone, Debug)] +pub struct MigrateToCpswapCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> MigrateToCpswapCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + cpswap_program: &'b solana_account_info::AccountInfo<'a>, + cpswap_pool: &'b solana_account_info::AccountInfo<'a>, + cpswap_authority: &'b solana_account_info::AccountInfo<'a>, + cpswap_lp_mint: &'b solana_account_info::AccountInfo<'a>, + cpswap_base_vault: &'b solana_account_info::AccountInfo<'a>, + cpswap_quote_vault: &'b solana_account_info::AccountInfo<'a>, + cpswap_config: &'b solana_account_info::AccountInfo<'a>, + cpswap_create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + cpswap_observation: &'b solana_account_info::AccountInfo<'a>, + lock_program: &'b solana_account_info::AccountInfo<'a>, + lock_authority: &'b solana_account_info::AccountInfo<'a>, + lock_lp_vault: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + metadata_program: &'b solana_account_info::AccountInfo<'a>, + ) -> Self { + let instruction = Box::new(MigrateToCpswapCpiBuilderInstruction { + __program, + payer, + base_mint, + quote_mint, + platform_config, + cpswap_program, + cpswap_pool, + cpswap_authority, + cpswap_lp_mint, + cpswap_base_vault, + cpswap_quote_vault, + cpswap_config, + cpswap_create_pool_fee, + cpswap_observation, + lock_program, + lock_authority, + lock_lp_vault, + authority, + pool_state, + global_config, + base_vault, + quote_vault, + pool_lp_token, + base_token_program, + quote_token_program, + associated_token_program, + system_program, + rent_program, + metadata_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 = MigrateToCpswapCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + base_mint: self.instruction.base_mint, + quote_mint: self.instruction.quote_mint, + platform_config: self.instruction.platform_config, + cpswap_program: self.instruction.cpswap_program, + cpswap_pool: self.instruction.cpswap_pool, + cpswap_authority: self.instruction.cpswap_authority, + cpswap_lp_mint: self.instruction.cpswap_lp_mint, + cpswap_base_vault: self.instruction.cpswap_base_vault, + cpswap_quote_vault: self.instruction.cpswap_quote_vault, + cpswap_config: self.instruction.cpswap_config, + cpswap_create_pool_fee: self.instruction.cpswap_create_pool_fee, + cpswap_observation: self.instruction.cpswap_observation, + lock_program: self.instruction.lock_program, + lock_authority: self.instruction.lock_authority, + lock_lp_vault: self.instruction.lock_lp_vault, + authority: self.instruction.authority, + pool_state: self.instruction.pool_state, + global_config: self.instruction.global_config, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + pool_lp_token: self.instruction.pool_lp_token, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + associated_token_program: self.instruction.associated_token_program, + system_program: self.instruction.system_program, + rent_program: self.instruction.rent_program, + metadata_program: self.instruction.metadata_program, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct MigrateToCpswapCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + base_mint: &'b solana_account_info::AccountInfo<'a>, + quote_mint: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + cpswap_program: &'b solana_account_info::AccountInfo<'a>, + cpswap_pool: &'b solana_account_info::AccountInfo<'a>, + cpswap_authority: &'b solana_account_info::AccountInfo<'a>, + cpswap_lp_mint: &'b solana_account_info::AccountInfo<'a>, + cpswap_base_vault: &'b solana_account_info::AccountInfo<'a>, + cpswap_quote_vault: &'b solana_account_info::AccountInfo<'a>, + cpswap_config: &'b solana_account_info::AccountInfo<'a>, + cpswap_create_pool_fee: &'b solana_account_info::AccountInfo<'a>, + cpswap_observation: &'b solana_account_info::AccountInfo<'a>, + lock_program: &'b solana_account_info::AccountInfo<'a>, + lock_authority: &'b solana_account_info::AccountInfo<'a>, + lock_lp_vault: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + pool_lp_token: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + associated_token_program: &'b solana_account_info::AccountInfo<'a>, + system_program: &'b solana_account_info::AccountInfo<'a>, + rent_program: &'b solana_account_info::AccountInfo<'a>, + metadata_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/raydium-launchpad/src/generated/instructions/mod.rs b/e2e/raydium-launchpad/src/generated/instructions/mod.rs new file mode 100644 index 0000000..b460c40 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/mod.rs @@ -0,0 +1,40 @@ +//! 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#buy_exact_in; +pub(crate) mod r#buy_exact_out; +pub(crate) mod r#claim_platform_fee; +pub(crate) mod r#claim_vested_token; +pub(crate) mod r#collect_fee; +pub(crate) mod r#collect_migrate_fee; +pub(crate) mod r#create_config; +pub(crate) mod r#create_platform_config; +pub(crate) mod r#create_vesting_account; +pub(crate) mod r#initialize; +pub(crate) mod r#migrate_to_amm; +pub(crate) mod r#migrate_to_cpswap; +pub(crate) mod r#sell_exact_in; +pub(crate) mod r#sell_exact_out; +pub(crate) mod r#update_config; +pub(crate) mod r#update_platform_config; + +pub use self::r#buy_exact_in::*; +pub use self::r#buy_exact_out::*; +pub use self::r#claim_platform_fee::*; +pub use self::r#claim_vested_token::*; +pub use self::r#collect_fee::*; +pub use self::r#collect_migrate_fee::*; +pub use self::r#create_config::*; +pub use self::r#create_platform_config::*; +pub use self::r#create_vesting_account::*; +pub use self::r#initialize::*; +pub use self::r#migrate_to_amm::*; +pub use self::r#migrate_to_cpswap::*; +pub use self::r#sell_exact_in::*; +pub use self::r#sell_exact_out::*; +pub use self::r#update_config::*; +pub use self::r#update_platform_config::*; diff --git a/e2e/raydium-launchpad/src/generated/instructions/sell_exact_in.rs b/e2e/raydium-launchpad/src/generated/instructions/sell_exact_in.rs new file mode 100644 index 0000000..f42c5d5 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/sell_exact_in.rs @@ -0,0 +1,746 @@ +//! 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 SELL_EXACT_IN_DISCRIMINATOR: [u8; 8] = [149, 39, 222, 155, 211, 124, 152, 26]; + +/// Accounts. +#[derive(Debug)] +pub struct SellExactIn { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: solana_address::Address, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: solana_address::Address, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: solana_address::Address, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: solana_address::Address, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: solana_address::Address, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: solana_address::Address, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: solana_address::Address, + /// The mint of the quote token + pub quote_token_mint: solana_address::Address, + /// SPL Token program for base token transfers + pub base_token_program: solana_address::Address, + /// SPL Token program for quote token transfers + pub quote_token_program: solana_address::Address, + + pub event_authority: solana_address::Address, + + pub program: solana_address::Address, +} + +impl SellExactIn { + pub fn instruction(&self, args: SellExactInInstructionArgs) -> 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: SellExactInInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.user_base_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.user_quote_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.event_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SellExactInInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SellExactInInstructionData { + discriminator: [u8; 8], +} + +impl SellExactInInstructionData { + pub fn new() -> Self { + Self { + discriminator: [149, 39, 222, 155, 211, 124, 152, 26], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SellExactInInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SellExactInInstructionArgs { + pub amount_in: u64, + pub minimum_amount_out: u64, + pub share_fee_rate: u64, +} + +impl SellExactInInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SellExactIn`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 13. `[optional]` event_authority (default to PDA derived from 'eventAuthority') +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct SellExactInBuilder { + payer: solana_address::Address, + authority: Option, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + quote_token_program: Option, + event_authority: Option, + program: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + __remaining_accounts: Vec, +} + +impl SellExactInBuilder { + pub fn new( + payer: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + program: solana_address::Address, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + ) -> Self { + Self { + payer, + authority: None, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program: None, + event_authority: None, + program, + amount_in, + minimum_amount_out, + share_fee_rate, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for quote token transfers + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to PDA derived from 'eventAuthority']` + #[inline(always)] + pub fn event_authority(&mut self, event_authority: solana_address::Address) -> &mut Self { + self.event_authority = Some(event_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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let global_config = self.global_config; + let platform_config = self.platform_config; + let pool_state = self.pool_state; + let user_base_token = self.user_base_token; + let user_quote_token = self.user_quote_token; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let base_token_mint = self.base_token_mint; + let quote_token_mint = self.quote_token_mint; + let base_token_program = self.base_token_program; + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let event_authority = self + .event_authority + .unwrap_or(crate::pdas::EVENT_AUTHORITY_ADDRESS); + let program = self.program; + let accounts = SellExactIn { + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + }; + let args = SellExactInInstructionArgs { + amount_in: self.amount_in.clone(), + minimum_amount_out: self.minimum_amount_out.clone(), + share_fee_rate: self.share_fee_rate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `sell_exact_in` CPI accounts. +pub struct SellExactInCpiAccounts<'a, 'b> { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `sell_exact_in` CPI instruction. +pub struct SellExactInCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SellExactInInstructionArgs, +} + +impl<'a, 'b> SellExactInCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SellExactInCpiAccounts<'a, 'b>, + args: SellExactInInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + global_config: accounts.global_config, + platform_config: accounts.platform_config, + pool_state: accounts.pool_state, + user_base_token: accounts.user_base_token, + user_quote_token: accounts.user_quote_token, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + base_token_mint: accounts.base_token_mint, + quote_token_mint: accounts.quote_token_mint, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + event_authority: accounts.event_authority, + program: accounts.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(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_base_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_quote_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.event_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *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 mut data = SellExactInInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(16 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.user_base_token.clone()); + account_infos.push(self.user_quote_token.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.base_token_mint.clone()); + account_infos.push(self.quote_token_mint.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.event_authority.clone()); + 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 `SellExactIn` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[]` quote_token_program +/// 13. `[]` event_authority +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct SellExactInCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SellExactInCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + ) -> Self { + let instruction = Box::new(SellExactInCpiBuilderInstruction { + __program, + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + amount_in, + minimum_amount_out, + share_fee_rate, + __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 = SellExactInInstructionArgs { + amount_in: self.instruction.amount_in.clone(), + minimum_amount_out: self.instruction.minimum_amount_out.clone(), + share_fee_rate: self.instruction.share_fee_rate.clone(), + }; + let instruction = SellExactInCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + global_config: self.instruction.global_config, + platform_config: self.instruction.platform_config, + pool_state: self.instruction.pool_state, + user_base_token: self.instruction.user_base_token, + user_quote_token: self.instruction.user_quote_token, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + base_token_mint: self.instruction.base_token_mint, + quote_token_mint: self.instruction.quote_token_mint, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + event_authority: self.instruction.event_authority, + program: self.instruction.program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SellExactInCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_in: u64, + minimum_amount_out: u64, + share_fee_rate: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/sell_exact_out.rs b/e2e/raydium-launchpad/src/generated/instructions/sell_exact_out.rs new file mode 100644 index 0000000..0839245 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/sell_exact_out.rs @@ -0,0 +1,749 @@ +//! 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 SELL_EXACT_OUT_DISCRIMINATOR: [u8; 8] = [95, 200, 71, 34, 8, 9, 11, 166]; + +/// Accounts. +#[derive(Debug)] +pub struct SellExactOut { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: solana_address::Address, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: solana_address::Address, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: solana_address::Address, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: solana_address::Address, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: solana_address::Address, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: solana_address::Address, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: solana_address::Address, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: solana_address::Address, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: solana_address::Address, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: solana_address::Address, + /// The mint of the quote token + pub quote_token_mint: solana_address::Address, + /// SPL Token program for base token transfers + pub base_token_program: solana_address::Address, + /// SPL Token program for quote token transfers + pub quote_token_program: solana_address::Address, + + pub event_authority: solana_address::Address, + + pub program: solana_address::Address, +} + +impl SellExactOut { + pub fn instruction( + &self, + args: SellExactOutInstructionArgs, + ) -> 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: SellExactOutInstructionArgs, + remaining_accounts: &[solana_instruction::AccountMeta], + ) -> solana_instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.payer, true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.global_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.platform_config, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.pool_state, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.user_base_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.user_quote_token, + false, + )); + accounts.push(solana_instruction::AccountMeta::new(self.base_vault, false)); + accounts.push(solana_instruction::AccountMeta::new( + self.quote_vault, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_mint, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.base_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.quote_token_program, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.event_authority, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + self.program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SellExactOutInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SellExactOutInstructionData { + discriminator: [u8; 8], +} + +impl SellExactOutInstructionData { + pub fn new() -> Self { + Self { + discriminator: [95, 200, 71, 34, 8, 9, 11, 166], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for SellExactOutInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct SellExactOutInstructionArgs { + pub amount_out: u64, + pub maximum_amount_in: u64, + pub share_fee_rate: u64, +} + +impl SellExactOutInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `SellExactOut`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[optional]` authority (default to PDA derived from 'authority') +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[optional]` quote_token_program (default to `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) +/// 13. `[optional]` event_authority (default to PDA derived from 'eventAuthority') +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct SellExactOutBuilder { + payer: solana_address::Address, + authority: Option, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + quote_token_program: Option, + event_authority: Option, + program: solana_address::Address, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + __remaining_accounts: Vec, +} + +impl SellExactOutBuilder { + pub fn new( + payer: solana_address::Address, + global_config: solana_address::Address, + platform_config: solana_address::Address, + pool_state: solana_address::Address, + user_base_token: solana_address::Address, + user_quote_token: solana_address::Address, + base_vault: solana_address::Address, + quote_vault: solana_address::Address, + base_token_mint: solana_address::Address, + quote_token_mint: solana_address::Address, + base_token_program: solana_address::Address, + program: solana_address::Address, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + ) -> Self { + Self { + payer, + authority: None, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program: None, + event_authority: None, + program, + amount_out, + maximum_amount_in, + share_fee_rate, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'authority']` + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + #[inline(always)] + pub fn authority(&mut self, authority: solana_address::Address) -> &mut Self { + self.authority = Some(authority); + self + } + /// `[optional account, default to 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA']` + /// SPL Token program for quote token transfers + #[inline(always)] + pub fn quote_token_program( + &mut self, + quote_token_program: solana_address::Address, + ) -> &mut Self { + self.quote_token_program = Some(quote_token_program); + self + } + /// `[optional account, default to PDA derived from 'eventAuthority']` + #[inline(always)] + pub fn event_authority(&mut self, event_authority: solana_address::Address) -> &mut Self { + self.event_authority = Some(event_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 payer = self.payer; + let authority = self.authority.unwrap_or(crate::pdas::AUTHORITY_ADDRESS); + let global_config = self.global_config; + let platform_config = self.platform_config; + let pool_state = self.pool_state; + let user_base_token = self.user_base_token; + let user_quote_token = self.user_quote_token; + let base_vault = self.base_vault; + let quote_vault = self.quote_vault; + let base_token_mint = self.base_token_mint; + let quote_token_mint = self.quote_token_mint; + let base_token_program = self.base_token_program; + let quote_token_program = self.quote_token_program.unwrap_or(solana_address::address!( + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + )); + let event_authority = self + .event_authority + .unwrap_or(crate::pdas::EVENT_AUTHORITY_ADDRESS); + let program = self.program; + let accounts = SellExactOut { + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + }; + let args = SellExactOutInstructionArgs { + amount_out: self.amount_out.clone(), + maximum_amount_in: self.maximum_amount_in.clone(), + share_fee_rate: self.share_fee_rate.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `sell_exact_out` CPI accounts. +pub struct SellExactOutCpiAccounts<'a, 'b> { + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, +} + +/// `sell_exact_out` CPI instruction. +pub struct SellExactOutCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The user performing the swap operation + /// Must sign the transaction and pay for fees + pub payer: &'b solana_account_info::AccountInfo<'a>, + /// PDA that acts as the authority for pool vault operations + /// Generated using AUTH_SEED + pub authority: &'b solana_account_info::AccountInfo<'a>, + /// Global configuration account containing protocol-wide settings + /// Used to read protocol fee rates and curve type + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// Platform configuration account containing platform-wide settings + /// Used to read platform fee rate + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The pool state account where the swap will be performed + /// Contains current pool parameters and balances + pub pool_state: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for base tokens (tokens being bought) + /// Will receive the output tokens after the swap + pub user_base_token: &'b solana_account_info::AccountInfo<'a>, + /// The user's token account for quote tokens (tokens being sold) + /// Will be debited for the input amount + pub user_quote_token: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for base tokens + /// Will be debited to send tokens to the user + pub base_vault: &'b solana_account_info::AccountInfo<'a>, + /// The pool's vault for quote tokens + /// Will receive the input tokens from the user + pub quote_vault: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the base token + /// Used for transfer fee calculations if applicable + pub base_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// The mint of the quote token + pub quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for base token transfers + pub base_token_program: &'b solana_account_info::AccountInfo<'a>, + /// SPL Token program for quote token transfers + pub quote_token_program: &'b solana_account_info::AccountInfo<'a>, + + pub event_authority: &'b solana_account_info::AccountInfo<'a>, + + pub program: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SellExactOutInstructionArgs, +} + +impl<'a, 'b> SellExactOutCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: SellExactOutCpiAccounts<'a, 'b>, + args: SellExactOutInstructionArgs, + ) -> Self { + Self { + __program: program, + payer: accounts.payer, + authority: accounts.authority, + global_config: accounts.global_config, + platform_config: accounts.platform_config, + pool_state: accounts.pool_state, + user_base_token: accounts.user_base_token, + user_quote_token: accounts.user_quote_token, + base_vault: accounts.base_vault, + quote_vault: accounts.quote_vault, + base_token_mint: accounts.base_token_mint, + quote_token_mint: accounts.quote_token_mint, + base_token_program: accounts.base_token_program, + quote_token_program: accounts.quote_token_program, + event_authority: accounts.event_authority, + program: accounts.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(15 + remaining_accounts.len()); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.payer.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.global_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.platform_config.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.pool_state.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_base_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.user_quote_token.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.base_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.quote_vault.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_mint.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.base_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.quote_token_program.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *self.event_authority.key, + false, + )); + accounts.push(solana_instruction::AccountMeta::new_readonly( + *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 mut data = SellExactOutInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(16 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.global_config.clone()); + account_infos.push(self.platform_config.clone()); + account_infos.push(self.pool_state.clone()); + account_infos.push(self.user_base_token.clone()); + account_infos.push(self.user_quote_token.clone()); + account_infos.push(self.base_vault.clone()); + account_infos.push(self.quote_vault.clone()); + account_infos.push(self.base_token_mint.clone()); + account_infos.push(self.quote_token_mint.clone()); + account_infos.push(self.base_token_program.clone()); + account_infos.push(self.quote_token_program.clone()); + account_infos.push(self.event_authority.clone()); + 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 `SellExactOut` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` payer +/// 1. `[]` authority +/// 2. `[]` global_config +/// 3. `[]` platform_config +/// 4. `[writable]` pool_state +/// 5. `[writable]` user_base_token +/// 6. `[writable]` user_quote_token +/// 7. `[writable]` base_vault +/// 8. `[writable]` quote_vault +/// 9. `[]` base_token_mint +/// 10. `[]` quote_token_mint +/// 11. `[]` base_token_program +/// 12. `[]` quote_token_program +/// 13. `[]` event_authority +/// 14. `[]` program +#[derive(Clone, Debug)] +pub struct SellExactOutCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SellExactOutCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + ) -> Self { + let instruction = Box::new(SellExactOutCpiBuilderInstruction { + __program, + payer, + authority, + global_config, + platform_config, + pool_state, + user_base_token, + user_quote_token, + base_vault, + quote_vault, + base_token_mint, + quote_token_mint, + base_token_program, + quote_token_program, + event_authority, + program, + amount_out, + maximum_amount_in, + share_fee_rate, + __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 = SellExactOutInstructionArgs { + amount_out: self.instruction.amount_out.clone(), + maximum_amount_in: self.instruction.maximum_amount_in.clone(), + share_fee_rate: self.instruction.share_fee_rate.clone(), + }; + let instruction = SellExactOutCpi { + __program: self.instruction.__program, + payer: self.instruction.payer, + authority: self.instruction.authority, + global_config: self.instruction.global_config, + platform_config: self.instruction.platform_config, + pool_state: self.instruction.pool_state, + user_base_token: self.instruction.user_base_token, + user_quote_token: self.instruction.user_quote_token, + base_vault: self.instruction.base_vault, + quote_vault: self.instruction.quote_vault, + base_token_mint: self.instruction.base_token_mint, + quote_token_mint: self.instruction.quote_token_mint, + base_token_program: self.instruction.base_token_program, + quote_token_program: self.instruction.quote_token_program, + event_authority: self.instruction.event_authority, + program: self.instruction.program, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SellExactOutCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + payer: &'b solana_account_info::AccountInfo<'a>, + authority: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + pool_state: &'b solana_account_info::AccountInfo<'a>, + user_base_token: &'b solana_account_info::AccountInfo<'a>, + user_quote_token: &'b solana_account_info::AccountInfo<'a>, + base_vault: &'b solana_account_info::AccountInfo<'a>, + quote_vault: &'b solana_account_info::AccountInfo<'a>, + base_token_mint: &'b solana_account_info::AccountInfo<'a>, + quote_token_mint: &'b solana_account_info::AccountInfo<'a>, + base_token_program: &'b solana_account_info::AccountInfo<'a>, + quote_token_program: &'b solana_account_info::AccountInfo<'a>, + event_authority: &'b solana_account_info::AccountInfo<'a>, + program: &'b solana_account_info::AccountInfo<'a>, + amount_out: u64, + maximum_amount_in: u64, + share_fee_rate: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/update_config.rs b/e2e/raydium-launchpad/src/generated/instructions/update_config.rs new file mode 100644 index 0000000..bb54cd6 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/update_config.rs @@ -0,0 +1,344 @@ +//! 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_CONFIG_DISCRIMINATOR: [u8; 8] = [29, 158, 252, 191, 10, 83, 219, 99]; + +/// Accounts. +#[derive(Debug)] +pub struct UpdateConfig { + /// The global config owner or admin + pub owner: solana_address::Address, + /// Global config account to be changed + pub global_config: solana_address::Address, +} + +impl UpdateConfig { + pub fn instruction( + &self, + args: UpdateConfigInstructionArgs, + ) -> 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: UpdateConfigInstructionArgs, + 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( + self.global_config, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = UpdateConfigInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdateConfigInstructionData { + discriminator: [u8; 8], +} + +impl UpdateConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [29, 158, 252, 191, 10, 83, 219, 99], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for UpdateConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdateConfigInstructionArgs { + pub param: u8, + pub value: u64, +} + +impl UpdateConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `UpdateConfig`. +/// +/// ### Accounts: +/// +/// 0. `[signer, optional]` owner (default to `GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ`) +/// 1. `[writable]` global_config +#[derive(Clone, Debug)] +pub struct UpdateConfigBuilder { + owner: Option, + global_config: solana_address::Address, + param: u8, + value: u64, + __remaining_accounts: Vec, +} + +impl UpdateConfigBuilder { + pub fn new(global_config: solana_address::Address, param: u8, value: u64) -> Self { + Self { + owner: None, + global_config, + param, + value, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to 'GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ']` + /// The global config owner or admin + #[inline(always)] + pub fn owner(&mut self, owner: solana_address::Address) -> &mut Self { + self.owner = Some(owner); + 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.unwrap_or(solana_address::address!( + "GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ" + )); + let global_config = self.global_config; + let accounts = UpdateConfig { + owner, + global_config, + }; + let args = UpdateConfigInstructionArgs { + param: self.param.clone(), + value: self.value.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_config` CPI accounts. +pub struct UpdateConfigCpiAccounts<'a, 'b> { + /// The global config owner or admin + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Global config account to be changed + pub global_config: &'b solana_account_info::AccountInfo<'a>, +} + +/// `update_config` CPI instruction. +pub struct UpdateConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The global config owner or admin + pub owner: &'b solana_account_info::AccountInfo<'a>, + /// Global config account to be changed + pub global_config: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdateConfigInstructionArgs, +} + +impl<'a, 'b> UpdateConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: UpdateConfigCpiAccounts<'a, 'b>, + args: UpdateConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + owner: accounts.owner, + global_config: accounts.global_config, + __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.owner.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *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 mut data = UpdateConfigInstructionData::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::RAYDIUM_LAUNCHPAD_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.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 `UpdateConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` owner +/// 1. `[writable]` global_config +#[derive(Clone, Debug)] +pub struct UpdateConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + param: u8, + value: u64, + ) -> Self { + let instruction = Box::new(UpdateConfigCpiBuilderInstruction { + __program, + owner, + global_config, + param, + value, + __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 = UpdateConfigInstructionArgs { + param: self.instruction.param.clone(), + value: self.instruction.value.clone(), + }; + let instruction = UpdateConfigCpi { + __program: self.instruction.__program, + owner: self.instruction.owner, + global_config: self.instruction.global_config, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct UpdateConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + owner: &'b solana_account_info::AccountInfo<'a>, + global_config: &'b solana_account_info::AccountInfo<'a>, + param: u8, + value: u64, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/instructions/update_platform_config.rs b/e2e/raydium-launchpad/src/generated/instructions/update_platform_config.rs new file mode 100644 index 0000000..8de8d82 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/instructions/update_platform_config.rs @@ -0,0 +1,342 @@ +//! 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::PlatformConfigParam; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +pub const UPDATE_PLATFORM_CONFIG_DISCRIMINATOR: [u8; 8] = [195, 60, 76, 129, 146, 45, 67, 143]; + +/// Accounts. +#[derive(Debug)] +pub struct UpdatePlatformConfig { + /// The account paying for the initialization costs + pub platform_admin: solana_address::Address, + /// Platform config account to be changed + pub platform_config: solana_address::Address, +} + +impl UpdatePlatformConfig { + pub fn instruction( + &self, + args: UpdatePlatformConfigInstructionArgs, + ) -> 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: UpdatePlatformConfigInstructionArgs, + 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.platform_admin, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + self.platform_config, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = UpdatePlatformConfigInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_instruction::Instruction { + program_id: crate::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdatePlatformConfigInstructionData { + discriminator: [u8; 8], +} + +impl UpdatePlatformConfigInstructionData { + pub fn new() -> Self { + Self { + discriminator: [195, 60, 76, 129, 146, 45, 67, 143], + } + } + + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +impl Default for UpdatePlatformConfigInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct UpdatePlatformConfigInstructionArgs { + pub param: PlatformConfigParam, +} + +impl UpdatePlatformConfigInstructionArgs { + pub(crate) fn try_to_vec(&self) -> Result, std::io::Error> { + borsh::to_vec(self) + } +} + +/// Instruction builder for `UpdatePlatformConfig`. +/// +/// ### Accounts: +/// +/// 0. `[signer]` platform_admin +/// 1. `[writable, optional]` platform_config (default to PDA derived from 'platformConfig') +#[derive(Clone, Debug)] +pub struct UpdatePlatformConfigBuilder { + platform_admin: solana_address::Address, + platform_config: Option, + param: PlatformConfigParam, + __remaining_accounts: Vec, +} + +impl UpdatePlatformConfigBuilder { + pub fn new(platform_admin: solana_address::Address, param: PlatformConfigParam) -> Self { + Self { + platform_admin, + platform_config: None, + param, + __remaining_accounts: Vec::new(), + } + } + /// `[optional account, default to PDA derived from 'platformConfig']` + /// Platform config account to be changed + #[inline(always)] + pub fn platform_config(&mut self, platform_config: solana_address::Address) -> &mut Self { + self.platform_config = Some(platform_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 platform_admin = self.platform_admin; + let platform_config = self + .platform_config + .unwrap_or_else(|| crate::pdas::find_platform_config_pda(&self.platform_admin).0); + let accounts = UpdatePlatformConfig { + platform_admin, + platform_config, + }; + let args = UpdatePlatformConfigInstructionArgs { + param: self.param.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_platform_config` CPI accounts. +pub struct UpdatePlatformConfigCpiAccounts<'a, 'b> { + /// The account paying for the initialization costs + pub platform_admin: &'b solana_account_info::AccountInfo<'a>, + /// Platform config account to be changed + pub platform_config: &'b solana_account_info::AccountInfo<'a>, +} + +/// `update_platform_config` CPI instruction. +pub struct UpdatePlatformConfigCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_account_info::AccountInfo<'a>, + /// The account paying for the initialization costs + pub platform_admin: &'b solana_account_info::AccountInfo<'a>, + /// Platform config account to be changed + pub platform_config: &'b solana_account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdatePlatformConfigInstructionArgs, +} + +impl<'a, 'b> UpdatePlatformConfigCpi<'a, 'b> { + pub fn new( + program: &'b solana_account_info::AccountInfo<'a>, + accounts: UpdatePlatformConfigCpiAccounts<'a, 'b>, + args: UpdatePlatformConfigInstructionArgs, + ) -> Self { + Self { + __program: program, + platform_admin: accounts.platform_admin, + platform_config: accounts.platform_config, + __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.platform_admin.key, + true, + )); + accounts.push(solana_instruction::AccountMeta::new( + *self.platform_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 mut data = UpdatePlatformConfigInstructionData::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::RAYDIUM_LAUNCHPAD_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(3 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.platform_admin.clone()); + account_infos.push(self.platform_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 `UpdatePlatformConfig` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[signer]` platform_admin +/// 1. `[writable]` platform_config +#[derive(Clone, Debug)] +pub struct UpdatePlatformConfigCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdatePlatformConfigCpiBuilder<'a, 'b> { + pub fn new( + __program: &'b solana_account_info::AccountInfo<'a>, + platform_admin: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + param: PlatformConfigParam, + ) -> Self { + let instruction = Box::new(UpdatePlatformConfigCpiBuilderInstruction { + __program, + platform_admin, + platform_config, + param, + __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 = UpdatePlatformConfigInstructionArgs { + param: self.instruction.param.clone(), + }; + let instruction = UpdatePlatformConfigCpi { + __program: self.instruction.__program, + platform_admin: self.instruction.platform_admin, + platform_config: self.instruction.platform_config, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct UpdatePlatformConfigCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_account_info::AccountInfo<'a>, + platform_admin: &'b solana_account_info::AccountInfo<'a>, + platform_config: &'b solana_account_info::AccountInfo<'a>, + param: PlatformConfigParam, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<(&'b solana_account_info::AccountInfo<'a>, bool, bool)>, +} diff --git a/e2e/raydium-launchpad/src/generated/mod.rs b/e2e/raydium-launchpad/src/generated/mod.rs new file mode 100644 index 0000000..726a6f0 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/mod.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. +//! +//! +//! + +pub mod accounts; +pub mod errors; +pub mod events; +pub mod instructions; +pub mod pdas; +pub mod programs; +pub mod shared; +pub mod types; + +pub(crate) use programs::*; diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_authority.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_authority.rs new file mode 100644 index 0000000..b20cb3c --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_authority.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. +//! +//! +//! + +pub const AMM_AUTHORITY_SEED: &'static [u8] = + &[97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121]; + +pub const AMM_AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"); + +pub const AMM_AUTHORITY_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[AMM_AUTHORITY_SEED, &[bump]], + &AMM_AUTHORITY_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[AMM_AUTHORITY_SEED], + &AMM_AUTHORITY_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_base_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_base_vault.rs new file mode 100644 index 0000000..310f395 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_base_vault.rs @@ -0,0 +1,44 @@ +//! 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; + +pub const AMM_BASE_VAULT_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_BASE_VAULT_SEED_1: &'static [u8] = &[ + 99, 111, 105, 110, 95, 118, 97, 117, 108, 116, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, + 100, 95, 115, 101, 101, 100, +]; + +pub const AMM_BASE_VAULT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_base_vault_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + AMM_BASE_VAULT_SEED_0, + market.as_ref(), + AMM_BASE_VAULT_SEED_1, + &[bump], + ], + &AMM_BASE_VAULT_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_base_vault_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + AMM_BASE_VAULT_SEED_0, + market.as_ref(), + AMM_BASE_VAULT_SEED_1, + ], + &AMM_BASE_VAULT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_config.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_config.rs new file mode 100644 index 0000000..afbf832 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_config.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. +//! +//! +//! + +pub const AMM_CONFIG_SEED: &'static [u8] = &[ + 97, 109, 109, 95, 99, 111, 110, 102, 105, 103, 95, 97, 99, 99, 111, 117, 110, 116, 95, 115, + 101, 101, 100, +]; + +pub const AMM_CONFIG_ADDRESS: solana_address::Address = + solana_address::address!("9DCxsMizn3H1hprZ7xWe6LDzeUeZBksYFpBWBtSf1PQX"); + +pub const AMM_CONFIG_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_config_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[AMM_CONFIG_SEED, &[bump]], + &AMM_CONFIG_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_config_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address(&[AMM_CONFIG_SEED], &AMM_CONFIG_PROGRAM_ADDRESS) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_lp_mint.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_lp_mint.rs new file mode 100644 index 0000000..d1a039a --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_lp_mint.rs @@ -0,0 +1,40 @@ +//! 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; + +pub const AMM_LP_MINT_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_LP_MINT_SEED_1: &'static [u8] = &[ + 108, 112, 95, 109, 105, 110, 116, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 95, 115, + 101, 101, 100, +]; + +pub const AMM_LP_MINT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_lp_mint_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + AMM_LP_MINT_SEED_0, + market.as_ref(), + AMM_LP_MINT_SEED_1, + &[bump], + ], + &AMM_LP_MINT_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_lp_mint_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[AMM_LP_MINT_SEED_0, market.as_ref(), AMM_LP_MINT_SEED_1], + &AMM_LP_MINT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_open_orders.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_open_orders.rs new file mode 100644 index 0000000..22e4b86 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_open_orders.rs @@ -0,0 +1,44 @@ +//! 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; + +pub const AMM_OPEN_ORDERS_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_OPEN_ORDERS_SEED_1: &'static [u8] = &[ + 111, 112, 101, 110, 95, 111, 114, 100, 101, 114, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, + 100, 95, 115, 101, 101, 100, +]; + +pub const AMM_OPEN_ORDERS_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_open_orders_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + AMM_OPEN_ORDERS_SEED_0, + market.as_ref(), + AMM_OPEN_ORDERS_SEED_1, + &[bump], + ], + &AMM_OPEN_ORDERS_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_open_orders_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + AMM_OPEN_ORDERS_SEED_0, + market.as_ref(), + AMM_OPEN_ORDERS_SEED_1, + ], + &AMM_OPEN_ORDERS_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_pool.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_pool.rs new file mode 100644 index 0000000..7e3dad7 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_pool.rs @@ -0,0 +1,34 @@ +//! 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; + +pub const AMM_POOL_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_POOL_SEED_1: &'static [u8] = &[ + 97, 109, 109, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 95, 115, 101, 101, 100, +]; + +pub const AMM_POOL_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_pool_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[AMM_POOL_SEED_0, market.as_ref(), AMM_POOL_SEED_1, &[bump]], + &AMM_POOL_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_pool_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[AMM_POOL_SEED_0, market.as_ref(), AMM_POOL_SEED_1], + &AMM_POOL_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_quote_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_quote_vault.rs new file mode 100644 index 0000000..d7e3e92 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_quote_vault.rs @@ -0,0 +1,44 @@ +//! 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; + +pub const AMM_QUOTE_VAULT_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_QUOTE_VAULT_SEED_1: &'static [u8] = &[ + 112, 99, 95, 118, 97, 117, 108, 116, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 95, + 115, 101, 101, 100, +]; + +pub const AMM_QUOTE_VAULT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_quote_vault_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + AMM_QUOTE_VAULT_SEED_0, + market.as_ref(), + AMM_QUOTE_VAULT_SEED_1, + &[bump], + ], + &AMM_QUOTE_VAULT_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_quote_vault_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + AMM_QUOTE_VAULT_SEED_0, + market.as_ref(), + AMM_QUOTE_VAULT_SEED_1, + ], + &AMM_QUOTE_VAULT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/amm_target_orders.rs b/e2e/raydium-launchpad/src/generated/pdas/amm_target_orders.rs new file mode 100644 index 0000000..951b70b --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/amm_target_orders.rs @@ -0,0 +1,44 @@ +//! 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; + +pub const AMM_TARGET_ORDERS_SEED_0: &'static [u8] = &[ + 75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, 161, 185, 151, 92, 241, + 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205, +]; +pub const AMM_TARGET_ORDERS_SEED_1: &'static [u8] = &[ + 116, 97, 114, 103, 101, 116, 95, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 95, 115, 101, + 101, 100, +]; + +pub const AMM_TARGET_ORDERS_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"); +pub fn create_amm_target_orders_pda( + market: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + AMM_TARGET_ORDERS_SEED_0, + market.as_ref(), + AMM_TARGET_ORDERS_SEED_1, + &[bump], + ], + &AMM_TARGET_ORDERS_PROGRAM_ADDRESS, + ) +} +pub fn find_amm_target_orders_pda(market: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + AMM_TARGET_ORDERS_SEED_0, + market.as_ref(), + AMM_TARGET_ORDERS_SEED_1, + ], + &AMM_TARGET_ORDERS_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/authority.rs b/e2e/raydium-launchpad/src/generated/pdas/authority.rs new file mode 100644 index 0000000..85c00a6 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/authority.rs @@ -0,0 +1,26 @@ +//! 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::RAYDIUM_LAUNCHPAD_ID; + +pub const AUTHORITY_SEED: &'static [u8] = &[ + 118, 97, 117, 108, 116, 95, 97, 117, 116, 104, 95, 115, 101, 101, 100, +]; + +pub const AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("WLHv2UAZm6z4KyaaELi5pjdbJh6RESMva1Rnn8pJVVh"); +pub fn create_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[AUTHORITY_SEED, &[bump]], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address(&[AUTHORITY_SEED], &RAYDIUM_LAUNCHPAD_ID) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/base_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/base_vault.rs new file mode 100644 index 0000000..df7d83e --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/base_vault.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::RAYDIUM_LAUNCHPAD_ID; + +pub const BASE_VAULT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; +pub fn create_base_vault_pda( + pool_state: Address, + base_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + BASE_VAULT_SEED, + pool_state.as_ref(), + base_mint.as_ref(), + &[bump], + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_base_vault_pda( + pool_state: &Address, + base_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[BASE_VAULT_SEED, pool_state.as_ref(), base_mint.as_ref()], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/cpswap_authority.rs b/e2e/raydium-launchpad/src/generated/pdas/cpswap_authority.rs new file mode 100644 index 0000000..f069ea6 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/cpswap_authority.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. +//! +//! +//! + +pub const CPSWAP_AUTHORITY_SEED: &'static [u8] = &[ + 118, 97, 117, 108, 116, 95, 97, 110, 100, 95, 108, 112, 95, 109, 105, 110, 116, 95, 97, 117, + 116, 104, 95, 115, 101, 101, 100, +]; + +pub const CPSWAP_AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("GpMZbSM2GgvTKHJirzeGfMFoaZ8UR2X7F4v8vHTvxFbL"); + +pub const CPSWAP_AUTHORITY_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub fn create_cpswap_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[CPSWAP_AUTHORITY_SEED, &[bump]], + &CPSWAP_AUTHORITY_PROGRAM_ADDRESS, + ) +} +pub fn find_cpswap_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[CPSWAP_AUTHORITY_SEED], + &CPSWAP_AUTHORITY_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/cpswap_base_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/cpswap_base_vault.rs new file mode 100644 index 0000000..b2fef25 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/cpswap_base_vault.rs @@ -0,0 +1,41 @@ +//! 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; + +pub const CPSWAP_BASE_VAULT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; + +pub const CPSWAP_BASE_VAULT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub fn create_cpswap_base_vault_pda( + cpswap_pool: Address, + base_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + CPSWAP_BASE_VAULT_SEED, + cpswap_pool.as_ref(), + base_mint.as_ref(), + &[bump], + ], + &CPSWAP_BASE_VAULT_PROGRAM_ADDRESS, + ) +} +pub fn find_cpswap_base_vault_pda( + cpswap_pool: &Address, + base_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + CPSWAP_BASE_VAULT_SEED, + cpswap_pool.as_ref(), + base_mint.as_ref(), + ], + &CPSWAP_BASE_VAULT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/cpswap_lp_mint.rs b/e2e/raydium-launchpad/src/generated/pdas/cpswap_lp_mint.rs new file mode 100644 index 0000000..d95a256 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/cpswap_lp_mint.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; + +pub const CPSWAP_LP_MINT_SEED: &'static [u8] = + &[112, 111, 111, 108, 95, 108, 112, 95, 109, 105, 110, 116]; + +pub const CPSWAP_LP_MINT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub fn create_cpswap_lp_mint_pda( + cpswap_pool: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[CPSWAP_LP_MINT_SEED, cpswap_pool.as_ref(), &[bump]], + &CPSWAP_LP_MINT_PROGRAM_ADDRESS, + ) +} +pub fn find_cpswap_lp_mint_pda(cpswap_pool: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[CPSWAP_LP_MINT_SEED, cpswap_pool.as_ref()], + &CPSWAP_LP_MINT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/cpswap_observation.rs b/e2e/raydium-launchpad/src/generated/pdas/cpswap_observation.rs new file mode 100644 index 0000000..5393446 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/cpswap_observation.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; + +pub const CPSWAP_OBSERVATION_SEED: &'static [u8] = + &[111, 98, 115, 101, 114, 118, 97, 116, 105, 111, 110]; + +pub const CPSWAP_OBSERVATION_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub fn create_cpswap_observation_pda( + cpswap_pool: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[CPSWAP_OBSERVATION_SEED, cpswap_pool.as_ref(), &[bump]], + &CPSWAP_OBSERVATION_PROGRAM_ADDRESS, + ) +} +pub fn find_cpswap_observation_pda(cpswap_pool: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[CPSWAP_OBSERVATION_SEED, cpswap_pool.as_ref()], + &CPSWAP_OBSERVATION_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/cpswap_quote_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/cpswap_quote_vault.rs new file mode 100644 index 0000000..d6977d1 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/cpswap_quote_vault.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; + +pub const CPSWAP_QUOTE_VAULT_SEED: &'static [u8] = + &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; + +pub const CPSWAP_QUOTE_VAULT_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub fn create_cpswap_quote_vault_pda( + cpswap_pool: Address, + quote_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + CPSWAP_QUOTE_VAULT_SEED, + cpswap_pool.as_ref(), + quote_mint.as_ref(), + &[bump], + ], + &CPSWAP_QUOTE_VAULT_PROGRAM_ADDRESS, + ) +} +pub fn find_cpswap_quote_vault_pda( + cpswap_pool: &Address, + quote_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + CPSWAP_QUOTE_VAULT_SEED, + cpswap_pool.as_ref(), + quote_mint.as_ref(), + ], + &CPSWAP_QUOTE_VAULT_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/event_authority.rs b/e2e/raydium-launchpad/src/generated/pdas/event_authority.rs new file mode 100644 index 0000000..20709f2 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/event_authority.rs @@ -0,0 +1,26 @@ +//! 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::RAYDIUM_LAUNCHPAD_ID; + +pub const EVENT_AUTHORITY_SEED: &'static [u8] = &[ + 95, 95, 101, 118, 101, 110, 116, 95, 97, 117, 116, 104, 111, 114, 105, 116, 121, +]; + +pub const EVENT_AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("2DPAtwB8L12vrMRExbLuyGnC7n2J5LNoZQSejeQGpwkr"); +pub fn create_event_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[EVENT_AUTHORITY_SEED, &[bump]], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_event_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address(&[EVENT_AUTHORITY_SEED], &RAYDIUM_LAUNCHPAD_ID) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/global_config.rs b/e2e/raydium-launchpad/src/generated/pdas/global_config.rs new file mode 100644 index 0000000..6f63c72 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/global_config.rs @@ -0,0 +1,45 @@ +//! 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::RAYDIUM_LAUNCHPAD_ID; + +pub const GLOBAL_CONFIG_SEED: &'static [u8] = + &[103, 108, 111, 98, 97, 108, 95, 99, 111, 110, 102, 105, 103]; +pub fn create_global_config_pda( + quote_token_mint: Address, + curve_type: u8, + index: u16, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + GLOBAL_CONFIG_SEED, + quote_token_mint.as_ref(), + curve_type.to_string().as_ref(), + index.to_string().as_ref(), + &[bump], + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_global_config_pda( + quote_token_mint: &Address, + curve_type: u8, + index: u16, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + GLOBAL_CONFIG_SEED, + quote_token_mint.as_ref(), + curve_type.to_string().as_ref(), + index.to_string().as_ref(), + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/lock_authority.rs b/e2e/raydium-launchpad/src/generated/pdas/lock_authority.rs new file mode 100644 index 0000000..9800531 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/lock_authority.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. +//! +//! +//! + +pub const LOCK_AUTHORITY_SEED: &'static [u8] = &[ + 108, 111, 99, 107, 95, 99, 112, 95, 97, 117, 116, 104, 111, 114, 105, 116, 121, 95, 115, 101, + 101, 100, +]; + +pub const LOCK_AUTHORITY_ADDRESS: solana_address::Address = + solana_address::address!("3f7GcQFG397GAaEnv51zR6tsTVihYRydnydDD1cXekxH"); + +pub const LOCK_AUTHORITY_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("LockrWmn6K5twhz3y9w1dQERbmgSaRkfnTeTKbpofwE"); +pub fn create_lock_authority_pda( + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[LOCK_AUTHORITY_SEED, &[bump]], + &LOCK_AUTHORITY_PROGRAM_ADDRESS, + ) +} +pub fn find_lock_authority_pda() -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[LOCK_AUTHORITY_SEED], + &LOCK_AUTHORITY_PROGRAM_ADDRESS, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/mod.rs b/e2e/raydium-launchpad/src/generated/pdas/mod.rs new file mode 100644 index 0000000..768704f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/mod.rs @@ -0,0 +1,52 @@ +//! 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 amm_authority; +pub mod amm_base_vault; +pub mod amm_config; +pub mod amm_lp_mint; +pub mod amm_open_orders; +pub mod amm_pool; +pub mod amm_quote_vault; +pub mod amm_target_orders; +pub mod authority; +pub mod base_vault; +pub mod cpswap_authority; +pub mod cpswap_base_vault; +pub mod cpswap_lp_mint; +pub mod cpswap_observation; +pub mod cpswap_quote_vault; +pub mod event_authority; +pub mod global_config; +pub mod lock_authority; +pub mod platform_config; +pub mod pool_state; +pub mod quote_vault; +pub mod vesting_record; + +pub use self::amm_authority::*; +pub use self::amm_base_vault::*; +pub use self::amm_config::*; +pub use self::amm_lp_mint::*; +pub use self::amm_open_orders::*; +pub use self::amm_pool::*; +pub use self::amm_quote_vault::*; +pub use self::amm_target_orders::*; +pub use self::authority::*; +pub use self::base_vault::*; +pub use self::cpswap_authority::*; +pub use self::cpswap_base_vault::*; +pub use self::cpswap_lp_mint::*; +pub use self::cpswap_observation::*; +pub use self::cpswap_quote_vault::*; +pub use self::event_authority::*; +pub use self::global_config::*; +pub use self::lock_authority::*; +pub use self::platform_config::*; +pub use self::pool_state::*; +pub use self::quote_vault::*; +pub use self::vesting_record::*; diff --git a/e2e/raydium-launchpad/src/generated/pdas/platform_config.rs b/e2e/raydium-launchpad/src/generated/pdas/platform_config.rs new file mode 100644 index 0000000..488530f --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/platform_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::RAYDIUM_LAUNCHPAD_ID; + +pub const PLATFORM_CONFIG_SEED: &'static [u8] = &[ + 112, 108, 97, 116, 102, 111, 114, 109, 95, 99, 111, 110, 102, 105, 103, +]; +pub fn create_platform_config_pda( + platform_admin: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[PLATFORM_CONFIG_SEED, platform_admin.as_ref(), &[bump]], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_platform_config_pda(platform_admin: &Address) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[PLATFORM_CONFIG_SEED, platform_admin.as_ref()], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/pool_state.rs b/e2e/raydium-launchpad/src/generated/pdas/pool_state.rs new file mode 100644 index 0000000..04ce450 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/pool_state.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::RAYDIUM_LAUNCHPAD_ID; + +pub const POOL_STATE_SEED: &'static [u8] = &[112, 111, 111, 108]; +pub fn create_pool_state_pda( + base_mint: Address, + quote_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + POOL_STATE_SEED, + base_mint.as_ref(), + quote_mint.as_ref(), + &[bump], + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_pool_state_pda( + base_mint: &Address, + quote_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[POOL_STATE_SEED, base_mint.as_ref(), quote_mint.as_ref()], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/quote_vault.rs b/e2e/raydium-launchpad/src/generated/pdas/quote_vault.rs new file mode 100644 index 0000000..8174aaa --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/quote_vault.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::RAYDIUM_LAUNCHPAD_ID; + +pub const QUOTE_VAULT_SEED: &'static [u8] = &[112, 111, 111, 108, 95, 118, 97, 117, 108, 116]; +pub fn create_quote_vault_pda( + pool_state: Address, + quote_mint: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + QUOTE_VAULT_SEED, + pool_state.as_ref(), + quote_mint.as_ref(), + &[bump], + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_quote_vault_pda( + pool_state: &Address, + quote_mint: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[QUOTE_VAULT_SEED, pool_state.as_ref(), quote_mint.as_ref()], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/pdas/vesting_record.rs b/e2e/raydium-launchpad/src/generated/pdas/vesting_record.rs new file mode 100644 index 0000000..3f8fc0b --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/pdas/vesting_record.rs @@ -0,0 +1,41 @@ +//! 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::RAYDIUM_LAUNCHPAD_ID; + +pub const VESTING_RECORD_SEED: &'static [u8] = + &[112, 111, 111, 108, 95, 118, 101, 115, 116, 105, 110, 103]; +pub fn create_vesting_record_pda( + pool_state: Address, + beneficiary: Address, + bump: u8, +) -> Result { + solana_address::Address::create_program_address( + &[ + VESTING_RECORD_SEED, + pool_state.as_ref(), + beneficiary.as_ref(), + &[bump], + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} +pub fn find_vesting_record_pda( + pool_state: &Address, + beneficiary: &Address, +) -> (solana_address::Address, u8) { + solana_address::Address::find_program_address( + &[ + VESTING_RECORD_SEED, + pool_state.as_ref(), + beneficiary.as_ref(), + ], + &RAYDIUM_LAUNCHPAD_ID, + ) +} diff --git a/e2e/raydium-launchpad/src/generated/programs.rs b/e2e/raydium-launchpad/src/generated/programs.rs new file mode 100644 index 0000000..d363645 --- /dev/null +++ b/e2e/raydium-launchpad/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}; + +/// `raydium_launchpad` program ID. +pub const RAYDIUM_LAUNCHPAD_ID: Address = address!("LanMV9sAd7wArD4vJFi2qDdfnVhFxYSUg6eADduJ3uj"); diff --git a/e2e/raydium-launchpad/src/generated/shared.rs b/e2e/raydium-launchpad/src/generated/shared.rs new file mode 100644 index 0000000..42eae7f --- /dev/null +++ b/e2e/raydium-launchpad/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/raydium-launchpad/src/generated/types/constant_curve.rs b/e2e/raydium-launchpad/src/generated/types/constant_curve.rs new file mode 100644 index 0000000..5681344 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/constant_curve.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; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct ConstantCurve { + pub supply: u64, + pub total_base_sell: u64, + pub total_quote_fund_raising: u64, + pub migrate_type: u8, +} diff --git a/e2e/raydium-launchpad/src/generated/types/curve_params.rs b/e2e/raydium-launchpad/src/generated/types/curve_params.rs new file mode 100644 index 0000000..210309d --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/curve_params.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::ConstantCurve; +use crate::generated::types::FixedCurve; +use crate::generated::types::LinearCurve; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum CurveParams { + Constant { data: ConstantCurve }, + Fixed { data: FixedCurve }, + Linear { data: LinearCurve }, +} diff --git a/e2e/raydium-launchpad/src/generated/types/fixed_curve.rs b/e2e/raydium-launchpad/src/generated/types/fixed_curve.rs new file mode 100644 index 0000000..e29ed07 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/fixed_curve.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 FixedCurve { + pub supply: u64, + pub total_quote_fund_raising: u64, + pub migrate_type: u8, +} diff --git a/e2e/raydium-launchpad/src/generated/types/linear_curve.rs b/e2e/raydium-launchpad/src/generated/types/linear_curve.rs new file mode 100644 index 0000000..98367b1 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/linear_curve.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 LinearCurve { + pub supply: u64, + pub total_quote_fund_raising: u64, + pub migrate_type: u8, +} diff --git a/e2e/raydium-launchpad/src/generated/types/migrate_nft_info.rs b/e2e/raydium-launchpad/src/generated/types/migrate_nft_info.rs new file mode 100644 index 0000000..75dcc37 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/migrate_nft_info.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Represents the parameters for initializing a platform config account(Only support MigrateType::CPSWAP) +/// # Fields +/// * `platform_scale` - Scale of the platform liquidity quantity rights will be converted into NFT +/// * `creator_scale` - Scale of the token creator liquidity quantity rights will be converted into NFT +/// * `burn_scale` - Scale of liquidity directly to burn +/// +/// * platform_scale + creator_scale + burn_scale = RATE_DENOMINATOR_VALUE +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct MigrateNftInfo { + pub platform_scale: u64, + pub creator_scale: u64, + pub burn_scale: u64, +} diff --git a/e2e/raydium-launchpad/src/generated/types/mint_params.rs b/e2e/raydium-launchpad/src/generated/types/mint_params.rs new file mode 100644 index 0000000..2f209c4 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/mint_params.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Represents the parameters for initializing a new token mint +/// # Fields +/// * `decimals` - Number of decimal places for the token +/// * `name` - Name of the token +/// * `symbol` - Symbol/ticker of the token +/// * `uri` - URI pointing to token metadata +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct MintParams { + pub decimals: u8, + pub name: String, + pub symbol: String, + pub uri: String, +} diff --git a/e2e/raydium-launchpad/src/generated/types/mod.rs b/e2e/raydium-launchpad/src/generated/types/mod.rs new file mode 100644 index 0000000..f72256d --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/mod.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. +//! +//! +//! + +pub(crate) mod r#constant_curve; +pub(crate) mod r#curve_params; +pub(crate) mod r#fixed_curve; +pub(crate) mod r#linear_curve; +pub(crate) mod r#migrate_nft_info; +pub(crate) mod r#mint_params; +pub(crate) mod r#platform_config_param; +pub(crate) mod r#pool_status; +pub(crate) mod r#trade_direction; +pub(crate) mod r#vesting_params; +pub(crate) mod r#vesting_schedule; + +pub use self::r#constant_curve::*; +pub use self::r#curve_params::*; +pub use self::r#fixed_curve::*; +pub use self::r#linear_curve::*; +pub use self::r#migrate_nft_info::*; +pub use self::r#mint_params::*; +pub use self::r#platform_config_param::*; +pub use self::r#pool_status::*; +pub use self::r#trade_direction::*; +pub use self::r#vesting_params::*; +pub use self::r#vesting_schedule::*; diff --git a/e2e/raydium-launchpad/src/generated/types/platform_config_param.rs b/e2e/raydium-launchpad/src/generated/types/platform_config_param.rs new file mode 100644 index 0000000..8bc34a1 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/platform_config_param.rs @@ -0,0 +1,22 @@ +//! 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::MigrateNftInfo; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_address::Address; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub enum PlatformConfigParam { + FeeWallet(Address), + NFTWallet(Address), + MigrateNftInfo(MigrateNftInfo), + FeeRate(u64), + Name(String), + Web(String), + Img(String), +} diff --git a/e2e/raydium-launchpad/src/generated/types/pool_status.rs b/e2e/raydium-launchpad/src/generated/types/pool_status.rs new file mode 100644 index 0000000..c1c93c1 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/pool_status.rs @@ -0,0 +1,32 @@ +//! 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; + +/// Represents the different states a pool can be in +/// * Fund - Initial state where pool is accepting funds +/// * Migrate - Pool funding has ended and waiting for migration +/// * Trade - Pool migration is complete and amm trading is enabled +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum PoolStatus { + Fund, + Migrate, + Trade, +} diff --git a/e2e/raydium-launchpad/src/generated/types/trade_direction.rs b/e2e/raydium-launchpad/src/generated/types/trade_direction.rs new file mode 100644 index 0000000..2de0f0e --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/trade_direction.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; +use num_derive::FromPrimitive; + +/// Specifies the direction of a trade in the bonding curve +/// This is important because curves can treat tokens differently through weights or offsets +#[derive( + BorshSerialize, + BorshDeserialize, + Clone, + Debug, + Eq, + PartialEq, + Copy, + PartialOrd, + Hash, + FromPrimitive, +)] +pub enum TradeDirection { + Buy, + Sell, +} diff --git a/e2e/raydium-launchpad/src/generated/types/vesting_params.rs b/e2e/raydium-launchpad/src/generated/types/vesting_params.rs new file mode 100644 index 0000000..7451193 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/vesting_params.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 VestingParams { + pub total_locked_amount: u64, + pub cliff_period: u64, + pub unlock_period: u64, +} diff --git a/e2e/raydium-launchpad/src/generated/types/vesting_schedule.rs b/e2e/raydium-launchpad/src/generated/types/vesting_schedule.rs new file mode 100644 index 0000000..d91c454 --- /dev/null +++ b/e2e/raydium-launchpad/src/generated/types/vesting_schedule.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 borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +pub struct VestingSchedule { + pub total_locked_amount: u64, + pub cliff_period: u64, + pub unlock_period: u64, + pub start_time: u64, + /// Total allocated share amount of the base token, not greater than total_locked_amount + pub allocated_share_amount: u64, +} diff --git a/e2e/raydium-launchpad/src/lib.rs b/e2e/raydium-launchpad/src/lib.rs new file mode 100644 index 0000000..6040d68 --- /dev/null +++ b/e2e/raydium-launchpad/src/lib.rs @@ -0,0 +1,106 @@ +mod generated; + +pub use generated::programs::RAYDIUM_LAUNCHPAD_ID as ID; +pub use generated::*; + +#[cfg(test)] +mod tests { + use solana_address::{address, Address}; + + fn filler(byte: u8) -> Address { + Address::new_from_array([byte; 32]) + } + + /// PDAs with a dynamic `programId` (a runtime account reference) must derive + /// under that program, not the local launchpad program. Expected addresses are + /// computed independently with codama's `dynamic-address-resolution` package + /// (the runtime source of truth), using + /// `market = So11111111111111111111111111111111111111112` and the default + /// (canonical) amm program `675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8`. + #[test] + fn migrate_to_amm_derives_pdas_under_dynamic_amm_program() { + let market = address!("So11111111111111111111111111111111111111112"); + let ix = crate::instructions::MigrateToAmmBuilder::new( + filler(1), // payer + filler(2), // base_mint + filler(3), // quote_mint + market, // market + filler(5), // request_queue + filler(6), // event_queue + filler(7), // bids + filler(8), // asks + filler(9), // market_vault_signer + filler(10), // market_base_vault + filler(11), // market_quote_vault + filler(12), // amm_create_fee_destination + filler(13), // global_config + filler(14), // base_vault + filler(15), // quote_vault + filler(16), // pool_lp_token + 1, // base_lot_size + 1, // quote_lot_size + 0, // market_vault_signer_nonce + ) + .instruction(); + + assert_eq!( + ix.accounts[13].pubkey, + address!("2ooeaoRtTBK2EgKFLUKeZVz7SJZo3etuVhHagwPxBegj"), + "amm_pool" + ); + assert_eq!( + ix.accounts[14].pubkey, + address!("5Q544fKrFoe6tsEbD7S8EmxGTJYAKtTVhAW5Q5pge4j1"), + "amm_authority" + ); + assert_eq!( + ix.accounts[15].pubkey, + address!("HUGGGKtDNCKVTWPRVcTXyEJxNchMhhyZjhvUpfqPbka"), + "amm_open_orders" + ); + assert_eq!( + ix.accounts[20].pubkey, + address!("9DCxsMizn3H1hprZ7xWe6LDzeUeZBksYFpBWBtSf1PQX"), + "amm_config" + ); + } + + /// Same as above for the cpswap/lock programs, with + /// `cpswap_pool = base_mint = quote_mint = So11111111111111111111111111111111111111112` + /// and the default cpswap/lock programs. + #[test] + fn migrate_to_cpswap_derives_pdas_under_dynamic_programs() { + let shared = address!("So11111111111111111111111111111111111111112"); + let ix = crate::instructions::MigrateToCpswapBuilder::new( + filler(1), // payer + shared, // base_mint + shared, // quote_mint + filler(4), // platform_config + shared, // cpswap_pool + filler(6), // cpswap_config + filler(7), // cpswap_create_pool_fee + filler(8), // lock_lp_vault + filler(9), // global_config + filler(10), // base_vault + filler(11), // quote_vault + filler(12), // pool_lp_token + ) + .instruction(); + + assert_eq!( + ix.accounts[6].pubkey, + address!("GpMZbSM2GgvTKHJirzeGfMFoaZ8UR2X7F4v8vHTvxFbL"), + "cpswap_authority" + ); + assert_eq!( + ix.accounts[7].pubkey, + address!("CnXtmAN29yi5xNoc47HhtfEER7Ei3F3BBDM9KL6jen6d"), + "cpswap_lp_mint" + ); + assert_eq!( + ix.accounts[14].pubkey, + address!("3f7GcQFG397GAaEnv51zR6tsTVihYRydnydDD1cXekxH"), + "lock_authority" + ); + } +} diff --git a/e2e/system/src/generated/accounts/nonce.rs b/e2e/system/src/generated/accounts/nonce.rs index 0f843c2..409cc42 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..ffa0329 100755 --- a/e2e/test.sh +++ b/e2e/test.sh @@ -18,5 +18,8 @@ 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 +test_anchor_project anchor +test_anchor_project raydium-cpmm +test_anchor_project raydium-launchpad \ No newline at end of file diff --git a/package.json b/package.json index 1fa2972..6dbacb4 100644 --- a/package.json +++ b/package.json @@ -41,11 +41,12 @@ "test:unit": "vitest run" }, "dependencies": { - "@codama/errors": "^1.5.0", - "@codama/nodes": "^1.5.0", + "@codama/errors": "^1.6.0", + "@codama/nodes": "^1.6.0", "@codama/renderers-core": "^1.3.5", - "@codama/visitors-core": "^1.5.0", + "@codama/visitors-core": "^1.6.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.1", "@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..64c9068 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,28 +4,41 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/node-types': https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/nodes': https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/nodes-from-anchor': https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/renderers-core': https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/visitors': https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/visitors-core': https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/validators': https://pkg.pr.new/ioxde/codama/@codama/validators@c8c4954ff716d41c81c9aad5d306470b83715b27 + importers: .: dependencies: '@codama/errors': - specifier: ^1.5.0 - version: 1.5.0 + specifier: https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + version: https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 '@codama/nodes': - specifier: ^1.5.0 - version: 1.5.0 + specifier: https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 + version: https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 '@codama/renderers-core': - specifier: ^1.3.5 - version: 1.3.5 + specifier: https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27 + version: https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27 '@codama/visitors-core': - specifier: ^1.5.0 - version: 1.5.0 + specifier: https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27 + version: https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27 '@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 +53,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: https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27 + version: https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27(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 +97,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 +147,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 +177,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 +193,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 +241,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 +251,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 +327,47 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@codama/errors@1.4.4': - resolution: {integrity: sha512-XC86H5X+zGTi0cSRKLc+wFkeXNsvnh+ttOgVnVHIljmXOJWbUt9wXhKding3UftipLWwlHPuoswERJ0vS0mO2A==} - hasBin: true - - '@codama/errors@1.5.0': - resolution: {integrity: sha512-i4cS+S7JaZXhofQHFY3cwzt8rqxUVPNaeJND5VOyKUbtcOi933YXJXk52gDG4mc+CpGqHJijsJjfSpr1lJGxzg==} + '@codama/errors@https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.7.0 hasBin: true - '@codama/node-types@1.4.4': - resolution: {integrity: sha512-uUeIz34Id/TTAMi4k5OVl9FByM/PawnlNIIVqgpooH9AS0UlniICZ+KJ/mdHZidJs/AGo6bSRoOPS1BLtMajyw==} + '@codama/fragments@https://pkg.pr.new/ioxde/codama/@codama/fragments@c8c4954': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/fragments@c8c4954} + version: 0.1.0 - '@codama/node-types@1.5.0': - resolution: {integrity: sha512-Ebz2vOUukmNaFXWdkni1ZihXkAIUnPYtqIMXYxKXOxjMP+TGz2q0lGtRo7sqw1pc2ksFBIkfBp5pZsl5p6gwXA==} + '@codama/node-types@https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.7.0 - '@codama/nodes-from-anchor@1.3.6': - resolution: {integrity: sha512-614DZS9H5gW16Rkeu0ES8BHnDvbd8M9FLqPWnp9QUE0b+wCvWB36yZiRylJ4fw8gRDSc+FR7C2i3NXKycpvBEg==} + '@codama/nodes-from-anchor@https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.5.0 - '@codama/nodes@1.4.4': - resolution: {integrity: sha512-JzlY5qLk3rhsnu0nerC/Vkc9/2HjdsLtEpBtST0dxC1j9kpfHvIc2uyIj+5hlB1YIBRJIDNo+UOHGla8hidkaA==} + '@codama/nodes@https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.7.0 - '@codama/nodes@1.5.0': - resolution: {integrity: sha512-yg+xmorWiMNjS3n19CGIt/FZ/ZCuDIu+HEY45bq6gHu1MN3RtJZY+Q3v0ErnBPA60D8mNWkvkKoeSZXfzcAvfw==} + '@codama/renderers-core@https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.3.8 - '@codama/renderers-core@1.3.5': - resolution: {integrity: sha512-MuZLU+3LZPQb1HuZffwZl+v5JHQDe5LYHGhA1wTMNlwRedYIysSxBjogHNciNIHsKP3JjmqyYmLO5LCEp3hjaQ==} + '@codama/visitors-core@https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.7.0 - '@codama/visitors-core@1.4.4': - resolution: {integrity: sha512-vk/4tczViAUHa7c8PF7FxN+JWbuTcDB0pIdrDbbO6eBPKDPQGZCUCEp6rXIYBVxfO129jWrNf2+CuyYre/c/vA==} + '@codama/visitors@https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27': + resolution: {tarball: https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27} + version: 1.7.0 - '@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 +687,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 +880,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 +1137,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 +1146,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 +1164,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 +1191,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 +1215,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 +1260,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 +1328,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 +1376,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 +1390,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 +1400,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 +1421,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 +1440,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 +1459,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,12 +1474,13 @@ 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': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} @@ -1663,8 +1711,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 +1730,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 @@ -1706,8 +1763,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -1726,8 +1783,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 +1813,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 +1838,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 +1883,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 +1925,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==} @@ -1903,8 +1956,8 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} esbuild@0.25.12: @@ -1985,6 +2038,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} @@ -2207,8 +2264,8 @@ packages: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} html-escaper@2.0.2: @@ -2579,13 +2636,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 +2699,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 +2821,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 +2971,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 +3082,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 +3129,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 +3202,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 +3212,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 +3362,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 +3390,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 +3432,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 +3712,65 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 - '@codama/errors@1.4.4': + '@codama/errors@https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27': dependencies: - '@codama/node-types': 1.4.4 - commander: 14.0.2 + '@codama/node-types': https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27 + commander: 14.0.3 picocolors: 1.1.1 - '@codama/errors@1.5.0': + '@codama/fragments@https://pkg.pr.new/ioxde/codama/@codama/fragments@c8c4954': dependencies: - '@codama/node-types': 1.5.0 - commander: 14.0.2 - picocolors: 1.1.1 - - '@codama/node-types@1.4.4': {} + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 - '@codama/node-types@1.5.0': {} + '@codama/node-types@https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27': {} - '@codama/nodes-from-anchor@1.3.6(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + '@codama/nodes-from-anchor@https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27(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': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/nodes': https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/visitors': https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27 '@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': + '@codama/nodes@https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27': dependencies: - '@codama/errors': 1.4.4 - '@codama/node-types': 1.4.4 + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/node-types': https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27 - '@codama/nodes@1.5.0': + '@codama/renderers-core@https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27': dependencies: - '@codama/errors': 1.5.0 - '@codama/node-types': 1.5.0 + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/fragments': https://pkg.pr.new/ioxde/codama/@codama/fragments@c8c4954 + '@codama/nodes': https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/visitors-core': https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27 - '@codama/renderers-core@1.3.5': + '@codama/visitors-core@https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27': dependencies: - '@codama/errors': 1.5.0 - '@codama/nodes': 1.5.0 - '@codama/visitors-core': 1.5.0 - - '@codama/visitors-core@1.4.4': - dependencies: - '@codama/errors': 1.4.4 - '@codama/nodes': 1.4.4 + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/nodes': https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 json-stable-stringify: 1.3.0 - '@codama/visitors-core@1.5.0': + '@codama/visitors@https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27': dependencies: - '@codama/errors': 1.5.0 - '@codama/nodes': 1.5.0 - json-stable-stringify: 1.3.0 + '@codama/errors': https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/nodes': https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27 + '@codama/visitors-core': https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27 - '@codama/visitors@1.4.4': + '@emnapi/core@1.9.1': dependencies: - '@codama/errors': 1.4.4 - '@codama/nodes': 1.4.4 - '@codama/visitors-core': 1.4.4 - - '@emnapi/core@1.7.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 +3936,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 +4030,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 +4044,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 +4078,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 +4096,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 +4114,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 +4125,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 +4147,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 +4178,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 +4202,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 +4243,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 +4407,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 +4417,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 +4510,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 +4535,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 +4594,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 +4624,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 +4651,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 +4677,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 +4697,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 +4706,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 +4715,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 +4731,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 +4763,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 +4779,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 +4800,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 +4955,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 +4969,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 +4984,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 +4994,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 +5042,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: @@ -4980,7 +5076,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -4998,7 +5094,7 @@ snapshots: camelcase@6.3.0: {} - caniuse-lite@1.0.30001757: {} + caniuse-lite@1.0.30001781: {} chai@6.2.1: {} @@ -5019,9 +5115,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 +5135,6 @@ snapshots: color-name@1.1.4: {} - commander@14.0.1: {} - commander@14.0.2: {} commander@14.0.3: {} @@ -5069,7 +5163,7 @@ snapshots: dependencies: ms: 2.1.3 - dedent@1.7.0: {} + dedent@1.7.2: {} deep-is@0.1.4: {} @@ -5099,7 +5193,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.263: {} + electron-to-chromium@1.5.322: {} emittery@0.13.1: {} @@ -5122,7 +5216,7 @@ snapshots: es-module-lexer@1.7.0: {} - es-object-atoms@1.1.1: + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -5192,7 +5286,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 +5337,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 +5451,8 @@ snapshots: fast-levenshtein@2.0.6: {} - fastestsmallesttextencoderdecoder@1.0.22: {} + fastestsmallesttextencoderdecoder@1.0.22: + optional: true fastq@1.19.1: dependencies: @@ -5433,12 +5530,12 @@ snapshots: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.4 math-intrinsics: 1.1.0 get-package-type@0.1.0: {} @@ -5446,7 +5543,7 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-stream@6.0.1: {} @@ -5478,7 +5575,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 @@ -5513,7 +5610,7 @@ snapshots: has-symbols@1.1.0: {} - hasown@2.0.2: + hasown@2.0.4: dependencies: function-bind: 1.1.2 @@ -5580,11 +5677,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 +5722,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 +5763,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 +5793,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 +5849,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 +5857,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 +5883,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 +5896,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 +5930,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 +5959,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 +5979,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 +5998,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 +6025,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 +6034,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 @@ -5955,7 +6084,7 @@ snapshots: json-stable-stringify@1.3.0: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 isarray: 2.0.5 jsonify: 0.0.1 @@ -6012,7 +6141,7 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 makeerror@1.0.12: dependencies: @@ -6035,14 +6164,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 +6217,7 @@ snapshots: node-int64@0.4.0: {} - node-releases@2.0.27: {} + node-releases@2.0.36: {} normalize-path@3.0.0: {} @@ -6151,7 +6292,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 +6321,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 +6473,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 +6575,7 @@ snapshots: dependencies: has-flag: 4.0.0 - synckit@0.11.11: + synckit@0.11.12: dependencies: '@pkgr/core': 0.2.9 @@ -6438,7 +6585,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 +6616,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 +6687,8 @@ snapshots: undici-types@7.16.0: {} + undici-types@7.18.2: {} + universalify@0.1.2: {} unrs-resolver@1.11.1: @@ -6566,9 +6715,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/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..6cccea3 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,14 @@ +# Forked codama packages, served as prebuilt tarballs by pkg.pr.new +# (producer: ioxde/codama .github/workflows/main.yml `publish-preview` job). +# Pinned to ioxde/codama@c8c4954 (main). workspace:* deps are rewritten by +# pkg.pr.new at publish time, so installing these resolves the whole fork set. +# These are overrides only — not part of the published @codama/renderers-rust. +overrides: + '@codama/errors': 'https://pkg.pr.new/ioxde/codama/@codama/errors@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/node-types': 'https://pkg.pr.new/ioxde/codama/@codama/node-types@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/nodes': 'https://pkg.pr.new/ioxde/codama/@codama/nodes@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/nodes-from-anchor': 'https://pkg.pr.new/ioxde/codama/@codama/nodes-from-anchor@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/renderers-core': 'https://pkg.pr.new/ioxde/codama/@codama/renderers-core@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/visitors': 'https://pkg.pr.new/ioxde/codama/@codama/visitors@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/visitors-core': 'https://pkg.pr.new/ioxde/codama/@codama/visitors-core@c8c4954ff716d41c81c9aad5d306470b83715b27' + '@codama/validators': 'https://pkg.pr.new/ioxde/codama/@codama/validators@c8c4954ff716d41c81c9aad5d306470b83715b27' diff --git a/public/templates/accountsPage.njk b/public/templates/accountsPage.njk index dd0a82d..931193d 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/eventsMod.njk b/public/templates/eventsMod.njk new file mode 100644 index 0000000..db434ef --- /dev/null +++ b/public/templates/eventsMod.njk @@ -0,0 +1,23 @@ +{% extends "layout.njk" %} + +{% block main %} + +{% for event in eventsToExport | sort(false, false, 'name') %} + pub(crate) mod r#{{ event.name | snakeCase }}; +{% endfor %} +{% for program in programsToExport | sort(false, false, 'name') %} +{% if programsWithEventEnum.has(program.name) %} + pub(crate) mod r#{{ program.name | snakeCase }}_events; +{% endif %} +{% endfor %} + +{% for event in eventsToExport | sort(false, false, 'name') %} + pub use self::r#{{ event.name | snakeCase }}::*; +{% endfor %} +{% for program in programsToExport | sort(false, false, 'name') %} +{% if programsWithEventEnum.has(program.name) %} + pub use self::r#{{ program.name | snakeCase }}_events::*; +{% endif %} +{% endfor %} + +{% endblock %} diff --git a/public/templates/eventsPage.njk b/public/templates/eventsPage.njk new file mode 100644 index 0000000..d3b5319 --- /dev/null +++ b/public/templates/eventsPage.njk @@ -0,0 +1,38 @@ +{% extends "layout.njk" %} +{% import "macros.njk" as macros %} + +{% block main %} + +{{ imports }} + +{{ macros.docblock(event.docs) }} +{{- typeManifest.type }} + +{% for nestedStruct in typeManifest.nestedStructs %} +{{ nestedStruct }} +{% endfor %} + +{{ discriminatorConstants }} + +{% if constantDiscriminators.length > 0 %} +impl {{ event.name | pascalCase }} { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { +{% for disc in constantDiscriminators %} + if {{ disc.condition }} { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "invalid event discriminator", + )); + } +{% endfor %} +{% if hiddenPrefixSkip.comment %} + // {{ hiddenPrefixSkip.comment }} +{% endif %} + let mut data = {{ hiddenPrefixSkip.expr }}; + Self::deserialize(&mut data) + } +} +{% endif %} + +{% endblock %} 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..835fb27 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,122 @@ {% 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 %} + {% for arg in extraArgs %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% 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 %} + {% for arg in extraArgs %} + {{ arg.name | snakeCase }}: {{ arg.type }}, + {% 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 %} + {% for arg in extraArgs %} + {{ arg.name | snakeCase }}, + {% 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 +156,56 @@ 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 and not account.pdaDefault.hasDynamicProgram %} + {% if account.isSigner === 'either' %} + let {{ account.name | snakeCase }} = self.{{ account.name | snakeCase }}.map(|(k, _)| k).unwrap_or( {% else %} - {{ account.name | snakeCase }}: self.{{ account.name | snakeCase }}.expect("{{ account.name | snakeCase }} is not set"), + 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 %} + {% if account.pdaDefault.hasDynamicProgram %} + &{{ account.pdaDefault.programAddressExpr }}, + {% endif %} + ).0 + {% else %} + 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 +218,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..5cf8278 --- /dev/null +++ b/public/templates/pdasPage.njk @@ -0,0 +1,253 @@ +{% extends "layout.njk" %} +{% import "macros.njk" as macros %} + +{% block main %} + +{{ imports }} + +{% if program and not dynamicProgramOnly %} +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 %} +{% if dynamicProgramOnly and canonicalProgramAddress %} + +{# The IDL pins the owning program's address (Anchor address constraint), so bake it in. #} +pub const {{ pda.name | snakeCase | upper }}_PROGRAM_ADDRESS: solana_address::Address = + solana_address::address!("{{ canonicalProgramAddress }}"); + +{{- 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 constantUsageIndexP = 0 %} + {% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} + {{ pda.name | snakeCase | upper }}_PROGRAM_ADDRESS.as_ref(), + {% elif seed.kind === 'constantPdaSeedNode' %} + {{ pda.name | snakeCase | upper }}_SEED{% if constantSeeds.length > 1 %}_{{ constantUsageIndexP }}{% endif %}, + {% set constantUsageIndexP = constantUsageIndexP + 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], + ], + &{{ pda.name | snakeCase | upper }}_PROGRAM_ADDRESS, + ) +} + +{{- 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 constantUsageIndexP2 = 0 %} + {% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} + {{ pda.name | snakeCase | upper }}_PROGRAM_ADDRESS.as_ref(), + {% elif seed.kind === 'constantPdaSeedNode' %} + {{ pda.name | snakeCase | upper }}_SEED{% if constantSeeds.length > 1 %}_{{ constantUsageIndexP2 }}{% endif %}, + {% set constantUsageIndexP2 = constantUsageIndexP2 + 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 %} + ], + &{{ pda.name | snakeCase | upper }}_PROGRAM_ADDRESS, + ) +} +{% elif dynamicProgramOnly %} + +{# The deriving program is unpinned and only known at runtime, so callers pass it in. #} +{{- 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, + program_address: &solana_address::Address, +) -> Result { + solana_address::Address::create_program_address( + &[ + {% set constantUsageIndex = 0 %} + {% for seed in seeds %} + {% if seed.kind === 'constantPdaSeedNode' and seed.value.kind === 'programIdValueNode' %} + program_address.as_ref(), + {% 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], + ], + program_address, + ) +} + +{{- 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 %} + program_address: &solana_address::Address, +) -> (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' %} + program_address.as_ref(), + {% 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 %} + ], + program_address, + ) +} +{% else %} + +{{- 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 constantUsageIndex3 = 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 %}_{{ constantUsageIndex3 }}{% endif %}, + {% set constantUsageIndex3 = constantUsageIndex3 + 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 constantUsageIndex4 = 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 %}_{{ constantUsageIndex4 }}{% endif %}, + {% set constantUsageIndex4 = constantUsageIndex4 + 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 %} + ) +} +{% endif %} + +{% endblock %} diff --git a/public/templates/programEventsPage.njk b/public/templates/programEventsPage.njk new file mode 100644 index 0000000..6bfc8aa --- /dev/null +++ b/public/templates/programEventsPage.njk @@ -0,0 +1,56 @@ +{% extends "layout.njk" %} + +{% block main %} + +{{ imports }} + +{% if eventFramingBytes and eventFramingName %} +/// Shared event-framing tag prepended to every framed event emitted by the +/// `{{ program.name | snakeCase }}` program. +pub const {{ eventFramingName }}: [u8; {{ eventFramingBytes.len }}] = {{ eventFramingBytes.literal }}; + +{% endif %} +/// Event kinds for the `{{ program.name | snakeCase }}` program. +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum {{ program.name | pascalCase }}EventKind { +{% for event in eventsWithDiscriminators | sort(false, false, 'name') %} + {{ event.name | pascalCase }}, +{% endfor %} +} + +/// Identifies a `{{ program.name | snakeCase }}` event from the provided data. +pub fn identify_{{ program.name | snakeCase }}_event(data: &[u8]) -> Option<{{ program.name | pascalCase }}EventKind> { +{% for event in eventsWithDiscriminators | sort(false, false, 'name') %} + if {{ event.conditions | join(' && ') }} { + return Some({{ program.name | pascalCase }}EventKind::{{ event.name | pascalCase }}); + } +{% endfor %} + None +} + +/// Parsed event variants for the `{{ program.name | snakeCase }}` program. +#[derive(Clone, Debug, PartialEq)] +pub enum {{ program.name | pascalCase }}Event { +{% for event in eventsWithDiscriminators | sort(false, false, 'name') %} + {{ event.name | pascalCase }}({{ event.name | pascalCase }}), +{% endfor %} +} + +/// Tries to parse a `{{ program.name | snakeCase }}` event from the provided data. +pub fn try_parse_{{ program.name | snakeCase }}_event(data: &[u8]) -> Option> { + let event_kind = identify_{{ program.name | snakeCase }}_event(data)?; + Some(match event_kind { +{% for event in eventsWithDiscriminators | sort(false, false, 'name') %} + {{ program.name | pascalCase }}EventKind::{{ event.name | pascalCase }} => { +{% if event.hiddenPrefixSkip.comment %} + // {{ event.hiddenPrefixSkip.comment }} +{% endif %} + let mut data = {{ event.hiddenPrefixSkip.expr }}; + {{ event.name | pascalCase }}::deserialize(&mut data) + .map({{ program.name | pascalCase }}Event::{{ event.name | pascalCase }}) + } +{% endfor %} + }) +} + +{% endblock %} diff --git a/public/templates/rootMod.njk b/public/templates/rootMod.njk index d792bcb..dc7d677 100644 --- a/public/templates/rootMod.njk +++ b/public/templates/rootMod.njk @@ -9,9 +9,15 @@ {% if programsToExport.length > 0 %} pub mod errors; {% endif %} + {% if eventsToExport.length > 0 %} + pub mod events; + {% endif %} {% 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/ImportMap.ts b/src/ImportMap.ts index f4a59c6..9dee67e 100644 --- a/src/ImportMap.ts +++ b/src/ImportMap.ts @@ -7,6 +7,7 @@ const DEFAULT_MODULE_MAP: Record = { generated: 'crate::generated', generatedAccounts: 'crate::generated::accounts', generatedErrors: 'crate::generated::errors', + generatedEvents: 'crate::generated::events', generatedInstructions: 'crate::generated::instructions', generatedTypes: 'crate::generated::types', hooked: 'crate::hooked', diff --git a/src/getRenderMapVisitor.ts b/src/getRenderMapVisitor.ts index 55e65a1..eac6d4c 100644 --- a/src/getRenderMapVisitor.ts +++ b/src/getRenderMapVisitor.ts @@ -1,14 +1,26 @@ import { logWarn } from '@codama/errors'; import { + type ConstantPdaSeedNode, + ConstantValueNode, + constantValueNode, + definedTypeNode, + EventFraming, + EventNode, getAllAccounts, getAllDefinedTypes, + getAllEvents, + getAllInstructionArguments, getAllInstructionsWithSubs, + getAllPdas, getAllPrograms, + type InstructionAccountNode, InstructionNode, isNode, isNodeFilter, pascalCase, - ProgramNode, + type PdaNode, + type PdaValueNode, + type ProgramNode, resolveNestedTypeNode, snakeCase, structTypeNodeFromInstructionArgumentNodes, @@ -17,6 +29,8 @@ import { import { addToRenderMap, createRenderMap, mergeRenderMaps } from '@codama/renderers-core'; import { extendVisitor, + findProgramNodeFromPath, + getResolvedInstructionInputsVisitor, LinkableDictionary, NodeStack, pipe, @@ -25,18 +39,26 @@ import { staticVisitor, visit, } from '@codama/visitors-core'; +import { getBase58Encoder } from '@solana/codecs-strings'; import { getTypeManifestVisitor } from './getTypeManifestVisitor'; import { ImportMap } from './ImportMap'; import { renderValueNode } from './renderValueNodeVisitor'; import { CargoDependencies, + computePdaAddress, + constantDiscriminatorName, + constantDiscriminatorSize, Fragment, + getByteArrayDiscriminatorConstantName, + getDiscriminatorConditions, getDiscriminatorConstants, getImportFromFactory, + type GetImportFromFunction, getTraitsFromNodeFactory, LinkOverrides, render, + renderByteCheck, TraitOptions, } from './utils'; @@ -53,7 +75,8 @@ export type GetRenderMapOptions = { export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const linkables = new LinkableDictionary(); const stack = new NodeStack(); - let program: ProgramNode | null = null; + let programEventFraming: ResolvedProgramEventFraming | undefined = undefined; + const programsWithEventEnum = new Set(); const renderParentInstructions = options.renderParentInstructions ?? false; const dependencyMap = options.dependencyMap ?? {}; @@ -64,15 +87,33 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { getTraitsFromNode, traitOptions: options.traitOptions, }); + // Optional accounts are safe as PDA seeds: builders hold accounts as + // Option and only expect() them on the derive path. + const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor({ + allowOptionalAccountsAsPdaSeeds: true, + }); const anchorTraits = options.anchorTraits ?? true; return pipe( staticVisitor(() => createRenderMap(), { - keys: ['rootNode', 'programNode', 'instructionNode', 'accountNode', 'definedTypeNode'], + keys: [ + 'rootNode', + 'programNode', + 'instructionNode', + 'accountNode', + 'definedTypeNode', + 'eventNode', + '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 +126,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 +147,10 @@ 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 }; + const seedBytes = renderConstantSeedBytes(seed, getImportFrom); + seedsImports.mergeWith(seedBytes.imports); + return { ...seed, resolvedType, seedBytesExpr: seedBytes.render, typeManifest: seedManifest }; }); const hasVariableSeeds = pdaSeeds.filter(isNodeFilter('variablePdaSeedNode')).length > 0; const constantSeeds = seeds @@ -120,6 +167,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { account: node, anchorTraits, constantSeeds, + discriminatorConstantName, discriminatorConstants: discriminatorConstants.render, hasVariableSeeds, imports: imports.toString(dependencyMap), @@ -148,7 +196,105 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }); }, + visitEvent(node) { + const allDiscriminators = node.discriminators ?? []; + const isCpiFramed = isEventCpiFramed(node, programEventFraming); + const framingConstantName = isCpiFramed + ? snakeCase(programEventFraming!.framing.sharedConstantName).toUpperCase() + : null; + // Strip the hoisted framing constant so per-event _DISCRIMINATOR matches IDL events[].discriminator bytes. + const discriminators = isCpiFramed ? allDiscriminators.slice(1) : allDiscriminators; + const innerType = resolveNestedTypeNode(node.data); + // Wrap as definedTypeNode so typeManifestVisitor generates the struct with derives. + const syntheticType = definedTypeNode({ + docs: node.docs, + name: node.name, + type: innerType, + }); + const typeManifest = visit(syntheticType, typeManifestVisitor); + + // Discriminator constants (excluding the hoisted framing one for CPI-framed events). + const fields = isNode(innerType, 'structTypeNode') ? innerType.fields : []; + const discriminatorConstants = getDiscriminatorConstants({ + discriminatorNodes: discriminators, + fields, + getImportFrom, + prefix: node.name, + typeManifestVisitor, + }); + + const hasFromBytes = eventHasFromBytes(node); + const perEventConstantDiscriminators = hasFromBytes + ? discriminators + .filter(isNodeFilter('constantDiscriminatorNode')) + .map(d => { + const name = snakeCase( + constantDiscriminatorName(node.name, d, discriminators), + ).toUpperCase(); + return { + condition: renderByteCheck(name, d.constant.type, d.offset, true), + name, + offset: d.offset, + size: constantDiscriminatorSize(d), + }; + }) + .sort((a, b) => a.offset - b.offset) + : []; + + const allConstantDiscriminators = + isCpiFramed && framingConstantName + ? [ + { + condition: renderByteCheck( + framingConstantName, + programEventFraming!.constant.type, + 0, + true, + ), + name: framingConstantName, + offset: 0, + size: renderConstantBytesArray(programEventFraming!.constant)?.len ?? null, + }, + ...perEventConstantDiscriminators, + ] + : perEventConstantDiscriminators; + + const hiddenPrefixSkipResult = hasFromBytes + ? isCpiFramed + ? getCpiFramedSkip(allConstantDiscriminators) + : getHiddenPrefixSkip(node) + : null; + const generateFromBytes = hasFromBytes && hiddenPrefixSkipResult !== null; + const hiddenPrefixSkip = hiddenPrefixSkipResult ?? NO_SKIP; + const constantDiscriminators = generateFromBytes ? allConstantDiscriminators : []; + + const imports = new ImportMap() + .mergeWithManifest(typeManifest) + .mergeWith(discriminatorConstants.imports) + .remove(`generatedEvents::${pascalCase(node.name)}`); + if (framingConstantName) { + imports.add(`generatedEvents::${framingConstantName}`); + } + + return createRenderMap(`events/${snakeCase(node.name)}.rs`, { + content: render('eventsPage.njk', { + constantDiscriminators, + discriminatorConstants: discriminatorConstants.render, + event: node, + hiddenPrefixSkip, + imports: imports.toString(dependencyMap), + typeManifest, + }), + imports, + }); + }, + 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(); @@ -225,6 +371,18 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }); }); + // Extra arguments: required, non-serialized caller inputs (e.g. Anchor + // account-data seeds lowered to argumentValueNodes). They become builder + // fields read by PDA derivations but never enter InstructionData/Args. + const extraArgs = (node.extraArguments ?? []).map(argument => { + const manifest = visit(argument.type, typeManifestVisitor); + imports.mergeWith(manifest.imports); + const name = accountsAndArgsConflicts.includes(argument.name) + ? `${argument.name}_arg` + : argument.name; + return { name, type: manifest.type }; + }); + const struct = structTypeNodeFromInstructionArgumentNodes(node.arguments); const structVisitor = getTypeManifestVisitor({ getImportFrom, @@ -239,30 +397,169 @@ 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), + ); + // Extra args are always required builder inputs. + const hasRequiredArgs = + instructionArgs.some(arg => !arg.default && !arg.optional && !arg.innerOptionType) || + extraArgs.length > 0; + const requiredArgNames = [ + ...instructionArgs + .filter(arg => !arg.default && !arg.optional && !arg.innerOptionType) + .map(arg => snakeCase(arg.name)), + ...extraArgs.map(arg => snakeCase(arg.name)), + ]; + + // Resolve PDA defaults; builder `let` bindings follow the visitor's + // dependency-first order so derived PDAs can feed later derivations. + // Strip `isOptional` for the ordering visit: codama rejects optional + // accounts as seed sources, but the builder unwraps them at runtime. + const orderingNode = { ...node, accounts: node.accounts.map(a => ({ ...a, isOptional: false })) }; + const orderedAccountNames = visit(orderingNode, resolvedInstructionInputVisitor) + .filter(isNodeFilter('instructionAccountNode')) + .map(input => input.name as string); + const resolvedAccounts = resolveInstructionPdaDefaults({ + accountsAndArgsConflicts, + builderOptionalAccounts, + getImportFrom, + imports, + instruction: node, + linkables, + orderedAccountNames, + program, + requiredArgNames, + stack, + }); + const hasRequiredAccounts = node.accounts.some(a => !builderOptionalAccounts.has(a.name)); + return createRenderMap(`instructions/${snakeCase(node.name)}.rs`, { content: render('instructionsPage.njk', { + accountsAndArgsConflicts, + builderOptionalAccounts: [...builderOptionalAccounts], + cpiBuilderOptionalAccounts: [...cpiBuilderOptionalAccounts], dataTraits: dataTraits.render, discriminatorConstants: discriminatorConstants.render, + extraArgs, 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); + const seedBytes = renderConstantSeedBytes(seed, getImportFrom); + imports.mergeWith(seedBytes.imports); + return { ...seed, resolvedType, seedBytesExpr: seedBytes.render, 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; + + // Dynamic-only PDAs: helpers take the deriving program as a parameter, + // and _ADDRESS folds under the canonical program, not this program's ID. + const dynamicProgramOnly = getDynamicProgramOnlyPdas(program).has(node.name as string); + // Codama pins foreign programs (IDL address constraint) on + // pdaNode.programId; bake that address into the helpers. + const canonicalProgramAddress = + node.programId && node.programId !== program.publicKey ? node.programId : undefined; + + let precomputedAddress: string | undefined; + if (!hasVariableSeeds) { + const foldProgram = dynamicProgramOnly ? canonicalProgramAddress : programAddress; + if (foldProgram) { + precomputedAddress = computePdaAddress(node.seeds, foldProgram) ?? 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', { + canonicalProgramAddress, + constantSeeds, + dynamicProgramOnly, + hasVariableSeeds, + imports: imports.toString(dependencyMap), + pda: node, + precomputedAddress, + program, + programAddress, + seeds, + }), + imports, + }); + }, + visitProgram(node, { self }) { - program = node; + programEventFraming = deriveProgramEventFraming(node); let renders = mergeRenderMaps([ ...node.accounts.map(account => visit(account, self)), ...node.definedTypes.map(type => visit(type, self)), + ...(node.events ?? []).map(event => visit(event, self)), ...getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }).map(ix => visit(ix, self)), + ...node.pdas.map(pda => visit(pda, self)), ]); // Errors. @@ -277,7 +574,25 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { }); } - program = null; + // Program events (enum + identify + try_parse). + const programEventsRender = buildProgramEventsRender( + node.events ?? [], + node, + programEventFraming, + getImportFrom, + typeManifestVisitor, + dependencyMap, + ); + if (programEventsRender) { + programsWithEventEnum.add(node.name); + renders = addToRenderMap( + renders, + `events/${snakeCase(node.name)}_events.rs`, + programEventsRender, + ); + } + + programEventFraming = undefined; return renders; }, @@ -287,22 +602,32 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { const instructionsToExport = getAllInstructionsWithSubs(node, { leavesOnly: !renderParentInstructions, }); + const pdasToExport = getAllPdas(node); const definedTypesToExport = getAllDefinedTypes(node); + const eventsToExport = getAllEvents(node).filter(Boolean); const hasAnythingToExport = programsToExport.length > 0 || accountsToExport.length > 0 || instructionsToExport.length > 0 || - definedTypesToExport.length > 0; + pdasToExport.length > 0 || + definedTypesToExport.length > 0 || + eventsToExport.length > 0; const ctx = { accountsToExport, definedTypesToExport, + eventsToExport, hasAnythingToExport, instructionsToExport, + pdasToExport, programsToExport, + programsWithEventEnum, root: node, }; + // Visit programs first so programsWithEventEnum is populated. + const programRenders = getAllPrograms(node).map(p => visit(p, self)); + return mergeRenderMaps([ createRenderMap({ ['accounts/mod.rs']: @@ -313,11 +638,19 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { programsToExport.length > 0 ? { content: render('errorsMod.njk', ctx), imports: new ImportMap() } : undefined, + ['events/mod.rs']: + eventsToExport.length > 0 + ? { content: render('eventsMod.njk', ctx), imports: new ImportMap() } + : undefined, ['instructions/mod.rs']: instructionsToExport.length > 0 ? { 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() } @@ -331,7 +664,7 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { ? { content: render('definedTypesMod.njk', ctx), imports: new ImportMap() } : undefined, }), - ...getAllPrograms(node).map(p => visit(p, self)), + ...programRenders, ]); }, }), @@ -340,11 +673,677 @@ export function getRenderMapVisitor(options: GetRenderMapOptions = {}) { ); } +function eventHasFromBytes(event: EventNode): boolean { + const hasConstantDiscriminator = (event.discriminators ?? []).some(d => isNode(d, 'constantDiscriminatorNode')); + const dataHasHiddenPrefix = isNode(event.data, 'hiddenPrefixTypeNode'); + return hasConstantDiscriminator && dataHasHiddenPrefix; +} + +/** A rendered `&data[..]` skip expression; `comment` lists the constants folded into a literal offset. */ +type SkipExpr = { comment: string | null; expr: string }; + +const NO_SKIP: SkipExpr = { comment: null, expr: 'data' }; + +function getHiddenPrefixSkip(event: EventNode): SkipExpr | null { + if (!isNode(event.data, 'hiddenPrefixTypeNode')) { + return NO_SKIP; + } + let hasNonFixedSize = false; + const prefixSize = event.data.prefix.reduce((sum, p) => { + if (!isNode(p.type, 'fixedSizeTypeNode')) { + logWarn( + `[Rust] Event [${event.name}] has a non-fixed-size hidden prefix entry; ` + + `from_bytes will not be generated.`, + ); + hasNonFixedSize = true; + return sum; + } + return sum + p.type.size; + }, 0); + if (hasNonFixedSize) { + return null; + } + // Literal byte count: keeps arithmetic out of generated code (clippy::arithmetic_side_effects). + return { comment: null, expr: `&data[${prefixSize}..]` }; +} + +/** Resolved program-level framing: the hoisted prefix constant + its source EventFraming. */ +type ResolvedProgramEventFraming = { constant: ConstantValueNode; framing: EventFraming }; + +function deriveProgramEventFraming(programNode: ProgramNode | null): ResolvedProgramEventFraming | undefined { + if (!programNode) return undefined; + let resolved: ResolvedProgramEventFraming | undefined; + for (const event of programNode.events ?? []) { + if (!event.framing) continue; + if (!isNode(event.data, 'hiddenPrefixTypeNode')) continue; + if (event.data.prefix.length === 0) continue; + if (!resolved) { + resolved = { constant: event.data.prefix[0], framing: event.framing }; + continue; + } + if (resolved.framing.sharedConstantName !== event.framing.sharedConstantName) { + logWarn( + `[Rust] Program [${programNode.name}] has events with conflicting event framings ` + + `('${resolved.framing.sharedConstantName}' vs '${event.framing.sharedConstantName}'). ` + + `Only the first will be hoisted.`, + ); + break; + } + } + return resolved; +} + +function isEventCpiFramed(event: EventNode, programEventFraming: ResolvedProgramEventFraming | undefined): boolean { + if (programEventFraming === undefined) return false; + if (!event.framing) return false; + if (event.framing.sharedConstantName !== programEventFraming.framing.sharedConstantName) return false; + if (!isNode(event.data, 'hiddenPrefixTypeNode')) return false; + return event.data.prefix.length > 0; +} + +function getCpiFramedSkip(constantDiscriminators: { name: string; offset: number; size: number | null }[]): SkipExpr { + // Fold known sizes into one leading literal range and chain `[X.len()..]` for the rest, + // so generated code never emits `+` (clippy::arithmetic_side_effects). + const knownSize = constantDiscriminators.reduce((sum, d) => sum + (d.size ?? 0), 0); + const ranges = constantDiscriminators.filter(d => d.size === null).map(d => `[${d.name}.len()..]`); + if (knownSize > 0 || ranges.length === 0) { + ranges.unshift(`[${knownSize}..]`); + } + const comment = + constantDiscriminators.length > 1 + ? constantDiscriminators.map(d => (d.size === null ? d.name : `${d.name} (${d.size})`)).join(' + ') + : null; + return { comment, expr: `&data${ranges.join('')}` }; +} + +/** Renders a fixed-size bytes ConstantValueNode as a Rust `[u8; N] = [b0, b1, ...]` array literal. */ +function renderConstantBytesArray(constant: ConstantValueNode): { len: number; literal: string } | null { + if (!isNode(constant.type, 'fixedSizeTypeNode')) return null; + if (!isNode(constant.value, 'bytesValueNode')) return null; + const size = constant.type.size; + const bytes: number[] = []; + const hex = constant.value.encoding === 'base16' ? constant.value.data.toLowerCase() : null; + if (hex === null || hex.length !== size * 2) return null; + for (let i = 0; i < size; i++) { + const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16); + if (Number.isNaN(byte)) return null; + bytes.push(byte); + } + return { len: size, literal: `[${bytes.join(', ')}]` }; +} + +function buildProgramEventsRender( + events: EventNode[], + programNode: ProgramNode, + programEventFraming: ResolvedProgramEventFraming | undefined, + getImportFrom: GetImportFromFunction, + typeManifestVisitor: ReturnType, + dependencyMap: Record, +): { content: string; imports: ImportMap } | null { + if (events.length === 0) { + return null; + } + + const imports = new ImportMap(); + const framingConstantName = programEventFraming + ? snakeCase(programEventFraming.framing.sharedConstantName).toUpperCase() + : null; + + const eventsWithDiscriminators = events + .filter(event => (event.discriminators ?? []).length > 0) + .flatMap(event => { + const isCpiFramed = isEventCpiFramed(event, programEventFraming); + const allDiscriminators = event.discriminators ?? []; + // For CPI-framed events, strip the leading framing discriminator — it's hoisted to the + // program-level shared constant and prepended manually below. + const perEventDiscriminators = isCpiFramed ? allDiscriminators.slice(1) : allDiscriminators; + const innerType = resolveNestedTypeNode(event.data); + const fields = isNode(innerType, 'structTypeNode') ? innerType.fields : []; + const { conditions: perEventConditions, imports: condImports } = getDiscriminatorConditions({ + discriminatorNodes: perEventDiscriminators, + fields, + getImportFrom, + importPrefix: 'generatedEvents', + prefix: event.name, + typeManifestVisitor, + }); + const perEventConstantDiscs = perEventDiscriminators + .filter(isNodeFilter('constantDiscriminatorNode')) + .map(d => ({ + name: snakeCase(constantDiscriminatorName(event.name, d, perEventDiscriminators)).toUpperCase(), + offset: d.offset, + size: constantDiscriminatorSize(d), + })); + + let conditions: string[]; + let hiddenPrefixSkipResult: SkipExpr | null; + if (isCpiFramed && framingConstantName) { + conditions = [ + renderByteCheck(framingConstantName, programEventFraming!.constant.type, 0), + ...perEventConditions, + ]; + const allConstantDiscs = [ + { + name: framingConstantName, + offset: 0, + size: renderConstantBytesArray(programEventFraming!.constant)?.len ?? null, + }, + ...perEventConstantDiscs, + ]; + hiddenPrefixSkipResult = getCpiFramedSkip(allConstantDiscs); + } else { + conditions = perEventConditions; + hiddenPrefixSkipResult = isNode(event.data, 'hiddenPrefixTypeNode') + ? getHiddenPrefixSkip(event) + : NO_SKIP; + } + + if (hiddenPrefixSkipResult === null || conditions.length === 0) { + return []; + } + + imports.mergeWith(condImports); + return [{ ...event, conditions, hiddenPrefixSkip: hiddenPrefixSkipResult }]; + }); + + if (eventsWithDiscriminators.length === 0) { + return null; + } + + imports.add('borsh::BorshDeserialize'); + eventsWithDiscriminators.forEach(event => { + imports.add(`generatedEvents::${pascalCase(event.name)}`); + }); + + const anyCpiFramed = eventsWithDiscriminators.some(event => isEventCpiFramed(event, programEventFraming)); + const eventFramingBytes = + anyCpiFramed && programEventFraming !== undefined + ? renderConstantBytesArray(programEventFraming.constant) + : null; + + return { + content: render('programEventsPage.njk', { + eventFramingBytes, + eventFramingName: anyCpiFramed ? framingConstantName : null, + eventsWithDiscriminators, + imports: imports.toString(dependencyMap), + program: programNode, + }), + imports, + }; +} + +/** + * Linked PDAs whose every use-site passes a dynamic programId. Their helpers + * take the deriving program as a parameter (unless pinned to a foreign address). + */ +function getDynamicProgramOnlyPdas(program: ProgramNode): Set { + const allUsagesDynamic = new Map(); + for (const instruction of getAllInstructionsWithSubs(program, { leavesOnly: false })) { + for (const account of instruction.accounts) { + const defaultValue = account.defaultValue; + if (!defaultValue || !isNode(defaultValue, 'pdaValueNode')) continue; + if (!isNode(defaultValue.pda, 'pdaLinkNode')) continue; + const name = defaultValue.pda.name as string; + allUsagesDynamic.set(name, (allUsagesDynamic.get(name) ?? true) && defaultValue.programId != null); + } + } + return new Set([...allUsagesDynamic.entries()].filter(([, allDynamic]) => allDynamic).map(([name]) => name)); +} + +/** + * Renders a constant PDA seed as a raw byte-slice expression suitable for + * `find_program_address(&[...])`: `b"…"` for strings, `&[…]` for bytes, and + * `&N.to_le_bytes()`-style for typed values. Shared by the PDA-helper pages + * and the inline instruction-builder derivations. + */ +function renderConstantSeedBytes( + seed: ConstantPdaSeedNode, + getImportFrom: GetImportFromFunction, +): { imports: ImportMap; render: string } { + if (isNode(seed.value, 'programIdValueNode')) { + // The program reference is context-dependent; callers render it themselves. + throw new Error('programIdValueNode seeds must be rendered by the caller.'); + } + if (isNode(seed.value, 'stringValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + return { imports: m.imports, render: `b${m.render}` }; + } + if (isNode(seed.value, 'bytesValueNode')) { + const m = renderValueNode(seed.value, getImportFrom, true); + return { imports: m.imports, render: `&${m.render}` }; + } + if (isNode(seed.value, 'publicKeyValueNode')) { + // Codama folds address-pinned program accounts used as seeds into + // constant publicKey seeds; emit the decoded 32 bytes. + const bytes = getBase58Encoder().encode(seed.value.publicKey); + return { imports: new ImportMap(), render: `&[${Array.from(bytes).join(', ')}]` }; + } + const m = renderValueNode(constantValueNode(seed.type, seed.value), getImportFrom, true); + return { imports: m.imports, render: `&${m.render}` }; +} + function getConflictsForInstructionAccountsAndArgs(instruction: InstructionNode): string[] { const allNames = [ ...instruction.accounts.map(account => account.name), - ...instruction.arguments.map(argument => argument.name), + ...getAllInstructionArguments(instruction).map(argument => argument.name), ]; 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 = { + /** + * True when the helper call needs a runtime program argument, i.e. the + * deriving program is dynamic and not address-pinned (pinned ones are baked in). + */ + hasDynamicProgram: boolean; + hasVariableSeeds: boolean; + isLinked: boolean; + linkedPdaName?: string; + programAddressExpr: string; + renderedSeeds: RenderedSeed[]; +}; + +type ResolvedAccount = InstructionAccountNode & { + pdaDefault: ResolvedPdaDefault | null; +}; + +function resolveInstructionPdaDefaults(ctx: { + accountsAndArgsConflicts: string[]; + builderOptionalAccounts: Set; + getImportFrom: GetImportFromFunction; + imports: ImportMap; + instruction: InstructionNode; + linkables: LinkableDictionary; + orderedAccountNames: string[]; + program: ProgramNode; + requiredArgNames: string[]; + stack: NodeStack; +}): ResolvedAccount[] { + const { + accountsAndArgsConflicts, + builderOptionalAccounts, + getImportFrom, + imports, + instruction, + linkables, + orderedAccountNames, + program, + requiredArgNames, + stack, + } = ctx; + + const accounts = instruction.accounts; + // Includes extraArguments — Anchor lowers account-data seeds (e.g. `guard.mint`) + // to caller-supplied extra arguments. + const instructionArguments = getAllInstructionArguments(instruction); + const instructionName = instruction.name; + const localProgramIdExpr = `crate::${snakeCase(program.name).toUpperCase()}_ID`; + // PDAs whose helpers require the deriving program as a parameter. + const dynamicOnlyPdas = getDynamicProgramOnlyPdas(program); + + // 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), + ); + + // Nested argument paths (e.g. `guard.mint`) have no builder field to read from. + const assertNoArgumentPath = (ref: { name: string; path?: readonly string[] }, accountName: string) => { + if (ref.path && ref.path.length > 0) { + throw new Error( + `[Rust] Account [${accountName}] of instruction [${instructionName}] references nested ` + + `argument path [${ref.name}.${ref.path.join('.')}], which the Rust renderer does not support.`, + ); + } + }; + + // Renders the builder expression for the account/argument reference used as a + // PDA's dynamic deriving program. + const renderProgramRefExpr = (ref: NonNullable, accountName: string): string => { + if (isNode(ref, 'accountValueNode')) { + const refName = snakeCase(ref.name); + if (pdaDefaultedNames.has(ref.name)) { + // Previously derived in the builder; visitor ordering guarantees it. + return refName; + } + const refAccount = accounts.find(a => a.name === ref.name); + const isEither = refAccount?.isSigner === 'either'; + const isOptional = builderOptionalAccounts.has(ref.name); + const eitherExtract = isEither ? (isOptional ? '.map(|(k, _)| k)' : '.0') : ''; + if (!isOptional) { + return `self.${refName}${eitherExtract}`; + } + if (refAccount?.defaultValue && isNode(refAccount.defaultValue, 'publicKeyValueNode')) { + return `self.${refName}${eitherExtract}.unwrap_or(solana_address::address!("${refAccount.defaultValue.publicKey}"))`; + } + if (refAccount?.defaultValue && isNode(refAccount.defaultValue, 'programIdValueNode')) { + return `self.${refName}${eitherExtract}.unwrap_or(${localProgramIdExpr})`; + } + return `self.${refName}${eitherExtract}.expect("${refName} is needed for ${snakeCase(accountName)} PDA")`; + } + assertNoArgumentPath(ref, accountName); + const argFieldName = accountsAndArgsConflicts.includes(ref.name) ? `${ref.name}_arg` : ref.name; + const fieldName = snakeCase(argFieldName); + if (requiredArgNames.includes(fieldName)) { + return `self.${fieldName}`; + } + return `self.${fieldName}.clone().expect("${fieldName} is needed for ${snakeCase(accountName)} PDA")`; + }; + + 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; + } + + // Dynamic programId: render as linked only when the PDA's helper takes a + // program parameter (dynamic-only); mixed-use PDAs fall back to inline. + const dynamicProgramRef = defaultValue.programId; + const renderAsLinked = + isLinked && (!dynamicProgramRef || (linkedPdaName !== undefined && dynamicOnlyPdas.has(linkedPdaName))); + + // Program priority mirrors codama resolve-pda-address.ts: + // dynamic runtime ref > pdaNode constant > local program ID. + let programAddressExpr: string; + if (dynamicProgramRef) { + programAddressExpr = renderProgramRefExpr(dynamicProgramRef, account.name); + } else if (pdaNode?.programId) { + programAddressExpr = `solana_address::address!("${pdaNode.programId}")`; + } else { + programAddressExpr = localProgramIdExpr; + } + + // 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] = localProgramIdExpr; + } + if (refAccount?.isSigner === 'either') { + eitherSignerAccounts.add(refName); + } + } + } + + const renderedSeeds: RenderedSeed[] = []; + + // 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 find_*_pda() with typed args (and the program + // when the helper takes one). + // Inline (pdaNode): emit find_program_address() with raw byte-slice seeds. + if (renderAsLinked) { + 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)) { + 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')) { + assertNoArgumentPath(seedValue, account.name); + 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); + if (!arg) { + // The native visitor validates seed dependencies upfront, so this is + // unreachable for well-formed IDLs. + throw new Error( + `[Rust] Seed argument [${seedValue.name}] for account [${account.name}] in ` + + `instruction [${instructionName}] does not match any instruction argument.`, + ); + } + 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 { + if (!pdaNode) { + throw new Error( + `[Rust] Could not resolve PDA node for account [${account.name}] ` + + `in instruction [${instructionName}].`, + ); + } + for (const seed of pdaNode.seeds) { + if (isNode(seed, 'constantPdaSeedNode')) { + if (isNode(seed.value, 'programIdValueNode')) { + // The deriving program doubles as a seed; honor the runtime ref. + const programSeedExpr = dynamicProgramRef ? programAddressExpr : localProgramIdExpr; + renderedSeeds.push({ + kind: 'programId', + render: `${programSeedExpr}.as_ref()`, + }); + } else { + const seedBytes = renderConstantSeedBytes(seed, getImportFrom); + imports.mergeWith(seedBytes.imports); + renderedSeeds.push({ kind: 'constant', render: seedBytes.render }); + } + continue; + } + + if (!isNode(seed, 'variablePdaSeedNode')) continue; + + const binding = defaultValue.seeds.find(s => s.name === seed.name); + if (!binding) { + throw new Error( + `[Rust] Missing seed value for variable seed [${seed.name}] in PDA default ` + + `for account [${account.name}] of instruction [${instructionName}].`, + ); + } + + 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]; + + 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')) { + assertNoArgumentPath(seedValue, account.name); + 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); + if (!arg) { + // The native visitor validates seed dependencies upfront, so this is + // unreachable for well-formed IDLs. + throw new Error( + `[Rust] Seed argument [${seedValue.name}] for account [${account.name}] in ` + + `instruction [${instructionName}] does not match any instruction argument.`, + ); + } + 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()` }); + } + } + } + } + + const pdaHasVariableSeeds = pdaNode ? pdaNode.seeds.some(s => isNode(s, 'variablePdaSeedNode')) : true; + + // Pinned programs (pdaNode.programId) are baked into the generated + // helpers and _ADDRESS constant, so the builder passes no program arg. + const pinnedProgram = + renderAsLinked && pdaNode?.programId && pdaNode.programId !== program.publicKey + ? pdaNode.programId + : undefined; + + resolvedPdas[account.name] = { + hasDynamicProgram: !!dynamicProgramRef && !pinnedProgram, + hasVariableSeeds: pdaHasVariableSeeds, + isLinked: renderAsLinked, + linkedPdaName, + programAddressExpr, + renderedSeeds, + }; + } + + // Inputs are already validated and dependency-ordered; emit builder `let` + // bindings in that order so derived PDAs can feed later derivations. + const accountsByName = new Map(accounts.map(a => [a.name as string, a])); + return orderedAccountNames.map(name => { + const account = accountsByName.get(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/cargoToml.ts b/src/utils/cargoToml.ts index 0c83a48..82653a8 100644 --- a/src/utils/cargoToml.ts +++ b/src/utils/cargoToml.ts @@ -246,8 +246,9 @@ function getUsedImportNames(renderMap: RenderMap, dependencyMap: Recor // and capturing only the crate name (first segment). For instance, // "some_crate::some_module::SomeType" or "::some_crate::SomeType". const PATH_REGEX = /\b(?:::)?([a-z_][a-z0-9_]*)(?:::[a-zA-Z0-9_]+)+/g; + const LINE_COMMENT_REGEX = /\/\/[^\n]*/g; const fromContent = fragments.flatMap(({ content }) => { - return [...content.matchAll(PATH_REGEX)] + return [...content.replace(LINE_COMMENT_REGEX, '').matchAll(PATH_REGEX)] .map(match => match[1]) .filter(crateName => !RUST_CORE_IMPORTS.has(crateName)); }); 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..8164a68 100644 --- a/src/utils/discriminatorConstant.ts +++ b/src/utils/discriminatorConstant.ts @@ -6,8 +6,11 @@ import { InstructionArgumentNode, isNode, isNodeFilter, + NumberTypeNode, + SizeDiscriminatorNode, snakeCase, StructFieldTypeNode, + TypeNode, VALUE_NODES, } from '@codama/nodes'; import { visit } from '@codama/visitors-core'; @@ -25,6 +28,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[]; @@ -70,10 +101,7 @@ function getConstantDiscriminatorConstant( ): Fragment { const { discriminatorNodes, getImportFrom, prefix, typeManifestVisitor } = scope; - const index = discriminatorNodes.filter(isNodeFilter('constantDiscriminatorNode')).indexOf(discriminatorNode); - const suffix = index <= 0 ? '' : `_${index + 1}`; - - const name = camelCase(`${prefix}_discriminator${suffix}`); + const name = constantDiscriminatorName(prefix, discriminatorNode, discriminatorNodes); const typeManifest = visit(discriminatorNode.constant.type, typeManifestVisitor); const value = renderValueNode(discriminatorNode.constant.value, getImportFrom); return getConstant(name, typeManifest, value); @@ -95,13 +123,181 @@ function getFieldDiscriminatorConstant( return null; } - const name = camelCase(`${prefix}_${discriminatorNode.name}`); const typeManifest = visit(field.type, typeManifestVisitor); const value = renderValueNode(field.defaultValue, getImportFrom); - return getConstant(name, typeManifest, value); + return getConstant(fieldDiscriminatorName(prefix, discriminatorNode.name), typeManifest, value); } function getConstant(name: string, typeManifest: TypeManifest, value: Fragment): Fragment { const type: Fragment = { imports: typeManifest.imports, render: typeManifest.type }; return mergeFragments([type, value], ([t, v]) => `pub const ${snakeCase(name).toUpperCase()}: ${t} = ${v};`); } + +export function constantDiscriminatorName( + prefix: string, + discriminatorNode: ConstantDiscriminatorNode, + discriminatorNodes: DiscriminatorNode[], +): string { + const index = discriminatorNodes.filter(isNodeFilter('constantDiscriminatorNode')).indexOf(discriminatorNode); + const suffix = index <= 0 ? '' : `_${index + 1}`; + return camelCase(`${prefix}_discriminator${suffix}`); +} + +function fieldDiscriminatorName(prefix: string, fieldName: string): string { + return camelCase(`${prefix}_${fieldName}`); +} + +export function getDiscriminatorConditions(scope: { + discriminatorNodes: DiscriminatorNode[]; + fields: InstructionArgumentNode[] | StructFieldTypeNode[]; + getImportFrom: GetImportFromFunction; + importPrefix: string; + prefix: string; + typeManifestVisitor: ReturnType; +}): { conditions: string[]; imports: ImportMap } { + const imports = new ImportMap(); + const conditions = scope.discriminatorNodes + .map(node => getDiscriminatorCondition(node, scope, imports)) + .filter(Boolean) as string[]; + return { conditions, imports }; +} + +function getDiscriminatorCondition( + discriminatorNode: DiscriminatorNode, + scope: { + discriminatorNodes: DiscriminatorNode[]; + fields: InstructionArgumentNode[] | StructFieldTypeNode[]; + getImportFrom: GetImportFromFunction; + importPrefix: string; + prefix: string; + typeManifestVisitor: ReturnType; + }, + imports: ImportMap, +): string | null { + switch (discriminatorNode.kind) { + case 'sizeDiscriminatorNode': + return getSizeCondition(discriminatorNode); + case 'constantDiscriminatorNode': + return getConstantCondition(discriminatorNode, scope, imports); + case 'fieldDiscriminatorNode': + return getFieldCondition(discriminatorNode, scope, imports); + default: + return null; + } +} + +function getSizeCondition(discriminatorNode: SizeDiscriminatorNode): string { + return `data.len() == ${discriminatorNode.size}`; +} + +function getConstantCondition( + discriminatorNode: ConstantDiscriminatorNode, + scope: { + discriminatorNodes: DiscriminatorNode[]; + importPrefix: string; + prefix: string; + }, + imports: ImportMap, +): string { + const { discriminatorNodes, importPrefix, prefix } = scope; + const constName = snakeCase(constantDiscriminatorName(prefix, discriminatorNode, discriminatorNodes)).toUpperCase(); + imports.add(`${importPrefix}::${constName}`); + + return renderByteCheck(constName, discriminatorNode.constant.type, discriminatorNode.offset); +} + +/** + * Renders a `data` vs discriminator constant check; `negate` inverts it for guards. Scalar number + * consts compare via `to_le/be_bytes`; ranges are precomputed literals (clippy::arithmetic_side_effects). + */ +export function renderByteCheck(name: string, type: TypeNode, offset: number, negate = false): string { + const eq = negate ? '!=' : '=='; + if (isNode(type, 'numberTypeNode')) { + const byteSize = getNumberByteSize(type.format); + const range = offset === 0 ? `..${byteSize}` : `${offset}..${offset + byteSize}`; + return `data.get(${range}) ${eq} Some(&${name}.${numberBytesFn(type)}())`; + } + if (offset === 0) { + return `data.get(..${name}.len()) ${eq} Some(&${name}[..])`; + } + const size = staticByteSize(type); + if (size !== null) { + return `data.get(${offset}..${offset + size}) ${eq} Some(&${name}[..])`; + } + return `${negate ? '!' : ''}data.get(${offset}..).is_some_and(|tail| tail.starts_with(&${name}[..]))`; +} + +/** Byte size of a constant discriminator, when statically known. */ +export function constantDiscriminatorSize(discriminatorNode: ConstantDiscriminatorNode): number | null { + const type = discriminatorNode.constant.type; + if (isNode(type, 'numberTypeNode')) { + return NUMBER_BYTE_SIZES[type.format] ?? null; + } + return staticByteSize(type); +} + +function numberBytesFn(type: NumberTypeNode): string { + return type.endian === 'be' ? 'to_be_bytes' : 'to_le_bytes'; +} + +/** + * Statically known byte size of a type rendered as `[u8; N]`. u8 arrays only: + * other element types wouldn't compile against `&[u8]` data anyway. + */ +function staticByteSize(type: TypeNode): number | null { + if (isNode(type, 'fixedSizeTypeNode')) { + return type.size; + } + if ( + isNode(type, 'arrayTypeNode') && + isNode(type.item, 'numberTypeNode') && + type.item.format === 'u8' && + isNode(type.count, 'fixedCountNode') + ) { + return type.count.value; + } + return null; +} + +function getFieldCondition( + discriminatorNode: FieldDiscriminatorNode, + scope: { + fields: InstructionArgumentNode[] | StructFieldTypeNode[]; + importPrefix: string; + prefix: string; + }, + imports: ImportMap, +): string | null { + const { fields, importPrefix, prefix } = scope; + const field = fields.find(f => f.name === discriminatorNode.name); + if (!field || !field.defaultValue || !isNode(field.defaultValue, VALUE_NODES)) { + return null; + } + + const constName = snakeCase(fieldDiscriminatorName(prefix, discriminatorNode.name)).toUpperCase(); + imports.add(`${importPrefix}::${constName}`); + return renderByteCheck(constName, field.type, discriminatorNode.offset); +} + +const NUMBER_BYTE_SIZES: Record = { + f32: 4, + f64: 8, + i128: 16, + i16: 2, + i32: 4, + i64: 8, + i8: 1, + u128: 16, + u16: 2, + u32: 4, + u64: 8, + u8: 1, +}; + +function getNumberByteSize(format: string): number { + const size = NUMBER_BYTE_SIZES[format]; + if (size === undefined) { + throw new Error(`Unknown number format: ${format}`); + } + return size; +} 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/eventsPage.test.ts b/test/eventsPage.test.ts new file mode 100644 index 0000000..a41289c --- /dev/null +++ b/test/eventsPage.test.ts @@ -0,0 +1,1405 @@ +import { + arrayTypeNode, + arrayValueNode, + bytesTypeNode, + bytesValueNode, + CamelCaseString, + constantDiscriminatorNode, + constantValueNode, + definedTypeLinkNode, + definedTypeNode, + eventNode, + fieldDiscriminatorNode, + fixedCountNode, + fixedSizeTypeNode, + hiddenPrefixTypeNode, + numberTypeNode, + numberValueNode, + programNode, + rootNode, + sizeDiscriminatorNode, + structFieldTypeNode, + structTypeNode, +} from '@codama/nodes'; +import { getFromRenderMap } from '@codama/renderers-core'; +import { visit } from '@codama/visitors-core'; +import { expect, test, vi } from 'vitest'; + +import { getRenderMapVisitor } from '../src'; +import { codeContains, codeDoesNotContains } from './_setup'; + +test('it renders an event with discriminator as a struct with from_bytes', () => { + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([ + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + structFieldTypeNode({ name: 'price', type: numberTypeNode('u64') }), + ]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'bddB7fd34ee661ee'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'bddB7fd34ee661ee'), + ), + ), + ], + name: 'tradeEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + + codeContains(getFromRenderMap(renderMap, 'events/trade_event.rs').content, [ + '#[derive(', + 'BorshSerialize', + 'BorshDeserialize', + 'pub struct TradeEvent', + 'pub amount: u64,', + 'pub price: u64,', + 'TRADE_EVENT_DISCRIMINATOR', + 'pub fn from_bytes', + '"invalid event discriminator"', + 'Self::deserialize(&mut data)', + ]); +}); + +test('it renders an event without discriminator as a plain struct', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') })]), + name: 'simpleEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + codeContains(getFromRenderMap(renderMap, 'events/simple_event.rs').content, [ + 'pub struct SimpleEvent', + 'pub value: u32,', + ]); + codeDoesNotContains(getFromRenderMap(renderMap, 'events/simple_event.rs').content, ['DISCRIMINATOR', 'from_bytes']); +}); + +test('it does not render events module for programs without events', () => { + const node = rootNode( + programNode({ + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }), + ); + + const renderMap = visit(node, getRenderMapVisitor()); + + codeDoesNotContains(getFromRenderMap(renderMap, 'mod.rs').content, 'pub mod events;'); +}); + +test('it renders events in the events module', () => { + const node = rootNode( + programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + name: 'transferEvent', + }), + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'delegate', type: numberTypeNode('u64') })]), + name: 'approveEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }), + ); + + const renderMap = visit(node, getRenderMapVisitor()); + codeContains(getFromRenderMap(renderMap, 'events/mod.rs').content, [ + 'pub(crate) mod r#approve_event;', + 'pub use self::r#approve_event::*;', + 'pub(crate) mod r#transfer_event;', + 'pub use self::r#transfer_event::*;', + ]); + + codeContains(getFromRenderMap(renderMap, 'mod.rs').content, 'pub mod events;'); +}); + +test('it renders an event with an empty struct', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([]), + name: 'emptyEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + codeContains(getFromRenderMap(renderMap, 'events/empty_event.rs').content, ['pub struct EmptyEvent']); + codeDoesNotContains(getFromRenderMap(renderMap, 'events/empty_event.rs').content, ['from_bytes', 'DISCRIMINATOR']); +}); + +test('it renders event docs', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') })]), + docs: ['Some documentation.', 'Second line.'], + name: 'documentedEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + codeContains(getFromRenderMap(renderMap, 'events/documented_event.rs').content, [ + '/// Some documentation.', + '/// Second line.', + 'pub struct DocumentedEvent', + ]); +}); + +test('it renders an event with a nested struct field', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') }), + structFieldTypeNode({ + name: 'metadata', + type: structTypeNode([ + structFieldTypeNode({ name: 'label', type: numberTypeNode('u8') }), + structFieldTypeNode({ name: 'version', type: numberTypeNode('u16') }), + ]), + }), + ]), + name: 'complexEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + codeContains(getFromRenderMap(renderMap, 'events/complex_event.rs').content, [ + 'pub struct ComplexEvent', + 'pub amount: u64,', + 'pub metadata: ComplexEventMetadata,', + 'pub struct ComplexEventMetadata', + 'pub label: u8,', + 'pub version: u16,', + ]); +}); + +test('it renders field discriminator constants and skips from_bytes without hidden prefix', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: numberValueNode(7), + name: 'eventType', + type: numberTypeNode('u8'), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [ + fieldDiscriminatorNode('eventType'), + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ), + ], + name: 'mixedEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/mixed_event.rs').content; + + codeContains(code, ['MIXED_EVENT_EVENT_TYPE: u8 = 7']); + codeContains(code, ['MIXED_EVENT_DISCRIMINATOR']); + codeDoesNotContains(code, ['from_bytes']); +}); + +test('it validates all constant discriminators in from_bytes for multi-disc events', () => { + const disc1 = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + const disc2 = constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 4), bytesValueNode('base16', 'eeff0011')); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [disc1], + ), + discriminators: [constantDiscriminatorNode(disc1, 0), constantDiscriminatorNode(disc2, 12)], + name: 'multiDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/multi_disc_event.rs').content; + + codeContains(code, [ + 'pub fn from_bytes', + 'MULTI_DISC_EVENT_DISCRIMINATOR.len()) != Some(&MULTI_DISC_EVENT_DISCRIMINATOR[..])', + 'data.get(12..16) != Some(&MULTI_DISC_EVENT_DISCRIMINATOR2[..])', + 'Self::deserialize(&mut data)', + ]); +}); + +test('it uses a literal range in from_bytes for u8-array constant discriminators at non-zero offset', () => { + const prefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + // u8-array constant: no fixedSizeTypeNode, but the fixed count gives a static size of 3. + const arrayDisc = constantValueNode( + arrayTypeNode(numberTypeNode('u8'), fixedCountNode(3)), + arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + ); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [prefix], + ), + discriminators: [constantDiscriminatorNode(prefix, 0), constantDiscriminatorNode(arrayDisc, 8)], + name: 'tailEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/tail_event.rs').content; + + codeContains(code, [ + 'pub const TAIL_EVENT_DISCRIMINATOR2: [u8; 3] = [1, 2, 3];', + 'if data.get(8..11) != Some(&TAIL_EVENT_DISCRIMINATOR2[..])', + 'let mut data = &data[8..];', + ]); +}); + +test('it falls back to starts_with in from_bytes when a non-zero-offset discriminator size is unknown', () => { + const prefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + // Link-typed constant: byte size not resolvable at the discriminator site. + const linkDisc = constantValueNode( + definedTypeLinkNode('discAlias'), + arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + ); + const node = programNode({ + definedTypes: [definedTypeNode({ name: 'discAlias', type: fixedSizeTypeNode(bytesTypeNode(), 3) })], + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [prefix], + ), + discriminators: [constantDiscriminatorNode(prefix, 0), constantDiscriminatorNode(linkDisc, 8)], + name: 'tailEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/tail_event.rs').content; + + codeContains(code, [ + 'pub const TAIL_EVENT_DISCRIMINATOR2: DiscAlias = [1, 2, 3];', + 'if !data.get(8..).is_some_and(|tail| tail.starts_with(&TAIL_EVENT_DISCRIMINATOR2[..]))', + 'let mut data = &data[8..];', + ]); +}); + +test('it compares number constant discriminators via to_le_bytes in from_bytes', () => { + // Number constants render as scalar Rust constants (`pub const X: u32`), + // so from_bytes must compare their byte encoding, not slice the constant. + const numDisc = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); + const node = programNode({ + events: [ + // Number discriminator at offset 0. + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 4), bytesValueNode('base16', '2a000000'))], + ), + discriminators: [constantDiscriminatorNode(numDisc, 0)], + name: 'numHeadEvent', + }), + // Number discriminator at non-zero offset. + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + 0, + ), + constantDiscriminatorNode(numDisc, 8), + ], + name: 'numTailEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + + const headCode = getFromRenderMap(renderMap, 'events/num_head_event.rs').content; + codeContains(headCode, [ + 'pub const NUM_HEAD_EVENT_DISCRIMINATOR: u32 = 42;', + 'if data.get(..4) != Some(&NUM_HEAD_EVENT_DISCRIMINATOR.to_le_bytes())', + 'let mut data = &data[4..];', + ]); + + const tailCode = getFromRenderMap(renderMap, 'events/num_tail_event.rs').content; + codeContains(tailCode, [ + 'pub const NUM_TAIL_EVENT_DISCRIMINATOR2: u32 = 42;', + 'if data.get(8..12) != Some(&NUM_TAIL_EVENT_DISCRIMINATOR2.to_le_bytes())', + 'let mut data = &data[8..];', + ]); +}); + +test('it uses literal byte count in from_bytes for multi-prefix hidden prefix', () => { + const prefix1 = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + const prefix2 = constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 4), bytesValueNode('base16', 'eeff0011')); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [prefix1, prefix2], + ), + discriminators: [constantDiscriminatorNode(prefix1, 0)], + name: 'multiPrefixEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/multi_prefix_event.rs').content; + + codeContains(code, ['let mut data = &data[12..];']); + codeDoesNotContains(code, ['.len()..']); +}); + +test('it uses literal byte count in from_bytes when constant disc is not at offset 0', () => { + const prefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [prefix], + ), + discriminators: [constantDiscriminatorNode(prefix, 8)], + name: 'offsetPrefixEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/offset_prefix_event.rs').content; + + codeContains(code, ['let mut data = &data[8..];']); + codeDoesNotContains(code, ['.len()..']); +}); + +test('it does not render from_bytes when hidden prefix has a non-fixed-size entry', () => { + const prefix1 = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + const prefix2 = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [prefix1, prefix2], + ), + discriminators: [constantDiscriminatorNode(prefix1)], + name: 'dynamicPrefixEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/dynamic_prefix_event.rs').content; + + codeContains(code, ['pub struct DynamicPrefixEvent', 'DYNAMIC_PREFIX_EVENT_DISCRIMINATOR']); + codeDoesNotContains(code, ['from_bytes']); +}); +// --- Program-level event codegen tests --- + +test('it does not render program events file when no events have discriminators', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + name: 'transferEvent', + }), + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'delegate', type: numberTypeNode('u64') })]), + name: 'approveEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const keys = [...renderMap.keys()]; + const programEventsFiles = keys.filter(k => k.includes('my_program_events')); + expect(programEventsFiles).toHaveLength(0); +}); + +test('it renders identify and try_parse for events with constant discriminators', () => { + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ), + ], + name: 'tradeEvent', + }), + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'price', type: numberTypeNode('u64') })]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', '1122334455667788'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', '1122334455667788'), + ), + ), + ], + name: 'settleEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'pub fn identify_my_program_event(data: &[u8]) -> Option', + 'SETTLE_EVENT_DISCRIMINATOR', + 'return Some(MyProgramEventKind::SettleEvent)', + 'TRADE_EVENT_DISCRIMINATOR', + 'return Some(MyProgramEventKind::TradeEvent)', + 'pub fn try_parse_my_program_event(data: &[u8]) -> Option>', + 'identify_my_program_event(data)?', + // Skips are numeric literals (8-byte prefix), so match each arm to keep them distinct. + /MyProgramEventKind::SettleEvent => \{\s*let mut data = &data\[8\.\.\];\s*SettleEvent::deserialize\(&mut data\)/, + /MyProgramEventKind::TradeEvent => \{\s*let mut data = &data\[8\.\.\];\s*TradeEvent::deserialize\(&mut data\)/, + ]); + codeDoesNotContains(code, ['from_bytes', 'Err(std::io::Error::new']); +}); + +test('it uses BorshDeserialize for events without from_bytes in try_parse', () => { + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ), + ], + name: 'tradeEvent', + }), + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') })]), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', '5566778899aabbcc'), + ), + ), + ], + name: 'simpleEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + /MyProgramEventKind::TradeEvent => \{\s*let mut data = &data\[8\.\.\];\s*TradeEvent::deserialize\(&mut data\)/, + ]); + codeContains(code, ['SimpleEvent::deserialize(&mut data)']); + codeDoesNotContains(code, ['from_bytes']); +}); + +test('it excludes non-fixed-size prefix events from program-level try_parse', () => { + const fixedPrefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ); + const nonFixedPrefix = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [fixedPrefix], + ), + discriminators: [constantDiscriminatorNode(fixedPrefix)], + name: 'goodEvent', + }), + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + [fixedPrefix, nonFixedPrefix], + ), + discriminators: [constantDiscriminatorNode(fixedPrefix)], + name: 'dynamicEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, ['GoodEvent', 'GoodEvent::deserialize']); + codeDoesNotContains(code, ['DynamicEvent']); +}); + +test('it does not render program events file when program has no events', () => { + const node = programNode({ + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const keys = [...renderMap.keys()]; + const programEventsFiles = keys.filter(k => k.includes('_events.rs')); + expect(programEventsFiles).toHaveLength(0); +}); + +test('it includes program events module in events mod.rs', () => { + const node = rootNode( + programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [ + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ], + ), + discriminators: [ + constantDiscriminatorNode( + constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), + ), + ), + ], + name: 'transferEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }), + ); + + const renderMap = visit(node, getRenderMapVisitor()); + expect(renderMap.has('events/my_program_events.rs')).toBe(true); + codeContains(getFromRenderMap(renderMap, 'events/mod.rs').content, [ + 'pub(crate) mod r#my_program_events;', + 'pub use self::r#my_program_events::*;', + ]); +}); + +test('it excludes program events module from events mod.rs when no events have discriminators', () => { + const node = rootNode( + programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + name: 'transferEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }), + ); + + const renderMap = visit(node, getRenderMapVisitor()); + codeDoesNotContains(getFromRenderMap(renderMap, 'events/mod.rs').content, ['my_program_events']); +}); + +test('it renders identify and try_parse for events with field discriminators', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: numberValueNode(7), + name: 'eventType', + type: numberTypeNode('u8'), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('eventType')], + name: 'typedEvent', + }), + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: numberValueNode(1.0), + name: 'version', + type: numberTypeNode('f32'), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('version')], + name: 'floatDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'pub fn identify_my_program_event', + 'data.get(..1) == Some(&TYPED_EVENT_EVENT_TYPE.to_le_bytes())', + 'return Some(MyProgramEventKind::TypedEvent)', + 'data.get(..4) == Some(&FLOAT_DISC_EVENT_VERSION.to_le_bytes())', + 'return Some(MyProgramEventKind::FloatDiscEvent)', + 'pub fn try_parse_my_program_event', + ]); +}); + +test('it renders identify and try_parse for events with size discriminators', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [sizeDiscriminatorNode(8)], + name: 'fixedSizeEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'pub fn identify_my_program_event', + 'data.len() == 8', + 'return Some(MyProgramEventKind::FixedSizeEvent)', + 'pub fn try_parse_my_program_event', + ]); +}); + +test('it AND-s multiple discriminators for the same event in identify', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: numberValueNode(3), + name: 'eventType', + type: numberTypeNode('u8'), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [sizeDiscriminatorNode(9), fieldDiscriminatorNode('eventType')], + name: 'mixedDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'data.len() == 9 && data.get(..1) == Some(&MIXED_DISC_EVENT_EVENT_TYPE.to_le_bytes())', + 'return Some(MyProgramEventKind::MixedDiscEvent)', + ]); +}); + +test('it renders identify for events with byte-array field discriminators', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ + defaultValue: arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + name: 'disc', + type: arrayTypeNode(numberTypeNode('u8'), fixedCountNode(3)), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('disc')], + name: 'arrayDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'pub fn identify_my_program_event', + 'data.get(..ARRAY_DISC_EVENT_DISC.len()) == Some(&ARRAY_DISC_EVENT_DISC[..])', + 'return Some(MyProgramEventKind::ArrayDiscEvent)', + ]); + codeDoesNotContains(code, ['to_le_bytes']); + + const eventCode = getFromRenderMap(renderMap, 'events/array_disc_event.rs').content; + codeContains(eventCode, ['ARRAY_DISC_EVENT_DISC: [u8; 3] = [1, 2, 3]']); +}); + +test('it handles non-zero offset in constant discriminator conditions', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [ + constantDiscriminatorNode( + constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 4), bytesValueNode('base16', 'aabbccdd')), + 8, + ), + ], + name: 'offsetEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'pub fn identify_my_program_event', + 'data.get(8..12) == Some(&OFFSET_EVENT_DISCRIMINATOR[..])', + 'return Some(MyProgramEventKind::OffsetEvent)', + 'pub fn try_parse_my_program_event', + 'OffsetEvent::deserialize(&mut data)', + ]); +}); + +test('it uses a literal range in identify for u8-array constant discriminators at non-zero offset', () => { + // u8-array constant: no fixedSizeTypeNode, but the fixed count gives a static size of 3. + const arrayDisc = constantValueNode( + arrayTypeNode(numberTypeNode('u8'), fixedCountNode(3)), + arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + ); + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [constantDiscriminatorNode(arrayDisc, 4)], + name: 'tailDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'data.get(4..7) == Some(&TAIL_DISC_EVENT_DISCRIMINATOR[..])', + 'return Some(MyProgramEventKind::TailDiscEvent)', + ]); +}); + +test('it falls back to starts_with in identify when a non-zero-offset discriminator size is unknown', () => { + // Link-typed constant: byte size not resolvable at the discriminator site. + const linkDisc = constantValueNode( + definedTypeLinkNode('discAlias'), + arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + ); + const node = programNode({ + definedTypes: [definedTypeNode({ name: 'discAlias', type: fixedSizeTypeNode(bytesTypeNode(), 3) })], + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [constantDiscriminatorNode(linkDisc, 4)], + name: 'tailDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'data.get(4..).is_some_and(|tail| tail.starts_with(&TAIL_DISC_EVENT_DISCRIMINATOR[..]))', + 'return Some(MyProgramEventKind::TailDiscEvent)', + ]); +}); + +test('it compares number constant discriminators via to_le_bytes in identify', () => { + // Scalar number constants can't be sliced, so identify compares their byte encoding. + // Only LE is reachable: the type manifest visitor rejects big-endian numbers for Borsh. + const numDisc = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); + const shortDisc = constantValueNode(numberTypeNode('u16'), numberValueNode(7)); + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [constantDiscriminatorNode(numDisc, 0), constantDiscriminatorNode(shortDisc, 8)], + name: 'numDiscEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + + const eventCode = getFromRenderMap(renderMap, 'events/num_disc_event.rs').content; + codeContains(eventCode, [ + 'pub const NUM_DISC_EVENT_DISCRIMINATOR: u32 = 42;', + 'pub const NUM_DISC_EVENT_DISCRIMINATOR2: u16 = 7;', + ]); + + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + codeContains(code, [ + 'data.get(..4) == Some(&NUM_DISC_EVENT_DISCRIMINATOR.to_le_bytes())', + 'data.get(8..10) == Some(&NUM_DISC_EVENT_DISCRIMINATOR2.to_le_bytes())', + 'return Some(MyProgramEventKind::NumDiscEvent)', + ]); +}); + +test('it uses a literal range for fixed-size field discriminators at non-zero offset', () => { + const node = programNode({ + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'header', type: numberTypeNode('u32') }), + structFieldTypeNode({ + defaultValue: arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + name: 'disc', + type: arrayTypeNode(numberTypeNode('u8'), fixedCountNode(3)), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('disc', 4)], + name: 'offsetFieldEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'data.get(4..7) == Some(&OFFSET_FIELD_EVENT_DISC[..])', + 'return Some(MyProgramEventKind::OffsetFieldEvent)', + ]); +}); + +test('it falls back to starts_with for field discriminators with unknown size at non-zero offset', () => { + const node = programNode({ + definedTypes: [definedTypeNode({ name: 'discAlias', type: fixedSizeTypeNode(bytesTypeNode(), 3) })], + events: [ + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'header', type: numberTypeNode('u32') }), + structFieldTypeNode({ + defaultValue: arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + name: 'disc', + // Link-typed field: byte size not resolvable at the discriminator site. + type: definedTypeLinkNode('discAlias'), + }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('disc', 4)], + name: 'offsetFieldEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'data.get(4..).is_some_and(|tail| tail.starts_with(&OFFSET_FIELD_EVENT_DISC[..]))', + 'return Some(MyProgramEventKind::OffsetFieldEvent)', + ]); +}); + +test('it handles multiple constant discriminators and excludes events with unresolvable field discriminators', () => { + const disc1 = constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 4), bytesValueNode('base16', 'aabbccdd')); + const disc2 = constantValueNode(fixedSizeTypeNode(bytesTypeNode(), 2), bytesValueNode('base16', 'eeff')); + const node = programNode({ + events: [ + // Event with two constant discriminators — tests _2 suffix naming and AND-ing. + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') })]), + discriminators: [constantDiscriminatorNode(disc1, 0), constantDiscriminatorNode(disc2, 4)], + name: 'multiDiscEvent', + }), + // Event with field discriminator that has no defaultValue — should be excluded. + eventNode({ + data: structTypeNode([ + structFieldTypeNode({ name: 'eventType', type: numberTypeNode('u8') }), + structFieldTypeNode({ name: 'value', type: numberTypeNode('u64') }), + ]), + discriminators: [fieldDiscriminatorNode('eventType')], + name: 'noDefaultEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const code = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(code, [ + 'MULTI_DISC_EVENT_DISCRIMINATOR.len()) == Some(&MULTI_DISC_EVENT_DISCRIMINATOR[..])', + 'data.get(4..6) == Some(&MULTI_DISC_EVENT_DISCRIMINATOR2[..])', + 'return Some(MyProgramEventKind::MultiDiscEvent)', + ]); + codeContains(code, ['pub enum MyProgramEventKind']); + codeDoesNotContains(code, ['NoDefaultEvent']); +}); + +// --- Event framing (CPI-framed) tests --- + +const cpiFraming = { kind: 'anchorEventCpi', sharedConstantName: 'eventCpiPrefix' as CamelCaseString }; +const framingPrefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'aabbccdd11223344'), +); +const tradeDisc = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', '1122334455667788'), +); +const settleDisc = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', '99aabbccddeeff00'), +); + +function framedEvent(name: string, eventDisc: ReturnType) { + return eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [framingPrefix, eventDisc], + ), + discriminators: [constantDiscriminatorNode(framingPrefix, 0), constantDiscriminatorNode(eventDisc, 8)], + framing: cpiFraming, + name, + }); +} + +test('it hoists the shared framing constant to the program-events file', () => { + const node = programNode({ + events: [framedEvent('tradeEvent', tradeDisc), framedEvent('settleEvent', settleDisc)], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(programEventsCode, [ + 'pub const EVENT_CPI_PREFIX: [u8; 8] = [170, 187, 204, 221, 17, 34, 51, 68];', + 'data.get(..EVENT_CPI_PREFIX.len()) == Some(&EVENT_CPI_PREFIX[..])', + 'return Some(MyProgramEventKind::TradeEvent)', + 'return Some(MyProgramEventKind::SettleEvent)', + ]); + expect(programEventsCode.match(/pub const EVENT_CPI_PREFIX/g)).toHaveLength(1); +}); + +test('it renders per-event _DISCRIMINATOR with IDL bytes, not framing bytes', () => { + const node = programNode({ + events: [framedEvent('tradeEvent', tradeDisc)], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const tradeEventCode = getFromRenderMap(renderMap, 'events/trade_event.rs').content; + + codeContains(tradeEventCode, ['TRADE_EVENT_DISCRIMINATOR: [u8; 8] = [17, 34, 51, 68, 85, 102, 119, 136]']); + codeDoesNotContains(tradeEventCode, ['[170, 187, 204, 221, 17, 34, 51, 68]', 'pub const EVENT_CPI_PREFIX']); +}); + +test('it generates from_bytes that validates both the framing prefix and the event-specific discriminator', () => { + const node = programNode({ + events: [framedEvent('tradeEvent', tradeDisc)], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const tradeEventCode = getFromRenderMap(renderMap, 'events/trade_event.rs').content; + + codeContains(tradeEventCode, [ + 'pub fn from_bytes', + 'data.get(..EVENT_CPI_PREFIX.len()) != Some(&EVENT_CPI_PREFIX[..])', + 'data.get(8..16) != Some(&TRADE_EVENT_DISCRIMINATOR[..])', + // Both discriminator sizes are known, so the skip folds to a literal + // with an explanatory comment on the line above. + /\/\/ EVENT_CPI_PREFIX \(8\) \+ TRADE_EVENT_DISCRIMINATOR \(8\)\n\s*let mut data = &data\[16\.\.\];\n\s*Self::deserialize\(&mut data\)/, + ]); +}); + +test('it folds the framed skip to a literal for u8-array discriminators', () => { + // u8-array discriminator: the fixed count gives a static size of 8, so the skip folds to 16. + const arrayEventDisc = constantValueNode( + arrayTypeNode(numberTypeNode('u8'), fixedCountNode(8)), + arrayValueNode([ + numberValueNode(1), + numberValueNode(2), + numberValueNode(3), + numberValueNode(4), + numberValueNode(5), + numberValueNode(6), + numberValueNode(7), + numberValueNode(8), + ]), + ); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [framingPrefix, arrayEventDisc], + ), + discriminators: [ + constantDiscriminatorNode(framingPrefix, 0), + constantDiscriminatorNode(arrayEventDisc, 8), + ], + framing: cpiFraming, + name: 'mixedEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const eventCode = getFromRenderMap(renderMap, 'events/mixed_event.rs').content; + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(eventCode, [ + 'data.get(..EVENT_CPI_PREFIX.len()) != Some(&EVENT_CPI_PREFIX[..])', + 'data.get(8..16) != Some(&MIXED_EVENT_DISCRIMINATOR[..])', + 'let mut data = &data[16..];', + ]); + codeContains(programEventsCode, [ + /MyProgramEventKind::MixedEvent => \{\s*\/\/ EVENT_CPI_PREFIX \(8\) \+ MIXED_EVENT_DISCRIMINATOR \(8\)\n\s*let mut data = &data\[16\.\.\];\n\s*MixedEvent::deserialize\(&mut data\)/, + ]); +}); + +test('it compares number constant discriminators via to_le_bytes in framed from_bytes', () => { + const numEventDisc = constantValueNode(numberTypeNode('u32'), numberValueNode(42)); + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [framingPrefix, numEventDisc], + ), + discriminators: [ + constantDiscriminatorNode(framingPrefix, 0), + constantDiscriminatorNode(numEventDisc, 8), + ], + framing: cpiFraming, + name: 'numFramedEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const eventCode = getFromRenderMap(renderMap, 'events/num_framed_event.rs').content; + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(eventCode, [ + 'pub const NUM_FRAMED_EVENT_DISCRIMINATOR: u32 = 42;', + 'data.get(..EVENT_CPI_PREFIX.len()) != Some(&EVENT_CPI_PREFIX[..])', + 'if data.get(8..12) != Some(&NUM_FRAMED_EVENT_DISCRIMINATOR.to_le_bytes())', + // Both sizes are known (8 framing + 4 number), so the skip folds to a literal. + 'let mut data = &data[12..];', + ]); + codeContains(programEventsCode, [ + 'data.get(8..12) == Some(&NUM_FRAMED_EVENT_DISCRIMINATOR.to_le_bytes())', + /MyProgramEventKind::NumFramedEvent => \{\s*\/\/ EVENT_CPI_PREFIX \(8\) \+ NUM_FRAMED_EVENT_DISCRIMINATOR \(4\)\n\s*let mut data = &data\[12\.\.\];\n\s*NumFramedEvent::deserialize\(&mut data\)/, + ]); +}); + +test('it falls back to a chained .len() slice skip when a framed discriminator size is unknown', () => { + // Link-typed discriminator: the aliased type's byte size is not resolvable + // at the discriminator site, so the framed skip can't fold to a literal. + const linkEventDisc = constantValueNode( + definedTypeLinkNode('discAlias'), + arrayValueNode([numberValueNode(1), numberValueNode(2), numberValueNode(3)]), + ); + const node = programNode({ + definedTypes: [definedTypeNode({ name: 'discAlias', type: fixedSizeTypeNode(bytesTypeNode(), 3) })], + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [framingPrefix, linkEventDisc], + ), + discriminators: [ + constantDiscriminatorNode(framingPrefix, 0), + constantDiscriminatorNode(linkEventDisc, 8), + ], + framing: cpiFraming, + name: 'mixedEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const eventCode = getFromRenderMap(renderMap, 'events/mixed_event.rs').content; + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(eventCode, [ + 'data.get(..EVENT_CPI_PREFIX.len()) != Some(&EVENT_CPI_PREFIX[..])', + 'if !data.get(8..).is_some_and(|tail| tail.starts_with(&MIXED_EVENT_DISCRIMINATOR[..]))', + // The framing size (8) is known and folds to a literal; the unknown-size + // discriminator chains a `[.len()..]` slice so no `+` arithmetic is emitted. + /\/\/ EVENT_CPI_PREFIX \(8\) \+ MIXED_EVENT_DISCRIMINATOR\n\s*let mut data = &data\[8\.\.\]\[MIXED_EVENT_DISCRIMINATOR\.len\(\)\.\.\];/, + ]); + codeContains(programEventsCode, ['let mut data = &data[8..][MIXED_EVENT_DISCRIMINATOR.len()..];']); +}); + +test('it references the hoisted framing constant in identify and try_parse', () => { + const node = programNode({ + events: [framedEvent('tradeEvent', tradeDisc), framedEvent('settleEvent', settleDisc)], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(programEventsCode, [ + 'pub fn identify_my_program_event', + 'data.get(..EVENT_CPI_PREFIX.len()) == Some(&EVENT_CPI_PREFIX[..])', + '&& data.get(8..16) == Some(&TRADE_EVENT_DISCRIMINATOR[..])', + '&& data.get(8..16) == Some(&SETTLE_EVENT_DISCRIMINATOR[..])', + 'pub fn try_parse_my_program_event', + // Skips are numeric literals (8 framing + 8 event disc), so match each arm to keep them distinct. + /MyProgramEventKind::TradeEvent => \{\s*\/\/ EVENT_CPI_PREFIX \(8\) \+ TRADE_EVENT_DISCRIMINATOR \(8\)\n\s*let mut data = &data\[16\.\.\];\n\s*TradeEvent::deserialize\(&mut data\)/, + /MyProgramEventKind::SettleEvent => \{\s*\/\/ EVENT_CPI_PREFIX \(8\) \+ SETTLE_EVENT_DISCRIMINATOR \(8\)\n\s*let mut data = &data\[16\.\.\];\n\s*SettleEvent::deserialize\(&mut data\)/, + ]); +}); + +test('it does not hoist a shared constant when no event has framing', () => { + const node = programNode({ + events: [ + eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [framingPrefix], + ), + discriminators: [constantDiscriminatorNode(framingPrefix, 0)], + name: 'plainEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + const plainEventCode = getFromRenderMap(renderMap, 'events/plain_event.rs').content; + + codeDoesNotContains(programEventsCode, ['EVENT_CPI_PREFIX']); + codeDoesNotContains(plainEventCode, ['EVENT_CPI_PREFIX']); + codeContains(plainEventCode, ['PLAIN_EVENT_DISCRIMINATOR: [u8; 8] = [170, 187, 204, 221, 17, 34, 51, 68]']); +}); + +test('it renders framed and non-framed events side-by-side without cross-contamination', () => { + const node = programNode({ + events: [ + framedEvent('tradeEvent', tradeDisc), + eventNode({ + data: structTypeNode([structFieldTypeNode({ name: 'value', type: numberTypeNode('u32') })]), + discriminators: [constantDiscriminatorNode(settleDisc, 0)], + name: 'plainEvent', + }), + ], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const tradeEventCode = getFromRenderMap(renderMap, 'events/trade_event.rs').content; + const plainEventCode = getFromRenderMap(renderMap, 'events/plain_event.rs').content; + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + codeContains(tradeEventCode, [ + 'use crate::generated::events::EVENT_CPI_PREFIX;', + 'data.get(..EVENT_CPI_PREFIX.len()) != Some(&EVENT_CPI_PREFIX[..])', + ]); + codeDoesNotContains(plainEventCode, ['EVENT_CPI_PREFIX']); + codeContains(programEventsCode, [ + 'pub const EVENT_CPI_PREFIX: [u8; 8] = [170, 187, 204, 221, 17, 34, 51, 68];', + 'return Some(MyProgramEventKind::TradeEvent)', + 'return Some(MyProgramEventKind::PlainEvent)', + ]); +}); + +test('it warns and hoists only the first framing when events have conflicting sharedConstantName', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + try { + const altFraming = { kind: 'anchorEventCpi', sharedConstantName: 'altPrefix' as CamelCaseString }; + const altPrefix = constantValueNode( + fixedSizeTypeNode(bytesTypeNode(), 8), + bytesValueNode('base16', 'deadbeefcafebabe'), + ); + const altEvent = eventNode({ + data: hiddenPrefixTypeNode( + structTypeNode([structFieldTypeNode({ name: 'amount', type: numberTypeNode('u64') })]), + [altPrefix, settleDisc], + ), + discriminators: [constantDiscriminatorNode(altPrefix, 0), constantDiscriminatorNode(settleDisc, 8)], + framing: altFraming, + name: 'settleEvent', + }); + + const node = programNode({ + events: [framedEvent('tradeEvent', tradeDisc), altEvent], + name: 'myProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const programEventsCode = getFromRenderMap(renderMap, 'events/my_program_events.rs').content; + + expect(warnSpy).toHaveBeenCalledTimes(1); + expect(warnSpy.mock.calls[0][0]).toMatch(/conflicting event framings.*'eventCpiPrefix' vs 'altPrefix'/); + + codeContains(programEventsCode, ['pub const EVENT_CPI_PREFIX']); + codeDoesNotContains(programEventsCode, ['pub const ALT_PREFIX']); + } finally { + warnSpy.mockRestore(); + } +}); diff --git a/test/instructionsPage.test.ts b/test/instructionsPage.test.ts index 8d1ad3a..311ce5e 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,1168 @@ 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 throws on 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', + }); + + // Then the native input resolution hard-throws instead of degrading. + expect(() => visit(node, getRenderMapVisitor())).toThrow(/[Cc]ircular dependency/); +}); + +test('it throws 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', + }); + + // An unbound variable seed cannot be derived at runtime — hard-throw. + expect(() => visit(node, getRenderMapVisitor())).toThrow(/Missing seed value for variable seed \[owner\]/); +}); + +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']); +}); + +test('it derives linked PDAs with a dynamic programId by passing the program to the helper', () => { + // Given linked PDAs whose deriving program is a runtime account reference. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + isOptional: false, + isSigner: false, + isWritable: false, + name: 'ammProgram', + }), + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'market' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaLinkNode('pool'), + [pdaSeedValueNode('market', accountValueNode('market'))], + accountValueNode('ammProgram'), + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'pool', + }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('authority'), [], accountValueNode('ammProgram')), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'authority', + }), + ], + name: 'migrate', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ name: 'pool', seeds: [variablePdaSeedNode('market', publicKeyTypeNode())] }), + pdaNode({ name: 'authority', seeds: [constantPdaSeedNodeFromString('utf8', 'authority')] }), + ], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/migrate.rs').content; + + // Then the builder calls the helpers with the referenced account as the + // deriving program. + codeContains(content, [ + `crate::pdas::find_pool_pda(`, + `&self.market,`, + `&self.amm_program,`, + `crate::pdas::find_authority_pda(`, + ]); + // And never through a local-program constant. + codeDoesNotContains(content, [`AUTHORITY_ADDRESS`, `_with_program`]); + + // And the dynamic-only PDA helpers take the deriving program as a required + // parameter; the local-program _ADDRESS constant is not emitted. + const authorityPda = getFromRenderMap(renderMap, 'pdas/authority.rs').content; + codeContains(authorityPda, [ + /pub fn find_authority_pda\(\s*program_address: &solana_address::Address,/, + `pub const AUTHORITY_SEED`, + ]); + codeDoesNotContains(authorityPda, [`AUTHORITY_ADDRESS`, `_with_program`, `use crate::TEST_PROGRAM_ID`]); +}); + +test('it derives linked PDAs with a dynamic programId from an argument reference', () => { + // Given a PDA whose deriving program comes from a required instruction argument. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'market' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaLinkNode('pool'), + [pdaSeedValueNode('market', accountValueNode('market'))], + argumentValueNode('poolProgram'), + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'pool', + }), + ], + arguments: [instructionArgumentNode({ name: 'poolProgram', type: publicKeyTypeNode() })], + name: 'migrate', + }), + ], + name: 'testProgram', + pdas: [pdaNode({ name: 'pool', seeds: [variablePdaSeedNode('market', publicKeyTypeNode())] })], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/migrate.rs').content; + + // Required arg — direct field access as the deriving program. + codeContains(content, [`crate::pdas::find_pool_pda(`, `&self.market,`, `&self.pool_program,`]); +}); + +test('it throws on a nested argument path in a PDA seed', () => { + // Given a PDA seed bound to a nested argument path (e.g. account-data field). + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('guard'), [ + pdaSeedValueNode('mint', argumentValueNode('guardData', ['mint'])), + ]), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'guard', + }), + ], + arguments: [instructionArgumentNode({ name: 'guardData', type: publicKeyTypeNode() })], + name: 'execute', + }), + ], + name: 'testProgram', + pdas: [pdaNode({ name: 'guard', seeds: [variablePdaSeedNode('mint', publicKeyTypeNode())] })], + publicKey: '11111111111111111111111111111111', + }); + + // Nested paths have no builder field to read from — hard-throw. + expect(() => visit(node, getRenderMapVisitor())).toThrow(/nested argument path \[guardData\.mint\]/); +}); + +test('it renders inline constant string seeds with byte semantics', () => { + // Given an inline (non-linked) PDA default with a constant string seed. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'owner' }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaNode({ + name: 'ata', + programId: 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'prefix'), + variablePdaSeedNode('owner', publicKeyTypeNode()), + ], + }), + [pdaSeedValueNode('owner', accountValueNode('owner'))], + ), + isOptional: false, + isSigner: false, + isWritable: true, + name: 'ata', + }), + ], + name: 'init', + }), + ], + name: 'testProgram', + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/init.rs').content; + + // The string seed must be a byte-string literal, not a Rust String. + codeContains(content, [ + `find_program_address`, + `b"prefix"`, + `solana_address::address!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL")`, + ]); + codeDoesNotContains(content, [`String::from`]); +}); + +test('it renders extra arguments as required builder inputs', () => { + // Given an instruction whose PDA seed reads a caller-supplied extra argument. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('guard'), [ + pdaSeedValueNode('mint', argumentValueNode('guardMint')), + ]), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'guard', + }), + ], + arguments: [instructionArgumentNode({ name: 'amount', type: numberTypeNode('u64') })], + extraArguments: [instructionArgumentNode({ name: 'guardMint', type: publicKeyTypeNode() })], + name: 'execute', + }), + ], + name: 'testProgram', + pdas: [pdaNode({ name: 'guard', seeds: [variablePdaSeedNode('mint', publicKeyTypeNode())] })], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/execute.rs').content; + + codeContains(content, [ + // Builder field + constructor param appended after required args. + /pub fn new\([\s\S]*amount: u64,[\s\S]*guard_mint: Address,[\s\S]*\) -> Self/, + `guard_mint: Address,`, + // Read by the PDA derivation. + `crate::pdas::find_guard_pda(`, + `&self.guard_mint.clone(),`, + ]); + // Never serialized into the instruction data/args structs. + codeDoesNotContains(content, [`pub guard_mint`]); +}); + +test('it suffixes extra arguments conflicting with account names', () => { + // Given an extra argument whose name collides with an account. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: false, isSigner: false, isWritable: false, name: 'mint' }), + instructionAccountNode({ + defaultValue: pdaValueNode(pdaLinkNode('guard'), [ + pdaSeedValueNode('mint', argumentValueNode('mint')), + ]), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'guard', + }), + ], + extraArguments: [instructionArgumentNode({ name: 'mint', type: publicKeyTypeNode() })], + name: 'execute', + }), + ], + name: 'testProgram', + pdas: [pdaNode({ name: 'guard', seeds: [variablePdaSeedNode('mint', publicKeyTypeNode())] })], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/execute.rs').content; + + // The extra-arg field and its seed usage both carry the _arg suffix. + codeContains(content, [`mint_arg: Address,`, `&self.mint_arg.clone(),`]); +}); + +// Relies on allowOptionalAccountsAsPdaSeeds; derivation runs inside unwrap_or_else, +// so the expect() only fires when the PDA actually needs deriving. +test('it derives a PDA from an optional account seed via expect', () => { + // Given a PDA-defaulted account whose seed reads an optional account. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ isOptional: true, 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', + pdas: [pdaNode({ name: 'record', seeds: [variablePdaSeedNode('owner', publicKeyTypeNode())] })], + publicKey: '11111111111111111111111111111111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'instructions/create_record.rs').content; + + codeContains(content, [`crate::pdas::find_record_pda(`, `&self.owner.expect("owner is needed for record PDA")`]); +}); + +test('it folds constant-seed dynamic PDAs under the canonical program default', () => { + // Given a constant-seed PDA pinned to a foreign program via pdaNode.programId, + // while the use-site still passes a runtime program reference. + const node = programNode({ + instructions: [ + instructionNode({ + accounts: [ + instructionAccountNode({ + defaultValue: publicKeyValueNode('CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C'), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'cpswapProgram', + }), + instructionAccountNode({ + defaultValue: pdaValueNode( + pdaLinkNode('vaultAuthority'), + [], + accountValueNode('cpswapProgram'), + ), + isOptional: false, + isSigner: false, + isWritable: false, + name: 'vaultAuthority', + }), + ], + name: 'migrate', + }), + ], + name: 'testProgram', + pdas: [ + pdaNode({ + name: 'vaultAuthority', + programId: 'CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C', + seeds: [constantPdaSeedNodeFromString('utf8', 'vault_auth')], + }), + ], + publicKey: '11111111111111111111111111111111', + }); + + const renderMap = visit(node, getRenderMapVisitor()); + + // The pdas page folds the address at codegen time under the pinned program, + // and the helpers bake that program in — no program parameter. + const pdaContent = getFromRenderMap(renderMap, 'pdas/vault_authority.rs').content; + codeContains(pdaContent, [ + `pub const VAULT_AUTHORITY_PROGRAM_ADDRESS: solana_address::Address`, + `CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C`, + `pub const VAULT_AUTHORITY_ADDRESS: solana_address::Address`, + ]); + codeDoesNotContains(pdaContent, [`program_address:`]); + + // The builder uses the folded constant directly. + const ixContent = getFromRenderMap(renderMap, 'instructions/migrate.rs').content; + codeContains(ixContent, [`unwrap_or(`, `crate::pdas::VAULT_AUTHORITY_ADDRESS`]); + codeDoesNotContains(ixContent, [`find_vault_authority_pda`]); +}); diff --git a/test/pdasPage.test.ts b/test/pdasPage.test.ts new file mode 100644 index 0000000..78715c1 --- /dev/null +++ b/test/pdasPage.test.ts @@ -0,0 +1,272 @@ +import { + bytesTypeNode, + constantPdaSeedNode, + constantPdaSeedNodeFromBytes, + constantPdaSeedNodeFromString, + fixedSizeTypeNode, + numberTypeNode, + numberValueNode, + pdaNode, + programNode, + publicKeyTypeNode, + publicKeyValueNode, + 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,', + ]); +}); + +test('it renders constant publicKey seeds as byte-array seed constants', () => { + // Given a PDA with a constant publicKey seed, as codama emits when an + // address-pinned program account is used as a seed (e.g. raydium's ammPool). + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'ammPool', + programId: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8', + seeds: [ + constantPdaSeedNode( + publicKeyTypeNode(), + publicKeyValueNode('675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8'), + ), + variablePdaSeedNode('market', publicKeyTypeNode()), + constantPdaSeedNodeFromString('utf8', 'amm_associated_seed'), + ], + }), + ], + publicKey: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + + // Then the publicKey seed renders as its base58-decoded byte slice. + codeContains(getFromRenderMap(renderMap, 'pdas/amm_pool.rs').content, [ + "pub const AMM_POOL_SEED_0: &'static [u8] = " + + '&[75, 217, 73, 196, 54, 2, 195, 63, 32, 119, 144, 237, 22, 163, 82, 76, ' + + '161, 185, 151, 92, 241, 33, 162, 169, 12, 255, 236, 125, 248, 182, 138, 205];', + 'pub const AMM_POOL_SEED_1: &\'static [u8] = b"amm_associated_seed";', + 'pub fn find_amm_pool_pda(', + ]); +}); + +test('it bakes the local program into helpers of same-program PDAs', () => { + // Given a standalone PDA with no dynamic-programId usages. + const node = programNode({ + name: 'myProgram', + pdas: [ + pdaNode({ + name: 'myPda', + seeds: [ + constantPdaSeedNodeFromString('utf8', 'prefix'), + variablePdaSeedNode('owner', publicKeyTypeNode()), + ], + }), + ], + publicKey: '1111', + }); + + // When we render it. + const renderMap = visit(node, getRenderMapVisitor()); + const content = getFromRenderMap(renderMap, 'pdas/my_pda.rs').content; + + // Then the helpers derive under this crate's program — no program parameter. + codeContains(content, [`pub fn find_my_pda_pda(`, `pub fn create_my_pda_pda(`, `&MY_PROGRAM_ID,`]); + codeDoesNotContains(content, [`program_address:`, `_with_program`]); +}); 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"'); + }); });