1use arch_program::compute_budget::ComputeBudgetInstruction;
12use arch_program::program_pack::Pack;
13use arch_program::{
14 account::AccountMeta, instruction::Instruction, pubkey::Pubkey, system_instruction,
15};
16
17use apl_token;
18
19use arch_token_metadata as program;
20use program::state::{
21 DESCRIPTION_MAX_LEN, IMAGE_MAX_LEN, MAX_ATTRIBUTES, MAX_KEY_LENGTH, MAX_VALUE_LENGTH,
22 NAME_MAX_LEN, SYMBOL_MAX_LEN,
23};
24
25use anyhow::Context as _;
27use program::state::{TokenMetadata, TokenMetadataAttributes};
28
29pub struct TokenMetadataClient {
33 pub program_id: Pubkey,
34}
35
36impl TokenMetadataClient {
37 pub fn new(program_id: Pubkey) -> Self {
38 Self { program_id }
39 }
40
41 pub fn metadata_pda(&self, mint: &Pubkey) -> Pubkey {
43 let (pda, _bump) = program::find_metadata_pda_with_program(&self.program_id, mint);
44 pda
45 }
46
47 pub fn metadata_pda_and_bump(&self, mint: &Pubkey) -> (Pubkey, u8) {
49 program::find_metadata_pda_with_program(&self.program_id, mint)
50 }
51
52 pub fn attributes_pda(&self, mint: &Pubkey) -> Pubkey {
54 let (pda, _bump) = program::find_attributes_pda_with_program(&self.program_id, mint);
55 pda
56 }
57
58 pub fn attributes_pda_and_bump(&self, mint: &Pubkey) -> (Pubkey, u8) {
60 program::find_attributes_pda_with_program(&self.program_id, mint)
61 }
62
63 pub fn create_metadata_ix(&self, params: CreateMetadataParams) -> anyhow::Result<Instruction> {
72 let metadata_pda = self.metadata_pda(¶ms.mint);
73 self.validate_metadata_fields(
74 ¶ms.name,
75 ¶ms.symbol,
76 ¶ms.image,
77 ¶ms.description,
78 )?;
79
80 let data = program::instruction::MetadataInstruction::CreateMetadata {
81 name: params.name,
82 symbol: params.symbol,
83 image: params.image,
84 description: params.description,
85 immutable: params.immutable,
86 }
87 .pack();
88
89 Ok(Instruction {
90 program_id: self.program_id,
91 accounts: vec![
92 AccountMeta::new(params.payer, true),
93 AccountMeta::new_readonly(Pubkey::system_program(), false),
94 AccountMeta::new_readonly(params.mint, false),
95 AccountMeta::new(metadata_pda, false),
96 AccountMeta::new_readonly(params.mint_or_freeze_authority, true),
97 ],
98 data,
99 })
100 }
101
102 pub fn update_metadata_ix(&self, params: UpdateMetadataParams) -> anyhow::Result<Instruction> {
108 let metadata_pda = self.metadata_pda(¶ms.mint);
109 self.validate_optional_metadata_fields(
110 params.name.as_ref(),
111 params.symbol.as_ref(),
112 params.image.as_ref(),
113 params.description.as_ref(),
114 )?;
115 let data = program::instruction::MetadataInstruction::UpdateMetadata {
116 name: params.name,
117 symbol: params.symbol,
118 image: params.image,
119 description: params.description,
120 }
121 .pack();
122
123 Ok(Instruction {
124 program_id: self.program_id,
125 accounts: vec![
126 AccountMeta::new(metadata_pda, false),
127 AccountMeta::new_readonly(params.update_authority, true),
128 ],
129 data,
130 })
131 }
132
133 pub fn create_attributes_ix(
143 &self,
144 params: CreateAttributesParams,
145 ) -> anyhow::Result<Instruction> {
146 let metadata_pda = self.metadata_pda(¶ms.mint);
147 let attributes_pda = self.attributes_pda(¶ms.mint);
148 self.validate_attributes(¶ms.data)?;
149
150 let data =
151 program::instruction::MetadataInstruction::CreateAttributes { data: params.data }
152 .pack();
153
154 Ok(Instruction {
155 program_id: self.program_id,
156 accounts: vec![
157 AccountMeta::new(params.payer, true),
158 AccountMeta::new_readonly(Pubkey::system_program(), false),
159 AccountMeta::new_readonly(params.mint, false),
160 AccountMeta::new(attributes_pda, false),
161 AccountMeta::new_readonly(params.update_authority, true),
162 AccountMeta::new_readonly(metadata_pda, false),
163 ],
164 data,
165 })
166 }
167
168 pub fn replace_attributes_ix(
175 &self,
176 params: ReplaceAttributesParams,
177 ) -> anyhow::Result<Instruction> {
178 let metadata_pda = self.metadata_pda(¶ms.mint);
179 let attributes_pda = self.attributes_pda(¶ms.mint);
180 self.validate_attributes(¶ms.data)?;
181
182 let data =
183 program::instruction::MetadataInstruction::ReplaceAttributes { data: params.data }
184 .pack();
185
186 Ok(Instruction {
187 program_id: self.program_id,
188 accounts: vec![
189 AccountMeta::new(attributes_pda, false),
190 AccountMeta::new_readonly(params.update_authority, true),
191 AccountMeta::new_readonly(metadata_pda, false),
192 ],
193 data,
194 })
195 }
196
197 pub fn transfer_authority_ix(
203 &self,
204 params: TransferAuthorityParams,
205 ) -> anyhow::Result<Instruction> {
206 let metadata_pda = self.metadata_pda(¶ms.mint);
207 let data = program::instruction::MetadataInstruction::TransferAuthority {
208 new_authority: params.new_authority,
209 }
210 .pack();
211
212 Ok(Instruction {
213 program_id: self.program_id,
214 accounts: vec![
215 AccountMeta::new(metadata_pda, false),
216 AccountMeta::new_readonly(params.current_update_authority, true),
217 ],
218 data,
219 })
220 }
221
222 pub fn make_immutable_ix(&self, params: MakeImmutableParams) -> anyhow::Result<Instruction> {
228 let metadata_pda = self.metadata_pda(¶ms.mint);
229 let data = program::instruction::MetadataInstruction::MakeImmutable.pack();
230
231 Ok(Instruction {
232 program_id: self.program_id,
233 accounts: vec![
234 AccountMeta::new(metadata_pda, false),
235 AccountMeta::new_readonly(params.current_update_authority, true),
236 ],
237 data,
238 })
239 }
240
241 pub fn create_mint_account_ix(&self, payer: Pubkey, mint: Pubkey) -> Instruction {
244 use arch_program::account::MIN_ACCOUNT_LAMPORTS;
245 system_instruction::create_account(
246 &payer,
247 &mint,
248 MIN_ACCOUNT_LAMPORTS,
249 apl_token::state::Mint::LEN as u64,
250 &apl_token::id(),
251 )
252 }
253
254 pub fn initialize_mint2_ix(
256 &self,
257 mint: Pubkey,
258 mint_authority: Pubkey,
259 freeze_authority: Option<Pubkey>,
260 decimals: u8,
261 ) -> anyhow::Result<Instruction> {
262 let ix = apl_token::instruction::initialize_mint2(
263 &apl_token::id(),
264 &mint,
265 &mint_authority,
266 freeze_authority.as_ref(),
267 decimals,
268 )?;
269 Ok(ix)
270 }
271
272 pub fn set_mint_authority_ix(
274 &self,
275 mint: Pubkey,
276 new_authority: Option<Pubkey>,
277 current_authority: Pubkey,
278 ) -> anyhow::Result<Instruction> {
279 let ix = apl_token::instruction::set_authority(
280 &apl_token::id(),
281 &mint,
282 new_authority.as_ref(),
283 apl_token::instruction::AuthorityType::MintTokens,
284 ¤t_authority,
285 &[],
286 )?;
287 Ok(ix)
288 }
289
290 pub fn create_token_with_metadata_tx(
295 &self,
296 params: TxCreateTokenWithMetadataParams,
297 ) -> anyhow::Result<Vec<Instruction>> {
298 let create_mint_ix = self.create_mint_account_ix(params.payer, params.mint);
299
300 let init_mint_ix = self.initialize_mint2_ix(
301 params.mint,
302 params.mint_authority,
303 params.freeze_authority,
304 params.decimals,
305 )?;
306
307 let create_md_ix = self.create_metadata_ix(CreateMetadataParams {
308 payer: params.payer,
309 mint: params.mint,
310 mint_or_freeze_authority: params.mint_authority,
311 name: params.name,
312 symbol: params.symbol,
313 image: params.image,
314 description: params.description,
315 immutable: params.immutable,
316 })?;
317
318 Ok(vec![create_mint_ix, init_mint_ix, create_md_ix])
319 }
320
321 pub fn create_token_with_metadata_tx_with_budget(
323 &self,
324 params: TxCreateTokenWithMetadataParams,
325 budget: ComputeBudgetOptions,
326 ) -> anyhow::Result<Vec<Instruction>> {
327 let mut out = self.compute_budget_ixs(&budget);
328 out.extend(self.create_token_with_metadata_tx(params)?);
329 Ok(out)
330 }
331
332 pub fn create_token_with_metadata_and_attributes_tx(
335 &self,
336 params: TxCreateTokenWithMetadataAndAttributesParams,
337 ) -> anyhow::Result<Vec<Instruction>> {
338 let create_mint_ix = self.create_mint_account_ix(params.payer, params.mint);
339 let init_mint_ix = self.initialize_mint2_ix(
340 params.mint,
341 params.mint_authority,
342 params.freeze_authority,
343 params.decimals,
344 )?;
345
346 let create_md_ix = self.create_metadata_ix(CreateMetadataParams {
347 payer: params.payer,
348 mint: params.mint,
349 mint_or_freeze_authority: params.mint_authority,
350 name: params.name,
351 symbol: params.symbol,
352 image: params.image,
353 description: params.description,
354 immutable: params.immutable,
355 })?;
356
357 let create_attrs_ix = self.create_attributes_ix(CreateAttributesParams {
358 payer: params.payer,
359 mint: params.mint,
360 update_authority: params.mint_authority,
361 data: params.attributes,
362 })?;
363
364 Ok(vec![
365 create_mint_ix,
366 init_mint_ix,
367 create_md_ix,
368 create_attrs_ix,
369 ])
370 }
371
372 pub fn create_token_with_metadata_and_attributes_tx_with_budget(
374 &self,
375 params: TxCreateTokenWithMetadataAndAttributesParams,
376 budget: ComputeBudgetOptions,
377 ) -> anyhow::Result<Vec<Instruction>> {
378 let mut out = self.compute_budget_ixs(&budget);
379 out.extend(self.create_token_with_metadata_and_attributes_tx(params)?);
380 Ok(out)
381 }
382
383 pub fn create_token_with_freeze_auth_metadata_tx(
386 &self,
387 params: TxCreateTokenWithFreezeAuthMetadataParams,
388 ) -> anyhow::Result<Vec<Instruction>> {
389 let create_mint_ix = self.create_mint_account_ix(params.payer, params.mint);
390 let init_mint_ix = self.initialize_mint2_ix(
391 params.mint,
392 params.initial_mint_authority,
393 Some(params.freeze_authority),
394 params.decimals,
395 )?;
396
397 let clear_mint_auth_ix =
398 self.set_mint_authority_ix(params.mint, None, params.initial_mint_authority)?;
399
400 let create_md_ix = self.create_metadata_ix(CreateMetadataParams {
402 payer: params.payer,
403 mint: params.mint,
404 mint_or_freeze_authority: params.freeze_authority,
405 name: params.name,
406 symbol: params.symbol,
407 image: params.image,
408 description: params.description,
409 immutable: params.immutable,
410 })?;
411
412 Ok(vec![
413 create_mint_ix,
414 init_mint_ix,
415 clear_mint_auth_ix,
416 create_md_ix,
417 ])
418 }
419
420 pub fn create_token_with_freeze_auth_metadata_tx_with_budget(
422 &self,
423 params: TxCreateTokenWithFreezeAuthMetadataParams,
424 budget: ComputeBudgetOptions,
425 ) -> anyhow::Result<Vec<Instruction>> {
426 let mut out = self.compute_budget_ixs(&budget);
427 out.extend(self.create_token_with_freeze_auth_metadata_tx(params)?);
428 Ok(out)
429 }
430
431 pub fn create_attributes_tx(
433 &self,
434 params: CreateAttributesParams,
435 ) -> anyhow::Result<Vec<Instruction>> {
436 Ok(vec![self.create_attributes_ix(params)?])
437 }
438
439 pub fn create_attributes_tx_with_budget(
441 &self,
442 params: CreateAttributesParams,
443 budget: ComputeBudgetOptions,
444 ) -> anyhow::Result<Vec<Instruction>> {
445 let mut out = self.compute_budget_ixs(&budget);
446 out.extend(self.create_attributes_tx(params)?);
447 Ok(out)
448 }
449
450 pub fn replace_attributes_tx(
452 &self,
453 params: ReplaceAttributesParams,
454 ) -> anyhow::Result<Vec<Instruction>> {
455 Ok(vec![self.replace_attributes_ix(params)?])
456 }
457
458 pub fn replace_attributes_tx_with_budget(
460 &self,
461 params: ReplaceAttributesParams,
462 budget: ComputeBudgetOptions,
463 ) -> anyhow::Result<Vec<Instruction>> {
464 let mut out = self.compute_budget_ixs(&budget);
465 out.extend(self.replace_attributes_tx(params)?);
466 Ok(out)
467 }
468
469 pub fn transfer_authority_then_update_tx(
472 &self,
473 params: TxTransferAuthorityThenUpdateParams,
474 ) -> anyhow::Result<Vec<Instruction>> {
475 let transfer_ix = self.transfer_authority_ix(TransferAuthorityParams {
476 mint: params.mint,
477 current_update_authority: params.current_update_authority,
478 new_authority: params.new_authority,
479 })?;
480
481 let update_ix = self.update_metadata_ix(UpdateMetadataParams {
482 mint: params.mint,
483 update_authority: params.new_authority,
484 name: params.name,
485 symbol: params.symbol,
486 image: params.image,
487 description: params.description,
488 })?;
489
490 Ok(vec![transfer_ix, update_ix])
491 }
492
493 pub fn transfer_authority_then_update_tx_with_budget(
495 &self,
496 params: TxTransferAuthorityThenUpdateParams,
497 budget: ComputeBudgetOptions,
498 ) -> anyhow::Result<Vec<Instruction>> {
499 let mut out = self.compute_budget_ixs(&budget);
500 out.extend(self.transfer_authority_then_update_tx(params)?);
501 Ok(out)
502 }
503
504 pub fn make_immutable_tx(
506 &self,
507 params: MakeImmutableParams,
508 ) -> anyhow::Result<Vec<Instruction>> {
509 Ok(vec![self.make_immutable_ix(params)?])
510 }
511
512 pub fn make_immutable_tx_with_budget(
514 &self,
515 params: MakeImmutableParams,
516 budget: ComputeBudgetOptions,
517 ) -> anyhow::Result<Vec<Instruction>> {
518 let mut out = self.compute_budget_ixs(&budget);
519 out.extend(self.make_immutable_tx(params)?);
520 Ok(out)
521 }
522
523 pub fn set_compute_unit_limit_ix(&self, units: u32) -> Instruction {
525 ComputeBudgetInstruction::set_compute_unit_limit(units)
526 }
527
528 pub fn request_heap_frame_ix(&self, bytes: u32) -> Instruction {
530 ComputeBudgetInstruction::request_heap_frame(bytes)
531 }
532
533 fn compute_budget_ixs(&self, opts: &ComputeBudgetOptions) -> Vec<Instruction> {
534 let mut out: Vec<Instruction> = Vec::new();
535 if let Some(units) = opts.units {
536 out.push(self.set_compute_unit_limit_ix(units));
537 }
538 if let Some(bytes) = opts.heap_bytes {
539 out.push(self.request_heap_frame_ix(bytes));
540 }
541 out
542 }
543
544 fn validate_metadata_fields(
545 &self,
546 name: &str,
547 symbol: &str,
548 image: &str,
549 description: &str,
550 ) -> anyhow::Result<()> {
551 anyhow::ensure!(name.len() <= NAME_MAX_LEN, "name too long");
552 anyhow::ensure!(symbol.len() <= SYMBOL_MAX_LEN, "symbol too long");
553 anyhow::ensure!(image.len() <= IMAGE_MAX_LEN, "image too long");
554 anyhow::ensure!(
555 description.len() <= DESCRIPTION_MAX_LEN,
556 "description too long"
557 );
558 Ok(())
559 }
560
561 fn validate_optional_metadata_fields(
562 &self,
563 name: Option<&String>,
564 symbol: Option<&String>,
565 image: Option<&String>,
566 description: Option<&String>,
567 ) -> anyhow::Result<()> {
568 if let Some(v) = name {
569 anyhow::ensure!(v.len() <= NAME_MAX_LEN, "name too long");
570 }
571 if let Some(v) = symbol {
572 anyhow::ensure!(v.len() <= SYMBOL_MAX_LEN, "symbol too long");
573 }
574 if let Some(v) = image {
575 anyhow::ensure!(v.len() <= IMAGE_MAX_LEN, "image too long");
576 }
577 if let Some(v) = description {
578 anyhow::ensure!(v.len() <= DESCRIPTION_MAX_LEN, "description too long");
579 }
580 Ok(())
581 }
582
583 fn validate_attributes(&self, data: &[(String, String)]) -> anyhow::Result<()> {
584 anyhow::ensure!(data.len() <= MAX_ATTRIBUTES, "too many attributes");
585 for (k, v) in data.iter() {
586 anyhow::ensure!(
587 !k.is_empty() && !v.is_empty(),
588 "attribute key and value must be non-empty"
589 );
590 anyhow::ensure!(k.len() <= MAX_KEY_LENGTH, "attribute key too long");
591 anyhow::ensure!(v.len() <= MAX_VALUE_LENGTH, "attribute value too long");
592 }
593 Ok(())
594 }
595}
596
597impl Default for TokenMetadataClient {
598 fn default() -> Self {
599 Self {
600 program_id: program::id(),
601 }
602 }
603}
604
605pub fn default_program_id() -> Pubkey {
607 program::id()
608}
609
610pub mod well_known_attributes {
612 pub const TWITTER: &str = "twitter";
613 pub const TELEGRAM: &str = "telegram";
614 pub const WEBSITE: &str = "website";
615 pub const DISCORD: &str = "discord";
616 pub const COINGECKO: &str = "coingecko";
617 pub const WHITEPAPER: &str = "whitepaper";
618 pub const AUDIT: &str = "audit";
619 pub const CATEGORY: &str = "category";
620 pub const TAGS: &str = "tags";
621}
622
623pub struct AccountDataLite {
627 pub data: Vec<u8>,
628 pub owner: Pubkey,
629}
630
631#[async_trait::async_trait]
633pub trait AsyncAccountReader: Send + Sync {
634 async fn get_multiple_accounts(
635 &self,
636 pubkeys: &[Pubkey],
637 ) -> anyhow::Result<Vec<Option<AccountDataLite>>>;
638}
639
640pub struct TokenMetadataReader<R: AsyncAccountReader> {
642 program_id: Pubkey,
643 rpc: R,
644}
645
646impl<R: AsyncAccountReader> TokenMetadataReader<R> {
647 pub fn new(program_id: Pubkey, rpc: R) -> Self {
648 Self { program_id, rpc }
649 }
650
651 fn metadata_pda(&self, mint: &Pubkey) -> Pubkey {
652 let (pda, _bump) = program::find_metadata_pda_with_program(&self.program_id, mint);
653 pda
654 }
655 fn attributes_pda(&self, mint: &Pubkey) -> Pubkey {
656 let (pda, _bump) = program::find_attributes_pda_with_program(&self.program_id, mint);
657 pda
658 }
659
660 fn is_owner_ok(&self, owner: &Pubkey) -> bool {
661 owner == &self.program_id
662 }
663
664 pub async fn get_token_metadata(&self, mint: Pubkey) -> anyhow::Result<Option<TokenMetadata>> {
665 let pda = self.metadata_pda(&mint);
666 let v = self.rpc.get_multiple_accounts(&[pda]).await?.pop().unwrap();
667 let Some(acc) = v else { return Ok(None) };
668 if !self.is_owner_ok(&acc.owner) {
669 return Ok(None);
670 }
671 let md = TokenMetadata::unpack_from_slice(&acc.data).context("unpack TokenMetadata")?;
672 Ok(Some(md))
673 }
674
675 pub async fn get_token_metadata_attributes(
676 &self,
677 mint: Pubkey,
678 ) -> anyhow::Result<Option<TokenMetadataAttributes>> {
679 let pda = self.attributes_pda(&mint);
680 let v = self.rpc.get_multiple_accounts(&[pda]).await?.pop().unwrap();
681 let Some(acc) = v else { return Ok(None) };
682 if !self.is_owner_ok(&acc.owner) {
683 return Ok(None);
684 }
685 let attrs = TokenMetadataAttributes::unpack_from_slice(&acc.data)
686 .context("unpack TokenMetadataAttributes")?;
687 Ok(Some(attrs))
688 }
689
690 pub async fn get_token_details(
691 &self,
692 mint: Pubkey,
693 ) -> anyhow::Result<(Option<TokenMetadata>, Option<TokenMetadataAttributes>)> {
694 let md_pda = self.metadata_pda(&mint);
695 let at_pda = self.attributes_pda(&mint);
696 let res = self.rpc.get_multiple_accounts(&[md_pda, at_pda]).await?;
697 let md_opt = match &res[0] {
698 Some(acc) if self.is_owner_ok(&acc.owner) => {
699 Some(TokenMetadata::unpack_from_slice(&acc.data).context("unpack TokenMetadata")?)
700 }
701 _ => None,
702 };
703 let at_opt = match &res[1] {
704 Some(acc) if self.is_owner_ok(&acc.owner) => Some(
705 TokenMetadataAttributes::unpack_from_slice(&acc.data)
706 .context("unpack TokenMetadataAttributes")?,
707 ),
708 _ => None,
709 };
710 Ok((md_opt, at_opt))
711 }
712
713 pub async fn get_token_metadata_batch(
714 &self,
715 mints: &[Pubkey],
716 ) -> anyhow::Result<Vec<Option<TokenMetadata>>> {
717 let pdas: Vec<Pubkey> = mints.iter().map(|m| self.metadata_pda(m)).collect();
718 let res = self.rpc.get_multiple_accounts(&pdas).await?;
719 let mut out = Vec::with_capacity(res.len());
720 for maybe in res {
721 if let Some(acc) = maybe {
722 if self.is_owner_ok(&acc.owner) {
723 let md = TokenMetadata::unpack_from_slice(&acc.data)
724 .context("unpack TokenMetadata")?;
725 out.push(Some(md));
726 continue;
727 }
728 }
729 out.push(None);
730 }
731 Ok(out)
732 }
733
734 pub async fn get_token_metadata_attributes_batch(
735 &self,
736 mints: &[Pubkey],
737 ) -> anyhow::Result<Vec<Option<TokenMetadataAttributes>>> {
738 let pdas: Vec<Pubkey> = mints.iter().map(|m| self.attributes_pda(m)).collect();
739 let res = self.rpc.get_multiple_accounts(&pdas).await?;
740 let mut out = Vec::with_capacity(res.len());
741 for maybe in res {
742 if let Some(acc) = maybe {
743 if self.is_owner_ok(&acc.owner) {
744 let attrs = TokenMetadataAttributes::unpack_from_slice(&acc.data)
745 .context("unpack TokenMetadataAttributes")?;
746 out.push(Some(attrs));
747 continue;
748 }
749 }
750 out.push(None);
751 }
752 Ok(out)
753 }
754}
755
756#[async_trait::async_trait]
758impl AsyncAccountReader for arch_sdk::AsyncArchRpcClient {
759 async fn get_multiple_accounts(
760 &self,
761 pubkeys: &[Pubkey],
762 ) -> anyhow::Result<Vec<Option<AccountDataLite>>> {
763 let mut out: Vec<Option<AccountDataLite>> = Vec::with_capacity(pubkeys.len());
764 for pk in pubkeys.iter() {
765 match self.read_account_info(*pk).await {
766 Ok(info) => {
767 out.push(Some(AccountDataLite {
768 data: info.data,
769 owner: info.owner,
770 }));
771 }
772 Err(_e) => {
773 out.push(None);
775 }
776 }
777 }
778 Ok(out)
779 }
780}
781
782#[derive(Clone, Debug)]
785pub struct CreateMetadataParams {
786 pub payer: Pubkey,
788 pub mint: Pubkey,
790 pub mint_or_freeze_authority: Pubkey,
792 pub name: String,
794 pub symbol: String,
796 pub image: String,
798 pub description: String,
800 pub immutable: bool,
802}
803
804#[derive(Clone, Debug)]
806pub struct UpdateMetadataParams {
807 pub mint: Pubkey,
809 pub update_authority: Pubkey,
811 pub name: Option<String>,
813 pub symbol: Option<String>,
815 pub image: Option<String>,
817 pub description: Option<String>,
819}
820
821#[derive(Clone, Debug)]
823pub struct CreateAttributesParams {
824 pub payer: Pubkey,
826 pub mint: Pubkey,
828 pub update_authority: Pubkey,
830 pub data: Vec<(String, String)>,
832}
833
834#[derive(Clone, Debug)]
836pub struct ReplaceAttributesParams {
837 pub mint: Pubkey,
839 pub update_authority: Pubkey,
841 pub data: Vec<(String, String)>,
843}
844
845#[derive(Clone, Debug)]
847pub struct TransferAuthorityParams {
848 pub mint: Pubkey,
850 pub current_update_authority: Pubkey,
852 pub new_authority: Pubkey,
854}
855
856#[derive(Clone, Debug)]
858pub struct MakeImmutableParams {
859 pub mint: Pubkey,
861 pub current_update_authority: Pubkey,
863}
864
865#[derive(Clone, Debug)]
867pub struct TxCreateTokenWithMetadataParams {
868 pub payer: Pubkey,
870 pub mint: Pubkey,
872 pub mint_authority: Pubkey,
874 pub freeze_authority: Option<Pubkey>,
876 pub decimals: u8,
878 pub name: String,
880 pub symbol: String,
882 pub image: String,
884 pub description: String,
886 pub immutable: bool,
888}
889
890#[derive(Clone, Debug)]
892pub struct TxCreateTokenWithMetadataAndAttributesParams {
893 pub payer: Pubkey,
895 pub mint: Pubkey,
897 pub mint_authority: Pubkey,
899 pub freeze_authority: Option<Pubkey>,
901 pub decimals: u8,
903 pub name: String,
905 pub symbol: String,
906 pub image: String,
907 pub description: String,
908 pub immutable: bool,
909 pub attributes: Vec<(String, String)>,
911}
912
913#[derive(Clone, Debug)]
915pub struct TxCreateTokenWithFreezeAuthMetadataParams {
916 pub payer: Pubkey,
918 pub mint: Pubkey,
920 pub initial_mint_authority: Pubkey,
922 pub freeze_authority: Pubkey,
924 pub decimals: u8,
926 pub name: String,
928 pub symbol: String,
929 pub image: String,
930 pub description: String,
931 pub immutable: bool,
932}
933
934#[derive(Clone, Debug)]
936pub struct TxTransferAuthorityThenUpdateParams {
937 pub mint: Pubkey,
939 pub current_update_authority: Pubkey,
941 pub new_authority: Pubkey,
943 pub name: Option<String>,
945 pub symbol: Option<String>,
946 pub image: Option<String>,
947 pub description: Option<String>,
948}
949
950#[derive(Clone, Copy, Debug, Default)]
952pub struct ComputeBudgetOptions {
953 pub units: Option<u32>,
955 pub heap_bytes: Option<u32>,
957}