metadata.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. use anchor_lang::context::CpiContext;
  2. use anchor_lang::{Accounts, Result, ToAccountInfos};
  3. use mpl_token_metadata::state::{CollectionDetails, DataV2, TokenMetadataAccount};
  4. use mpl_token_metadata::ID;
  5. use solana_program::account_info::AccountInfo;
  6. use solana_program::pubkey::Pubkey;
  7. use std::ops::Deref;
  8. pub fn create_metadata_accounts_v2<'info>(
  9. ctx: CpiContext<'_, '_, '_, 'info, CreateMetadataAccountsV2<'info>>,
  10. data: DataV2,
  11. is_mutable: bool,
  12. update_authority_is_signer: bool,
  13. ) -> Result<()> {
  14. let DataV2 {
  15. name,
  16. symbol,
  17. uri,
  18. creators,
  19. seller_fee_basis_points,
  20. collection,
  21. uses,
  22. } = data;
  23. let ix = mpl_token_metadata::instruction::create_metadata_accounts_v2(
  24. ID,
  25. *ctx.accounts.metadata.key,
  26. *ctx.accounts.mint.key,
  27. *ctx.accounts.mint_authority.key,
  28. *ctx.accounts.payer.key,
  29. *ctx.accounts.update_authority.key,
  30. name,
  31. symbol,
  32. uri,
  33. creators,
  34. seller_fee_basis_points,
  35. update_authority_is_signer,
  36. is_mutable,
  37. collection,
  38. uses,
  39. );
  40. solana_program::program::invoke_signed(
  41. &ix,
  42. &ToAccountInfos::to_account_infos(&ctx),
  43. ctx.signer_seeds,
  44. )
  45. .map_err(Into::into)
  46. }
  47. pub fn create_metadata_accounts_v3<'info>(
  48. ctx: CpiContext<'_, '_, '_, 'info, CreateMetadataAccountsV3<'info>>,
  49. data: DataV2,
  50. is_mutable: bool,
  51. update_authority_is_signer: bool,
  52. details: Option<CollectionDetails>,
  53. ) -> Result<()> {
  54. let DataV2 {
  55. name,
  56. symbol,
  57. uri,
  58. creators,
  59. seller_fee_basis_points,
  60. collection,
  61. uses,
  62. } = data;
  63. let ix = mpl_token_metadata::instruction::create_metadata_accounts_v3(
  64. ID,
  65. *ctx.accounts.metadata.key,
  66. *ctx.accounts.mint.key,
  67. *ctx.accounts.mint_authority.key,
  68. *ctx.accounts.payer.key,
  69. *ctx.accounts.update_authority.key,
  70. name,
  71. symbol,
  72. uri,
  73. creators,
  74. seller_fee_basis_points,
  75. update_authority_is_signer,
  76. is_mutable,
  77. collection,
  78. uses,
  79. details,
  80. );
  81. solana_program::program::invoke_signed(
  82. &ix,
  83. &ToAccountInfos::to_account_infos(&ctx),
  84. ctx.signer_seeds,
  85. )
  86. .map_err(Into::into)
  87. }
  88. pub fn update_metadata_accounts_v2<'info>(
  89. ctx: CpiContext<'_, '_, '_, 'info, UpdateMetadataAccountsV2<'info>>,
  90. new_update_authority: Option<Pubkey>,
  91. data: Option<DataV2>,
  92. primary_sale_happened: Option<bool>,
  93. is_mutable: Option<bool>,
  94. ) -> Result<()> {
  95. let ix = mpl_token_metadata::instruction::update_metadata_accounts_v2(
  96. ID,
  97. *ctx.accounts.metadata.key,
  98. *ctx.accounts.update_authority.key,
  99. new_update_authority,
  100. data,
  101. primary_sale_happened,
  102. is_mutable,
  103. );
  104. solana_program::program::invoke_signed(
  105. &ix,
  106. &ToAccountInfos::to_account_infos(&ctx),
  107. ctx.signer_seeds,
  108. )
  109. .map_err(Into::into)
  110. }
  111. pub fn create_master_edition_v3<'info>(
  112. ctx: CpiContext<'_, '_, '_, 'info, CreateMasterEditionV3<'info>>,
  113. max_supply: Option<u64>,
  114. ) -> Result<()> {
  115. let ix = mpl_token_metadata::instruction::create_master_edition_v3(
  116. ID,
  117. *ctx.accounts.edition.key,
  118. *ctx.accounts.mint.key,
  119. *ctx.accounts.update_authority.key,
  120. *ctx.accounts.mint_authority.key,
  121. *ctx.accounts.metadata.key,
  122. *ctx.accounts.payer.key,
  123. max_supply,
  124. );
  125. solana_program::program::invoke_signed(
  126. &ix,
  127. &ToAccountInfos::to_account_infos(&ctx),
  128. ctx.signer_seeds,
  129. )
  130. .map_err(Into::into)
  131. }
  132. pub fn mint_new_edition_from_master_edition_via_token<'info>(
  133. ctx: CpiContext<'_, '_, '_, 'info, MintNewEditionFromMasterEditionViaToken<'info>>,
  134. edition: u64,
  135. ) -> Result<()> {
  136. let ix = mpl_token_metadata::instruction::mint_new_edition_from_master_edition_via_token(
  137. ID,
  138. *ctx.accounts.new_metadata.key,
  139. *ctx.accounts.new_edition.key,
  140. *ctx.accounts.master_edition.key,
  141. *ctx.accounts.new_mint.key,
  142. *ctx.accounts.new_mint_authority.key,
  143. *ctx.accounts.payer.key,
  144. *ctx.accounts.token_account_owner.key,
  145. *ctx.accounts.token_account.key,
  146. *ctx.accounts.new_metadata_update_authority.key,
  147. *ctx.accounts.metadata.key,
  148. *ctx.accounts.metadata_mint.key,
  149. edition,
  150. );
  151. solana_program::program::invoke_signed(
  152. &ix,
  153. &ToAccountInfos::to_account_infos(&ctx),
  154. ctx.signer_seeds,
  155. )
  156. .map_err(Into::into)
  157. }
  158. pub fn set_collection_size<'info>(
  159. ctx: CpiContext<'_, '_, '_, 'info, SetCollectionSize<'info>>,
  160. collection_authority_record: Option<Pubkey>,
  161. size: u64,
  162. ) -> Result<()> {
  163. let ix = mpl_token_metadata::instruction::set_collection_size(
  164. ID,
  165. *ctx.accounts.metadata.key,
  166. *ctx.accounts.update_authority.key,
  167. *ctx.accounts.mint.key,
  168. collection_authority_record,
  169. size,
  170. );
  171. solana_program::program::invoke_signed(
  172. &ix,
  173. &ToAccountInfos::to_account_infos(&ctx),
  174. ctx.signer_seeds,
  175. )
  176. .map_err(Into::into)
  177. }
  178. pub fn verify_collection<'info>(
  179. ctx: CpiContext<'_, '_, '_, 'info, VerifyCollection<'info>>,
  180. collection_authority_record: Option<Pubkey>,
  181. ) -> Result<()> {
  182. let ix = mpl_token_metadata::instruction::verify_collection(
  183. ID,
  184. *ctx.accounts.metadata.key,
  185. *ctx.accounts.collection_authority.key,
  186. *ctx.accounts.payer.key,
  187. *ctx.accounts.collection_mint.key,
  188. *ctx.accounts.collection_metadata.key,
  189. *ctx.accounts.collection_master_edition.key,
  190. collection_authority_record,
  191. );
  192. solana_program::program::invoke_signed(
  193. &ix,
  194. &ToAccountInfos::to_account_infos(&ctx),
  195. ctx.signer_seeds,
  196. )
  197. .map_err(Into::into)
  198. }
  199. pub fn verify_sized_collection_item<'info>(
  200. ctx: CpiContext<'_, '_, '_, 'info, VerifySizedCollectionItem<'info>>,
  201. collection_authority_record: Option<Pubkey>,
  202. ) -> Result<()> {
  203. let ix = mpl_token_metadata::instruction::verify_sized_collection_item(
  204. ID,
  205. *ctx.accounts.metadata.key,
  206. *ctx.accounts.collection_authority.key,
  207. *ctx.accounts.payer.key,
  208. *ctx.accounts.collection_mint.key,
  209. *ctx.accounts.collection_metadata.key,
  210. *ctx.accounts.collection_master_edition.key,
  211. collection_authority_record,
  212. );
  213. solana_program::program::invoke_signed(
  214. &ix,
  215. &ToAccountInfos::to_account_infos(&ctx),
  216. ctx.signer_seeds,
  217. )
  218. .map_err(Into::into)
  219. }
  220. pub fn set_and_verify_collection<'info>(
  221. ctx: CpiContext<'_, '_, '_, 'info, SetAndVerifyCollection<'info>>,
  222. collection_authority_record: Option<Pubkey>,
  223. ) -> Result<()> {
  224. let ix = mpl_token_metadata::instruction::set_and_verify_collection(
  225. ID,
  226. *ctx.accounts.metadata.key,
  227. *ctx.accounts.collection_authority.key,
  228. *ctx.accounts.payer.key,
  229. *ctx.accounts.update_authority.key,
  230. *ctx.accounts.collection_mint.key,
  231. *ctx.accounts.collection_metadata.key,
  232. *ctx.accounts.collection_master_edition.key,
  233. collection_authority_record,
  234. );
  235. solana_program::program::invoke_signed(
  236. &ix,
  237. &ToAccountInfos::to_account_infos(&ctx),
  238. ctx.signer_seeds,
  239. )
  240. .map_err(Into::into)
  241. }
  242. pub fn set_and_verify_sized_collection_item<'info>(
  243. ctx: CpiContext<'_, '_, '_, 'info, SetAndVerifySizedCollectionItem<'info>>,
  244. collection_authority_record: Option<Pubkey>,
  245. ) -> Result<()> {
  246. let ix = mpl_token_metadata::instruction::set_and_verify_sized_collection_item(
  247. ID,
  248. *ctx.accounts.metadata.key,
  249. *ctx.accounts.collection_authority.key,
  250. *ctx.accounts.payer.key,
  251. *ctx.accounts.update_authority.key,
  252. *ctx.accounts.collection_mint.key,
  253. *ctx.accounts.collection_metadata.key,
  254. *ctx.accounts.collection_master_edition.key,
  255. collection_authority_record,
  256. );
  257. solana_program::program::invoke_signed(
  258. &ix,
  259. &ToAccountInfos::to_account_infos(&ctx),
  260. ctx.signer_seeds,
  261. )
  262. .map_err(Into::into)
  263. }
  264. pub fn freeze_delegated_account<'info>(
  265. ctx: CpiContext<'_, '_, '_, 'info, FreezeDelegatedAccount<'info>>,
  266. ) -> Result<()> {
  267. let ix = mpl_token_metadata::instruction::freeze_delegated_account(
  268. ID,
  269. *ctx.accounts.delegate.key,
  270. *ctx.accounts.token_account.key,
  271. *ctx.accounts.edition.key,
  272. *ctx.accounts.mint.key,
  273. );
  274. solana_program::program::invoke_signed(
  275. &ix,
  276. &ToAccountInfos::to_account_infos(&ctx),
  277. ctx.signer_seeds,
  278. )
  279. .map_err(Into::into)
  280. }
  281. pub fn thaw_delegated_account<'info>(
  282. ctx: CpiContext<'_, '_, '_, 'info, ThawDelegatedAccount<'info>>,
  283. ) -> Result<()> {
  284. let ix = mpl_token_metadata::instruction::thaw_delegated_account(
  285. ID,
  286. *ctx.accounts.delegate.key,
  287. *ctx.accounts.token_account.key,
  288. *ctx.accounts.edition.key,
  289. *ctx.accounts.mint.key,
  290. );
  291. solana_program::program::invoke_signed(
  292. &ix,
  293. &ToAccountInfos::to_account_infos(&ctx),
  294. ctx.signer_seeds,
  295. )
  296. .map_err(Into::into)
  297. }
  298. pub fn update_primary_sale_happened_via_token<'info>(
  299. ctx: CpiContext<'_, '_, '_, 'info, UpdatePrimarySaleHappenedViaToken<'info>>,
  300. ) -> Result<()> {
  301. let ix = mpl_token_metadata::instruction::update_primary_sale_happened_via_token(
  302. ID,
  303. *ctx.accounts.metadata.key,
  304. *ctx.accounts.owner.key,
  305. *ctx.accounts.token.key,
  306. );
  307. solana_program::program::invoke_signed(
  308. &ix,
  309. &ToAccountInfos::to_account_infos(&ctx),
  310. ctx.signer_seeds,
  311. )?;
  312. Ok(())
  313. }
  314. pub fn sign_metadata<'info>(ctx: CpiContext<'_, '_, '_, 'info, SignMetadata<'info>>) -> Result<()> {
  315. let ix = mpl_token_metadata::instruction::sign_metadata(
  316. ID,
  317. *ctx.accounts.metadata.key,
  318. *ctx.accounts.creator.key,
  319. );
  320. solana_program::program::invoke_signed(
  321. &ix,
  322. &ToAccountInfos::to_account_infos(&ctx),
  323. ctx.signer_seeds,
  324. )?;
  325. Ok(())
  326. }
  327. pub fn remove_creator_verification<'info>(
  328. ctx: CpiContext<'_, '_, '_, 'info, RemoveCreatorVerification<'info>>,
  329. ) -> Result<()> {
  330. let ix = mpl_token_metadata::instruction::remove_creator_verification(
  331. ID,
  332. *ctx.accounts.metadata.key,
  333. *ctx.accounts.creator.key,
  334. );
  335. solana_program::program::invoke_signed(
  336. &ix,
  337. &ToAccountInfos::to_account_infos(&ctx),
  338. ctx.signer_seeds,
  339. )?;
  340. Ok(())
  341. }
  342. #[derive(Accounts)]
  343. pub struct CreateMetadataAccountsV2<'info> {
  344. pub metadata: AccountInfo<'info>,
  345. pub mint: AccountInfo<'info>,
  346. pub mint_authority: AccountInfo<'info>,
  347. pub payer: AccountInfo<'info>,
  348. pub update_authority: AccountInfo<'info>,
  349. pub system_program: AccountInfo<'info>,
  350. pub rent: AccountInfo<'info>,
  351. }
  352. #[derive(Accounts)]
  353. pub struct CreateMetadataAccountsV3<'info> {
  354. pub metadata: AccountInfo<'info>,
  355. pub mint: AccountInfo<'info>,
  356. pub mint_authority: AccountInfo<'info>,
  357. pub payer: AccountInfo<'info>,
  358. pub update_authority: AccountInfo<'info>,
  359. pub system_program: AccountInfo<'info>,
  360. pub rent: AccountInfo<'info>,
  361. }
  362. #[derive(Accounts)]
  363. pub struct UpdateMetadataAccountsV2<'info> {
  364. pub metadata: AccountInfo<'info>,
  365. pub update_authority: AccountInfo<'info>,
  366. }
  367. #[derive(Accounts)]
  368. pub struct CreateMasterEditionV3<'info> {
  369. pub edition: AccountInfo<'info>,
  370. pub mint: AccountInfo<'info>,
  371. pub update_authority: AccountInfo<'info>,
  372. pub mint_authority: AccountInfo<'info>,
  373. pub payer: AccountInfo<'info>,
  374. pub metadata: AccountInfo<'info>,
  375. pub token_program: AccountInfo<'info>,
  376. pub system_program: AccountInfo<'info>,
  377. pub rent: AccountInfo<'info>,
  378. }
  379. #[derive(Accounts)]
  380. pub struct MintNewEditionFromMasterEditionViaToken<'info> {
  381. pub new_metadata: AccountInfo<'info>,
  382. pub new_edition: AccountInfo<'info>,
  383. pub master_edition: AccountInfo<'info>,
  384. pub new_mint: AccountInfo<'info>,
  385. pub edition_mark_pda: AccountInfo<'info>,
  386. pub new_mint_authority: AccountInfo<'info>,
  387. pub payer: AccountInfo<'info>,
  388. pub token_account_owner: AccountInfo<'info>,
  389. pub token_account: AccountInfo<'info>,
  390. pub new_metadata_update_authority: AccountInfo<'info>,
  391. pub metadata: AccountInfo<'info>,
  392. pub token_program: AccountInfo<'info>,
  393. pub system_program: AccountInfo<'info>,
  394. pub rent: AccountInfo<'info>,
  395. //
  396. // Not actually used by the program but still needed because it's needed
  397. // for the pda calculation in the helper. :/
  398. //
  399. // The better thing to do would be to remove this and have the instruction
  400. // helper pass in the `edition_mark_pda` directly.
  401. //
  402. pub metadata_mint: AccountInfo<'info>,
  403. }
  404. #[derive(Accounts)]
  405. pub struct SetCollectionSize<'info> {
  406. pub metadata: AccountInfo<'info>,
  407. pub mint: AccountInfo<'info>,
  408. pub update_authority: AccountInfo<'info>,
  409. pub system_program: AccountInfo<'info>,
  410. }
  411. #[derive(Accounts)]
  412. pub struct VerifyCollection<'info> {
  413. pub payer: AccountInfo<'info>,
  414. pub metadata: AccountInfo<'info>,
  415. pub collection_authority: AccountInfo<'info>,
  416. pub collection_mint: AccountInfo<'info>,
  417. pub collection_metadata: AccountInfo<'info>,
  418. pub collection_master_edition: AccountInfo<'info>,
  419. }
  420. #[derive(Accounts)]
  421. pub struct VerifySizedCollectionItem<'info> {
  422. pub payer: AccountInfo<'info>,
  423. pub metadata: AccountInfo<'info>,
  424. pub collection_authority: AccountInfo<'info>,
  425. pub collection_mint: AccountInfo<'info>,
  426. pub collection_metadata: AccountInfo<'info>,
  427. pub collection_master_edition: AccountInfo<'info>,
  428. }
  429. #[derive(Accounts)]
  430. pub struct SetAndVerifyCollection<'info> {
  431. pub metadata: AccountInfo<'info>,
  432. pub collection_authority: AccountInfo<'info>,
  433. pub payer: AccountInfo<'info>,
  434. pub update_authority: AccountInfo<'info>,
  435. pub collection_mint: AccountInfo<'info>,
  436. pub collection_metadata: AccountInfo<'info>,
  437. pub collection_master_edition: AccountInfo<'info>,
  438. }
  439. #[derive(Accounts)]
  440. pub struct SetAndVerifySizedCollectionItem<'info> {
  441. pub metadata: AccountInfo<'info>,
  442. pub collection_authority: AccountInfo<'info>,
  443. pub payer: AccountInfo<'info>,
  444. pub update_authority: AccountInfo<'info>,
  445. pub collection_mint: AccountInfo<'info>,
  446. pub collection_metadata: AccountInfo<'info>,
  447. pub collection_master_edition: AccountInfo<'info>,
  448. }
  449. #[derive(Accounts)]
  450. pub struct FreezeDelegatedAccount<'info> {
  451. pub metadata: AccountInfo<'info>,
  452. pub delegate: AccountInfo<'info>,
  453. pub token_account: AccountInfo<'info>,
  454. pub edition: AccountInfo<'info>,
  455. pub mint: AccountInfo<'info>,
  456. pub token_program: AccountInfo<'info>,
  457. }
  458. #[derive(Accounts)]
  459. pub struct ThawDelegatedAccount<'info> {
  460. pub metadata: AccountInfo<'info>,
  461. pub delegate: AccountInfo<'info>,
  462. pub token_account: AccountInfo<'info>,
  463. pub edition: AccountInfo<'info>,
  464. pub mint: AccountInfo<'info>,
  465. pub token_program: AccountInfo<'info>,
  466. }
  467. #[derive(Accounts)]
  468. pub struct UpdatePrimarySaleHappenedViaToken<'info> {
  469. pub metadata: AccountInfo<'info>,
  470. pub owner: AccountInfo<'info>,
  471. pub token: AccountInfo<'info>,
  472. }
  473. #[derive(Accounts)]
  474. pub struct SignMetadata<'info> {
  475. pub creator: AccountInfo<'info>,
  476. pub metadata: AccountInfo<'info>,
  477. }
  478. #[derive(Accounts)]
  479. pub struct RemoveCreatorVerification<'info> {
  480. pub creator: AccountInfo<'info>,
  481. pub metadata: AccountInfo<'info>,
  482. }
  483. #[derive(Clone, Debug, PartialEq)]
  484. pub struct MetadataAccount(mpl_token_metadata::state::Metadata);
  485. impl MetadataAccount {
  486. pub const LEN: usize = mpl_token_metadata::state::MAX_METADATA_LEN;
  487. }
  488. impl anchor_lang::AccountDeserialize for MetadataAccount {
  489. fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result<Self> {
  490. let result = mpl_token_metadata::state::Metadata::safe_deserialize(buf)?;
  491. Ok(MetadataAccount(result))
  492. }
  493. }
  494. impl anchor_lang::AccountSerialize for MetadataAccount {}
  495. impl anchor_lang::Owner for MetadataAccount {
  496. fn owner() -> Pubkey {
  497. ID
  498. }
  499. }
  500. impl Deref for MetadataAccount {
  501. type Target = mpl_token_metadata::state::Metadata;
  502. fn deref(&self) -> &Self::Target {
  503. &self.0
  504. }
  505. }
  506. #[derive(Clone)]
  507. pub struct Metadata;
  508. impl anchor_lang::Id for Metadata {
  509. fn id() -> Pubkey {
  510. ID
  511. }
  512. }