metaboss_lib/transfer/
mod.rs1use anyhow::Result;
2use mpl_token_metadata::{
3 instructions::TransferV1Builder,
4 types::{AuthorizationData, ProgrammableConfig, TokenStandard},
5};
6use solana_client::rpc_client::RpcClient;
7use solana_sdk::{
8 signature::{Keypair, Signature},
9 signer::Signer,
10};
11
12use crate::{data::Asset, decode::ToPubkey, transaction::send_and_confirm_tx};
13
14pub enum TransferAssetArgs<'a, P: ToPubkey> {
15 V1 {
16 payer: Option<&'a Keypair>,
17 authority: &'a Keypair,
18 mint: P,
19 source_owner: P,
20 source_token: P,
21 destination_owner: P,
22 destination_token: P,
23 amount: u64,
24 authorization_data: Option<AuthorizationData>,
25 },
26}
27
28pub fn transfer_asset<P: ToPubkey>(
29 client: &RpcClient,
30 args: TransferAssetArgs<P>,
31) -> Result<Signature> {
32 match args {
33 TransferAssetArgs::V1 { .. } => transfer_asset_v1(client, args),
34 }
35}
36
37fn transfer_asset_v1<P: ToPubkey>(
38 client: &RpcClient,
39 args: TransferAssetArgs<P>,
40) -> Result<Signature> {
41 let TransferAssetArgs::V1 {
42 payer,
43 authority,
44 mint,
45 source_owner,
46 source_token,
47 destination_owner,
48 destination_token,
49 amount,
50 authorization_data,
51 } = args;
52
53 let mint = mint.to_pubkey()?;
54 let source_owner = source_owner.to_pubkey()?;
55 let source_token = source_token.to_pubkey()?;
56 let destination_owner = destination_owner.to_pubkey()?;
57 let destination_token = destination_token.to_pubkey()?;
58
59 let mut asset = Asset::new(mint);
60 let payer = payer.unwrap_or(authority);
61
62 let mut transfer_builder = TransferV1Builder::new();
63 transfer_builder
64 .payer(payer.pubkey())
65 .authority(authority.pubkey())
66 .token(source_token)
67 .token_owner(source_owner)
68 .destination_token(destination_token)
69 .destination_owner(destination_owner)
70 .mint(asset.mint)
71 .metadata(asset.metadata)
72 .amount(amount);
73
74 if let Some(data) = authorization_data {
75 transfer_builder.authorization_data(data);
76 }
77
78 let md = asset.get_metadata(client)?;
79
80 if matches!(
81 md.token_standard,
82 Some(TokenStandard::ProgrammableNonFungible)
83 ) {
84 let source_token_record = asset.get_token_record(&source_token);
86 let destination_token_record = asset.get_token_record(&destination_token);
87 transfer_builder
88 .token_record(Some(source_token_record))
89 .destination_token_record(Some(destination_token_record));
90
91 if let Some(ProgrammableConfig::V1 {
94 rule_set: Some(auth_rules),
95 }) = md.programmable_config
96 {
97 transfer_builder.authorization_rules_program(Some(mpl_token_auth_rules::ID));
98 transfer_builder.authorization_rules(Some(auth_rules));
99 }
100 }
101
102 if matches!(
103 md.token_standard,
104 Some(
105 TokenStandard::NonFungible
106 | TokenStandard::NonFungibleEdition
107 | TokenStandard::ProgrammableNonFungible
108 ) | None
109 ) {
110 asset.add_edition();
111 transfer_builder.edition(asset.edition);
112 }
113
114 let transfer_ix = transfer_builder.instruction();
115
116 send_and_confirm_tx(client, &[payer, authority], &[transfer_ix])
117}