Skip to main content

sealevel_tools/cpi/token_program/
transfer.rs

1#[cfg(feature = "alloc")]
2use alloc::vec;
3
4use crate::{
5    cpi::{CpiAuthority, CpiInstruction},
6    entrypoint::{NoStdAccountInfo, ProgramResult},
7    pubkey::Pubkey,
8};
9
10/// If "alloc" feature is disabled, only this maximum number of additional accounts can be passed
11/// into [Transfer] (panics) and [TransferChecked] (returns [Err]).
12pub const MAX_ADDITIONAL_ACCOUNTS_NOALLOC: usize = 12;
13
14/// Arguments for the transfer instruction on the specified Token program, which moves a specified
15/// amount of tokens from the source to destination token account.
16///
17/// ### Notes
18///
19/// When [TransferChecked] is used, the transfer checked instruction is invoked. Otherwise the
20/// old transfer instruction (which is marked as deprecated) will be used.
21///
22/// Also, do not be fooled by the suffix of this function (because all of the invoke methods are
23/// suffixed with "unchecked" to indicate a distinction between this library's way of performing CPI
24/// calls vs the way found in [solana_cpi::invoke_signed]).
25///
26/// There is another method called [TransferChecked], which specifically handles invoking the
27/// transfer checked instruction. It will perform a length check on the additional accounts if the
28/// "alloc" feature is disabled (and will error out if it exceeds
29/// [MAX_ADDITIONAL_ACCOUNTS_NOALLOC]).
30///
31/// ### Examples
32///
33/// ```
34/// use sealevel_tools::{
35///     account_info::{
36///         try_next_enumerated_account, Authority, AccountInfoConstraints,
37///         WritableTokenProgramAccount, WritableAccount,
38///     },
39///     cpi::token_program as token_program_cpi,
40///     entrypoint::{NoStdAccountInfo, ProgramResult},
41///     pubkey::Pubkey,
42/// };
43///
44/// sealevel_tools::declare_id!("Examp1eTokenManagement1111111111111111111111");
45///
46/// pub fn transfer(accounts: &[NoStdAccountInfo], amount: u64) -> ProgramResult {
47///     let mut accounts_iter = accounts.iter().enumerate();
48///
49///     // First account is the source token account. We don't care to deserialize the token
50///     // account.
51///     let (_, source_account) = try_next_enumerated_account::<WritableTokenProgramAccount>(
52///         &mut accounts_iter,
53///         Default::default(),
54///     )?;
55///
56///     let token_program_id = source_account.owner();
57///
58///     // Second account is the destination token account. No need to check whether this account
59///     // belongs to a Token program because we enforce the Token program ID from the source
60///     // account.
61///     let (_, destination_account) =
62///         try_next_enumerated_account::<WritableAccount>(&mut accounts_iter, Default::default())?;
63///
64///     // Third account is the authority, which should have been delegated by the owner of the
65///     // source account.
66///     let (_, authority) =
67///         try_next_enumerated_account::<Authority>(&mut accounts_iter, Default::default())?;
68///
69///     token_program_cpi::Transfer {
70///         token_program_id,
71///         source: &source_account,
72///         destination: &destination_account,
73///         authority: authority.as_cpi_authority(),
74///         amount,
75///         checked: None,
76///     }
77///     .into_invoke();
78///
79///     Ok(())
80/// }
81/// ```
82///
83/// Use [UseTransferChecked] to perform a transfer checked instruction.
84///
85/// ```
86/// use sealevel_tools::{
87///     account_info::{
88///         try_next_enumerated_account, Authority, AccountInfoConstraints, ReadonlyAccount,
89///         WritableTokenProgramAccount, WritableAccount,
90///     },
91///     cpi::token_program as token_program_cpi,
92///     entrypoint::{NoStdAccountInfo, ProgramResult},
93///     pubkey::Pubkey,
94/// };
95///
96/// sealevel_tools::declare_id!("Examp1eTokenManagement1111111111111111111111");
97///
98/// pub fn transfer_checked(
99///     accounts: &[NoStdAccountInfo],
100///     amount: u64,
101///     decimals: u8
102/// ) -> ProgramResult {
103///     let mut accounts_iter = accounts.iter().enumerate();
104///
105///     // First account is the source token account. We don't care to deserialize the token
106///     // account.
107///     let (_, source_account) = try_next_enumerated_account::<WritableTokenProgramAccount>(
108///         &mut accounts_iter,
109///         Default::default(),
110///     )?;
111///
112///     let token_program_id = source_account.owner();
113///
114///     // Second account is the destination token account. No need to check whether this account
115///     // belongs to a Token program because we enforce the Token program ID from the source
116///     // account.
117///     let (_, destination_account) =
118///         try_next_enumerated_account::<WritableAccount>(&mut accounts_iter, Default::default())?;
119///
120///     // Third account is the authority, which should have been delegated by the owner of the
121///     // source account.
122///     let (_, authority) =
123///         try_next_enumerated_account::<Authority>(&mut accounts_iter, Default::default())?;
124///
125///     // Fourth account is the mint. No need to check whether this account belongs to a Token
126///     // program because we enforce the Token program ID from the source account.
127///     //
128///     // Save the index to pass in remaining accounts.
129///     let (index, mint_account) =
130///         try_next_enumerated_account::<ReadonlyAccount>(&mut accounts_iter, Default::default())?;
131///
132///     token_program_cpi::Transfer {
133///         token_program_id,
134///         source: &source_account,
135///         destination: &destination_account,
136///         authority: authority.as_cpi_authority(),
137///         amount,
138///         checked: Some(token_program_cpi::UseTransferChecked {
139///             mint: &mint_account,
140///             decimals,
141///             additional_accounts: Some(&accounts[index..]),
142///         }),
143///     }
144///     .into_invoke();
145///
146///     Ok(())
147/// }
148/// ```
149#[derive(Clone, PartialEq, Eq)]
150pub struct Transfer<'a, 'b: 'a> {
151    pub token_program_id: &'a Pubkey,
152    pub source: &'b NoStdAccountInfo,
153    pub destination: &'b NoStdAccountInfo,
154
155    /// Either the owner or delegated authority of the source token account.
156    pub authority: CpiAuthority<'a, 'b>,
157    pub amount: u64,
158
159    /// If [Some], the transfer checked instruction will be used instead of the deprecated transfer
160    /// instruction. See [UseTransferChecked] for more information about its usage.
161    pub checked: Option<UseTransferChecked<'b>>,
162}
163
164/// Optional arguments for [Transfer], which enables the transfer checked instruction instead of the
165/// deprecated transfer instruction.
166#[derive(Clone, PartialEq, Eq)]
167pub struct UseTransferChecked<'a> {
168    pub mint: &'a NoStdAccountInfo,
169    pub decimals: u8,
170
171    /// These additional accounts apply to the transfer checked instruction on the Token Extensions
172    /// program. Examples of these accounts may include signers of the multisig extension or
173    /// accounts needed for transfer hook CPI (which is performed by the Token Extensions program).
174    ///
175    /// ### Notes
176    ///
177    /// If the "alloc" feature is disabled, only a max number specified by
178    /// [MAX_ADDITIONAL_ACCOUNTS_NOALLOC] can be passed in and will panic if more are passed into
179    /// [Transfer].
180    ///
181    /// If additional accounts happen to be passed in for a transfer checked call to the
182    /// legacy Token program, the program will disregard these accounts when performing CPI.
183    pub additional_accounts: Option<&'a [NoStdAccountInfo]>,
184}
185
186impl<'a, 'b: 'a> Transfer<'a, 'b> {
187    /// Consume arguments to perform CPI call.
188    #[inline(always)]
189    pub fn into_invoke(self) {
190        let Self {
191            token_program_id,
192            source,
193            destination,
194            authority,
195            amount,
196            checked,
197        } = self;
198
199        match checked {
200            Some(checked) => _invoke_transfer_checked(
201                token_program_id,
202                source,
203                destination,
204                &authority,
205                amount,
206                checked,
207            ),
208            None => _invoke_transfer(token_program_id, source, destination, &authority, amount),
209        }
210    }
211}
212
213/// Arguments for the transfer checked instruction on the specified Token program, which moves
214/// a specified amount of tokens from the source to destination token account only if the specified
215/// decimals agree with the decimals encoded in the mint account. Only the token account's owner or
216/// delegated authority can invoke this instruction.
217///
218/// If the "alloc" feature is disabled, this method will error out if the number of additional
219/// accounts exceeds [MAX_ADDITIONAL_ACCOUNTS_NOALLOC]. Otherwise this method should be infallible.
220#[derive(Clone, PartialEq, Eq)]
221pub struct TransferChecked<'a, 'b: 'a> {
222    pub token_program_id: &'a Pubkey,
223    pub source: &'b NoStdAccountInfo,
224    pub mint: &'b NoStdAccountInfo,
225    pub destination: &'b NoStdAccountInfo,
226
227    /// Either the owner or delegated authority of the source token account.
228    pub authority: CpiAuthority<'a, 'b>,
229    pub amount: u64,
230    pub decimals: u8,
231
232    /// These additional accounts apply to the transfer checked instruction on the Token Extensions
233    /// program. Examples of these accounts may include signers of the multisig extension or
234    /// accounts needed for transfer hook CPI (which is performed by the Token Extensions program).
235    pub additional_accounts: Option<&'a [NoStdAccountInfo]>,
236}
237
238impl<'a, 'b: 'a> TransferChecked<'a, 'b> {
239    /// Tries to consume arguments to perform CPI call.
240    #[inline(always)]
241    pub fn try_into_invoke(self) -> ProgramResult {
242        let Self {
243            token_program_id,
244            source,
245            mint,
246            destination,
247            authority,
248            amount,
249            decimals,
250            additional_accounts,
251        } = self;
252
253        #[cfg(feature = "alloc")]
254        {
255            _invoke_transfer_checked(
256                token_program_id,
257                source,
258                destination,
259                &authority,
260                amount,
261                UseTransferChecked {
262                    mint,
263                    decimals,
264                    additional_accounts,
265                },
266            );
267
268            Ok(())
269        }
270
271        #[cfg(not(feature = "alloc"))]
272        if additional_accounts
273            .is_some_and(|accounts| accounts.len() > MAX_ADDITIONAL_ACCOUNTS_NOALLOC)
274        {
275            return Err(crate::error::SealevelToolsError::Cpi(&[
276                "Additional accounts exceed max allowed",
277            ])
278            .into());
279        } else {
280            _invoke_transfer_checked(
281                token_program_id,
282                source,
283                destination,
284                &authority,
285                amount,
286                UseTransferChecked {
287                    mint,
288                    decimals,
289                    additional_accounts,
290                },
291            );
292
293            Ok(())
294        }
295    }
296}
297
298#[inline(always)]
299fn _invoke_transfer(
300    token_program_id: &Pubkey,
301    source: &NoStdAccountInfo,
302    destination: &NoStdAccountInfo,
303    authority: &CpiAuthority,
304    amount: u64,
305) {
306    // Transfer selector == 3.
307    let instruction_data = super::serialize_amount_instruction_data(3, amount);
308
309    CpiInstruction {
310        program_id: token_program_id,
311        accounts: &[
312            source.to_meta_c(),
313            destination.to_meta_c(),
314            authority.to_meta_c_signer(),
315        ],
316        data: &instruction_data,
317    }
318    .invoke_possibly_signed(
319        &[
320            source.to_info_c(),
321            destination.to_info_c(),
322            authority.to_info_c(),
323        ],
324        &[authority.signer_seeds],
325    );
326}
327
328#[inline(always)]
329fn _invoke_transfer_checked(
330    token_program_id: &Pubkey,
331    source: &NoStdAccountInfo,
332    destination: &NoStdAccountInfo,
333    authority: &CpiAuthority,
334    amount: u64,
335    UseTransferChecked {
336        mint,
337        decimals,
338        additional_accounts,
339    }: UseTransferChecked,
340) {
341    // Transfer checked selector == 12.
342    let instruction_data = super::serialize_checked_amount_instruction_data(12, amount, decimals);
343
344    match additional_accounts {
345        Some(account_infos)
346            if token_program_id == &spl_token_2022::ID && !account_infos.is_empty() =>
347        {
348            _invoke_transfer_checked_with_additional_accounts(
349                token_program_id,
350                source,
351                mint,
352                destination,
353                authority,
354                &instruction_data,
355                account_infos,
356            )
357        }
358        Some(_) | None => _invoke_transfer_checked_without_additional_accounts(
359            token_program_id,
360            source,
361            mint,
362            destination,
363            authority,
364            &instruction_data,
365        ),
366    }
367}
368
369#[inline(always)]
370fn _invoke_transfer_checked_without_additional_accounts(
371    token_program_id: &Pubkey,
372    source: &NoStdAccountInfo,
373    mint: &NoStdAccountInfo,
374    destination: &NoStdAccountInfo,
375    authority: &CpiAuthority,
376    data: &[u8],
377) {
378    CpiInstruction {
379        program_id: token_program_id,
380        accounts: &[
381            source.to_meta_c(),
382            mint.to_meta_c(),
383            destination.to_meta_c(),
384            authority.to_meta_c_signer(),
385        ],
386        data,
387    }
388    .invoke_possibly_signed(
389        &[
390            source.to_info_c(),
391            mint.to_info_c(),
392            destination.to_info_c(),
393            authority.to_info_c(),
394        ],
395        &[authority.signer_seeds],
396    );
397}
398
399#[cfg(feature = "alloc")]
400#[inline(always)]
401fn _invoke_transfer_checked_with_additional_accounts(
402    token_program_id: &Pubkey,
403    source: &NoStdAccountInfo,
404    mint: &NoStdAccountInfo,
405    destination: &NoStdAccountInfo,
406    authority: &CpiAuthority,
407    data: &[u8],
408    additional_accounts: &[NoStdAccountInfo],
409) {
410    let mut accounts = vec![
411        source.to_meta_c(),
412        mint.to_meta_c(),
413        destination.to_meta_c(),
414        authority.to_meta_c_signer(),
415    ];
416
417    let mut infos = vec![
418        source.to_info_c(),
419        mint.to_info_c(),
420        destination.to_info_c(),
421        authority.to_info_c(),
422    ];
423
424    for account in additional_accounts {
425        accounts.push(account.to_meta_c());
426        infos.push(account.to_info_c());
427    }
428
429    crate::cpi::CpiInstruction {
430        program_id: token_program_id,
431        accounts: &accounts,
432        data,
433    }
434    .invoke_possibly_signed(&infos, &[authority.signer_seeds]);
435}
436
437#[cfg(not(feature = "alloc"))]
438use __noalloc::_invoke_transfer_checked_with_additional_accounts;
439
440#[cfg(not(feature = "alloc"))]
441mod __noalloc {
442    use super::*;
443
444    #[inline(always)]
445    pub fn _invoke_transfer_checked_with_additional_accounts(
446        token_program_id: &Pubkey,
447        source: &NoStdAccountInfo,
448        mint: &NoStdAccountInfo,
449        destination: &NoStdAccountInfo,
450        authority: &CpiAuthority,
451        data: &[u8],
452        additional_accounts: &[NoStdAccountInfo],
453    ) {
454        match additional_accounts.len() {
455            1 => _invoke_transfer_checked_with_additional_accounts_1(
456                token_program_id,
457                source,
458                mint,
459                destination,
460                authority,
461                data,
462                additional_accounts,
463            ),
464            2 => _invoke_transfer_checked_with_additional_accounts_2(
465                token_program_id,
466                source,
467                mint,
468                destination,
469                authority,
470                data,
471                additional_accounts,
472            ),
473            3 => _invoke_transfer_checked_with_additional_accounts_3(
474                token_program_id,
475                source,
476                mint,
477                destination,
478                authority,
479                data,
480                additional_accounts,
481            ),
482            4 => _invoke_transfer_checked_with_additional_accounts_4(
483                token_program_id,
484                source,
485                mint,
486                destination,
487                authority,
488                data,
489                additional_accounts,
490            ),
491            5 => _invoke_transfer_checked_with_additional_accounts_5(
492                token_program_id,
493                source,
494                mint,
495                destination,
496                authority,
497                data,
498                additional_accounts,
499            ),
500            6 => _invoke_transfer_checked_with_additional_accounts_6(
501                token_program_id,
502                source,
503                mint,
504                destination,
505                authority,
506                data,
507                additional_accounts,
508            ),
509            7 => _invoke_transfer_checked_with_additional_accounts_7(
510                token_program_id,
511                source,
512                mint,
513                destination,
514                authority,
515                data,
516                additional_accounts,
517            ),
518            8 => _invoke_transfer_checked_with_additional_accounts_8(
519                token_program_id,
520                source,
521                mint,
522                destination,
523                authority,
524                data,
525                additional_accounts,
526            ),
527            9 => _invoke_transfer_checked_with_additional_accounts_9(
528                token_program_id,
529                source,
530                mint,
531                destination,
532                authority,
533                data,
534                additional_accounts,
535            ),
536            10 => _invoke_transfer_checked_with_additional_accounts_10(
537                token_program_id,
538                source,
539                mint,
540                destination,
541                authority,
542                data,
543                additional_accounts,
544            ),
545            11 => _invoke_transfer_checked_with_additional_accounts_11(
546                token_program_id,
547                source,
548                mint,
549                destination,
550                authority,
551                data,
552                additional_accounts,
553            ),
554            MAX_ADDITIONAL_ACCOUNTS_NOALLOC => {
555                _invoke_transfer_checked_with_additional_accounts_12(
556                    token_program_id,
557                    source,
558                    mint,
559                    destination,
560                    authority,
561                    data,
562                    additional_accounts,
563                )
564            }
565            _ => panic!("Too many additional accounts passed in for transfer checked CPI"),
566        }
567    }
568
569    #[inline(always)]
570    fn _invoke_transfer_checked_with_additional_accounts_1(
571        token_program_id: &Pubkey,
572        source: &NoStdAccountInfo,
573        mint: &NoStdAccountInfo,
574        destination: &NoStdAccountInfo,
575        authority: &CpiAuthority,
576        data: &[u8],
577        additional_accounts: &[NoStdAccountInfo],
578    ) {
579        CpiInstruction {
580            program_id: token_program_id,
581            accounts: &[
582                source.to_meta_c(),
583                mint.to_meta_c(),
584                destination.to_meta_c(),
585                authority.to_meta_c_signer(),
586                additional_accounts[0].to_meta_c(),
587            ],
588            data,
589        }
590        .invoke_possibly_signed(
591            &[
592                source.to_info_c(),
593                mint.to_info_c(),
594                destination.to_info_c(),
595                authority.to_info_c(),
596                additional_accounts[0].to_info_c(),
597            ],
598            &[authority.signer_seeds],
599        );
600    }
601
602    #[inline(always)]
603    fn _invoke_transfer_checked_with_additional_accounts_2(
604        token_program_id: &Pubkey,
605        source: &NoStdAccountInfo,
606        mint: &NoStdAccountInfo,
607        destination: &NoStdAccountInfo,
608        authority: &CpiAuthority,
609        data: &[u8],
610        additional_accounts: &[NoStdAccountInfo],
611    ) {
612        CpiInstruction {
613            program_id: token_program_id,
614            accounts: &[
615                source.to_meta_c(),
616                mint.to_meta_c(),
617                destination.to_meta_c(),
618                authority.to_meta_c_signer(),
619                additional_accounts[0].to_meta_c(),
620                additional_accounts[1].to_meta_c(),
621            ],
622            data,
623        }
624        .invoke_possibly_signed(
625            &[
626                source.to_info_c(),
627                mint.to_info_c(),
628                destination.to_info_c(),
629                authority.to_info_c(),
630                additional_accounts[0].to_info_c(),
631                additional_accounts[1].to_info_c(),
632            ],
633            &[authority.signer_seeds],
634        );
635    }
636
637    #[inline(always)]
638    fn _invoke_transfer_checked_with_additional_accounts_3(
639        token_program_id: &Pubkey,
640        source: &NoStdAccountInfo,
641        mint: &NoStdAccountInfo,
642        destination: &NoStdAccountInfo,
643        authority: &CpiAuthority,
644        data: &[u8],
645        additional_accounts: &[NoStdAccountInfo],
646    ) {
647        CpiInstruction {
648            program_id: token_program_id,
649            accounts: &[
650                source.to_meta_c(),
651                mint.to_meta_c(),
652                destination.to_meta_c(),
653                authority.to_meta_c_signer(),
654                additional_accounts[0].to_meta_c(),
655                additional_accounts[1].to_meta_c(),
656                additional_accounts[2].to_meta_c(),
657            ],
658            data,
659        }
660        .invoke_possibly_signed(
661            &[
662                source.to_info_c(),
663                mint.to_info_c(),
664                destination.to_info_c(),
665                authority.to_info_c(),
666                additional_accounts[0].to_info_c(),
667                additional_accounts[1].to_info_c(),
668                additional_accounts[2].to_info_c(),
669            ],
670            &[authority.signer_seeds],
671        );
672    }
673
674    #[inline(always)]
675    fn _invoke_transfer_checked_with_additional_accounts_4(
676        token_program_id: &Pubkey,
677        source: &NoStdAccountInfo,
678        mint: &NoStdAccountInfo,
679        destination: &NoStdAccountInfo,
680        authority: &CpiAuthority,
681        data: &[u8],
682        additional_accounts: &[NoStdAccountInfo],
683    ) {
684        CpiInstruction {
685            program_id: token_program_id,
686            accounts: &[
687                source.to_meta_c(),
688                mint.to_meta_c(),
689                destination.to_meta_c(),
690                authority.to_meta_c_signer(),
691                additional_accounts[0].to_meta_c(),
692                additional_accounts[1].to_meta_c(),
693                additional_accounts[2].to_meta_c(),
694                additional_accounts[3].to_meta_c(),
695            ],
696            data,
697        }
698        .invoke_possibly_signed(
699            &[
700                source.to_info_c(),
701                mint.to_info_c(),
702                destination.to_info_c(),
703                authority.to_info_c(),
704                additional_accounts[0].to_info_c(),
705                additional_accounts[1].to_info_c(),
706                additional_accounts[2].to_info_c(),
707                additional_accounts[3].to_info_c(),
708            ],
709            &[authority.signer_seeds],
710        );
711    }
712
713    #[inline(always)]
714    fn _invoke_transfer_checked_with_additional_accounts_5(
715        token_program_id: &Pubkey,
716        source: &NoStdAccountInfo,
717        mint: &NoStdAccountInfo,
718        destination: &NoStdAccountInfo,
719        authority: &CpiAuthority,
720        data: &[u8],
721        additional_accounts: &[NoStdAccountInfo],
722    ) {
723        CpiInstruction {
724            program_id: token_program_id,
725            accounts: &[
726                source.to_meta_c(),
727                mint.to_meta_c(),
728                destination.to_meta_c(),
729                authority.to_meta_c_signer(),
730                additional_accounts[0].to_meta_c(),
731                additional_accounts[1].to_meta_c(),
732                additional_accounts[2].to_meta_c(),
733                additional_accounts[3].to_meta_c(),
734                additional_accounts[4].to_meta_c(),
735            ],
736            data,
737        }
738        .invoke_possibly_signed(
739            &[
740                source.to_info_c(),
741                mint.to_info_c(),
742                destination.to_info_c(),
743                authority.to_info_c(),
744                additional_accounts[0].to_info_c(),
745                additional_accounts[1].to_info_c(),
746                additional_accounts[2].to_info_c(),
747                additional_accounts[3].to_info_c(),
748                additional_accounts[4].to_info_c(),
749            ],
750            &[authority.signer_seeds],
751        );
752    }
753
754    #[inline(always)]
755    fn _invoke_transfer_checked_with_additional_accounts_6(
756        token_program_id: &Pubkey,
757        source: &NoStdAccountInfo,
758        mint: &NoStdAccountInfo,
759        destination: &NoStdAccountInfo,
760        authority: &CpiAuthority,
761        data: &[u8],
762        additional_accounts: &[NoStdAccountInfo],
763    ) {
764        CpiInstruction {
765            program_id: token_program_id,
766            accounts: &[
767                source.to_meta_c(),
768                mint.to_meta_c(),
769                destination.to_meta_c(),
770                authority.to_meta_c_signer(),
771                additional_accounts[0].to_meta_c(),
772                additional_accounts[1].to_meta_c(),
773                additional_accounts[2].to_meta_c(),
774                additional_accounts[3].to_meta_c(),
775                additional_accounts[4].to_meta_c(),
776                additional_accounts[5].to_meta_c(),
777            ],
778            data,
779        }
780        .invoke_possibly_signed(
781            &[
782                source.to_info_c(),
783                mint.to_info_c(),
784                destination.to_info_c(),
785                authority.to_info_c(),
786                additional_accounts[0].to_info_c(),
787                additional_accounts[1].to_info_c(),
788                additional_accounts[2].to_info_c(),
789                additional_accounts[3].to_info_c(),
790                additional_accounts[4].to_info_c(),
791                additional_accounts[5].to_info_c(),
792            ],
793            &[authority.signer_seeds],
794        );
795    }
796
797    #[inline(always)]
798    fn _invoke_transfer_checked_with_additional_accounts_7(
799        token_program_id: &Pubkey,
800        source: &NoStdAccountInfo,
801        mint: &NoStdAccountInfo,
802        destination: &NoStdAccountInfo,
803        authority: &CpiAuthority,
804        data: &[u8],
805        additional_accounts: &[NoStdAccountInfo],
806    ) {
807        CpiInstruction {
808            program_id: token_program_id,
809            accounts: &[
810                source.to_meta_c(),
811                mint.to_meta_c(),
812                destination.to_meta_c(),
813                authority.to_meta_c_signer(),
814                additional_accounts[0].to_meta_c(),
815                additional_accounts[1].to_meta_c(),
816                additional_accounts[2].to_meta_c(),
817                additional_accounts[3].to_meta_c(),
818                additional_accounts[4].to_meta_c(),
819                additional_accounts[5].to_meta_c(),
820                additional_accounts[6].to_meta_c(),
821            ],
822            data,
823        }
824        .invoke_possibly_signed(
825            &[
826                source.to_info_c(),
827                mint.to_info_c(),
828                destination.to_info_c(),
829                authority.to_info_c(),
830                additional_accounts[0].to_info_c(),
831                additional_accounts[1].to_info_c(),
832                additional_accounts[2].to_info_c(),
833                additional_accounts[3].to_info_c(),
834                additional_accounts[4].to_info_c(),
835                additional_accounts[5].to_info_c(),
836                additional_accounts[6].to_info_c(),
837            ],
838            &[authority.signer_seeds],
839        );
840    }
841
842    #[inline(always)]
843    fn _invoke_transfer_checked_with_additional_accounts_8(
844        token_program_id: &Pubkey,
845        source: &NoStdAccountInfo,
846        mint: &NoStdAccountInfo,
847        destination: &NoStdAccountInfo,
848        authority: &CpiAuthority,
849        data: &[u8],
850        additional_accounts: &[NoStdAccountInfo],
851    ) {
852        CpiInstruction {
853            program_id: token_program_id,
854            accounts: &[
855                source.to_meta_c(),
856                mint.to_meta_c(),
857                destination.to_meta_c(),
858                authority.to_meta_c_signer(),
859                additional_accounts[0].to_meta_c(),
860                additional_accounts[1].to_meta_c(),
861                additional_accounts[2].to_meta_c(),
862                additional_accounts[3].to_meta_c(),
863                additional_accounts[4].to_meta_c(),
864                additional_accounts[5].to_meta_c(),
865                additional_accounts[6].to_meta_c(),
866                additional_accounts[7].to_meta_c(),
867            ],
868            data,
869        }
870        .invoke_possibly_signed(
871            &[
872                source.to_info_c(),
873                mint.to_info_c(),
874                destination.to_info_c(),
875                authority.to_info_c(),
876                additional_accounts[0].to_info_c(),
877                additional_accounts[1].to_info_c(),
878                additional_accounts[2].to_info_c(),
879                additional_accounts[3].to_info_c(),
880                additional_accounts[4].to_info_c(),
881                additional_accounts[5].to_info_c(),
882                additional_accounts[6].to_info_c(),
883                additional_accounts[7].to_info_c(),
884            ],
885            &[authority.signer_seeds],
886        );
887    }
888
889    #[inline(always)]
890    fn _invoke_transfer_checked_with_additional_accounts_9(
891        token_program_id: &Pubkey,
892        source: &NoStdAccountInfo,
893        mint: &NoStdAccountInfo,
894        destination: &NoStdAccountInfo,
895        authority: &CpiAuthority,
896        data: &[u8],
897        additional_accounts: &[NoStdAccountInfo],
898    ) {
899        CpiInstruction {
900            program_id: token_program_id,
901            accounts: &[
902                source.to_meta_c(),
903                mint.to_meta_c(),
904                destination.to_meta_c(),
905                authority.to_meta_c_signer(),
906                additional_accounts[0].to_meta_c(),
907                additional_accounts[1].to_meta_c(),
908                additional_accounts[2].to_meta_c(),
909                additional_accounts[3].to_meta_c(),
910                additional_accounts[4].to_meta_c(),
911                additional_accounts[5].to_meta_c(),
912                additional_accounts[6].to_meta_c(),
913                additional_accounts[7].to_meta_c(),
914                additional_accounts[8].to_meta_c(),
915            ],
916            data,
917        }
918        .invoke_possibly_signed(
919            &[
920                source.to_info_c(),
921                mint.to_info_c(),
922                destination.to_info_c(),
923                authority.to_info_c(),
924                additional_accounts[0].to_info_c(),
925                additional_accounts[1].to_info_c(),
926                additional_accounts[2].to_info_c(),
927                additional_accounts[3].to_info_c(),
928                additional_accounts[4].to_info_c(),
929                additional_accounts[5].to_info_c(),
930                additional_accounts[6].to_info_c(),
931                additional_accounts[7].to_info_c(),
932                additional_accounts[8].to_info_c(),
933            ],
934            &[authority.signer_seeds],
935        );
936    }
937
938    #[inline(always)]
939    fn _invoke_transfer_checked_with_additional_accounts_10(
940        token_program_id: &Pubkey,
941        source: &NoStdAccountInfo,
942        mint: &NoStdAccountInfo,
943        destination: &NoStdAccountInfo,
944        authority: &CpiAuthority,
945        data: &[u8],
946        additional_accounts: &[NoStdAccountInfo],
947    ) {
948        CpiInstruction {
949            program_id: token_program_id,
950            accounts: &[
951                source.to_meta_c(),
952                mint.to_meta_c(),
953                destination.to_meta_c(),
954                authority.to_meta_c_signer(),
955                additional_accounts[0].to_meta_c(),
956                additional_accounts[1].to_meta_c(),
957                additional_accounts[2].to_meta_c(),
958                additional_accounts[3].to_meta_c(),
959                additional_accounts[4].to_meta_c(),
960                additional_accounts[5].to_meta_c(),
961                additional_accounts[6].to_meta_c(),
962                additional_accounts[7].to_meta_c(),
963                additional_accounts[8].to_meta_c(),
964                additional_accounts[9].to_meta_c(),
965            ],
966            data,
967        }
968        .invoke_possibly_signed(
969            &[
970                source.to_info_c(),
971                mint.to_info_c(),
972                destination.to_info_c(),
973                authority.to_info_c(),
974                additional_accounts[0].to_info_c(),
975                additional_accounts[1].to_info_c(),
976                additional_accounts[2].to_info_c(),
977                additional_accounts[3].to_info_c(),
978                additional_accounts[4].to_info_c(),
979                additional_accounts[5].to_info_c(),
980                additional_accounts[6].to_info_c(),
981                additional_accounts[7].to_info_c(),
982                additional_accounts[8].to_info_c(),
983                additional_accounts[9].to_info_c(),
984            ],
985            &[authority.signer_seeds],
986        );
987    }
988
989    #[inline(always)]
990    fn _invoke_transfer_checked_with_additional_accounts_11(
991        token_program_id: &Pubkey,
992        source: &NoStdAccountInfo,
993        mint: &NoStdAccountInfo,
994        destination: &NoStdAccountInfo,
995        authority: &CpiAuthority,
996        data: &[u8],
997        additional_accounts: &[NoStdAccountInfo],
998    ) {
999        CpiInstruction {
1000            program_id: token_program_id,
1001            accounts: &[
1002                source.to_meta_c(),
1003                mint.to_meta_c(),
1004                destination.to_meta_c(),
1005                authority.to_meta_c_signer(),
1006                additional_accounts[0].to_meta_c(),
1007                additional_accounts[1].to_meta_c(),
1008                additional_accounts[2].to_meta_c(),
1009                additional_accounts[3].to_meta_c(),
1010                additional_accounts[4].to_meta_c(),
1011                additional_accounts[5].to_meta_c(),
1012                additional_accounts[6].to_meta_c(),
1013                additional_accounts[7].to_meta_c(),
1014                additional_accounts[8].to_meta_c(),
1015                additional_accounts[9].to_meta_c(),
1016                additional_accounts[10].to_meta_c(),
1017            ],
1018            data,
1019        }
1020        .invoke_possibly_signed(
1021            &[
1022                source.to_info_c(),
1023                mint.to_info_c(),
1024                destination.to_info_c(),
1025                authority.to_info_c(),
1026                additional_accounts[0].to_info_c(),
1027                additional_accounts[1].to_info_c(),
1028                additional_accounts[2].to_info_c(),
1029                additional_accounts[3].to_info_c(),
1030                additional_accounts[4].to_info_c(),
1031                additional_accounts[5].to_info_c(),
1032                additional_accounts[6].to_info_c(),
1033                additional_accounts[7].to_info_c(),
1034                additional_accounts[8].to_info_c(),
1035                additional_accounts[9].to_info_c(),
1036                additional_accounts[10].to_info_c(),
1037            ],
1038            &[authority.signer_seeds],
1039        );
1040    }
1041
1042    #[inline(always)]
1043    fn _invoke_transfer_checked_with_additional_accounts_12(
1044        token_program_id: &Pubkey,
1045        source: &NoStdAccountInfo,
1046        mint: &NoStdAccountInfo,
1047        destination: &NoStdAccountInfo,
1048        authority: &CpiAuthority,
1049        data: &[u8],
1050        additional_accounts: &[NoStdAccountInfo],
1051    ) {
1052        CpiInstruction {
1053            program_id: token_program_id,
1054            accounts: &[
1055                source.to_meta_c(),
1056                mint.to_meta_c(),
1057                destination.to_meta_c(),
1058                authority.to_meta_c_signer(),
1059                additional_accounts[0].to_meta_c(),
1060                additional_accounts[1].to_meta_c(),
1061                additional_accounts[2].to_meta_c(),
1062                additional_accounts[3].to_meta_c(),
1063                additional_accounts[4].to_meta_c(),
1064                additional_accounts[5].to_meta_c(),
1065                additional_accounts[6].to_meta_c(),
1066                additional_accounts[7].to_meta_c(),
1067                additional_accounts[8].to_meta_c(),
1068                additional_accounts[9].to_meta_c(),
1069                additional_accounts[10].to_meta_c(),
1070                additional_accounts[11].to_meta_c(),
1071            ],
1072            data,
1073        }
1074        .invoke_possibly_signed(
1075            &[
1076                source.to_info_c(),
1077                mint.to_info_c(),
1078                destination.to_info_c(),
1079                authority.to_info_c(),
1080                additional_accounts[0].to_info_c(),
1081                additional_accounts[1].to_info_c(),
1082                additional_accounts[2].to_info_c(),
1083                additional_accounts[3].to_info_c(),
1084                additional_accounts[4].to_info_c(),
1085                additional_accounts[5].to_info_c(),
1086                additional_accounts[6].to_info_c(),
1087                additional_accounts[7].to_info_c(),
1088                additional_accounts[8].to_info_c(),
1089                additional_accounts[9].to_info_c(),
1090                additional_accounts[10].to_info_c(),
1091                additional_accounts[11].to_info_c(),
1092            ],
1093            &[authority.signer_seeds],
1094        );
1095    }
1096}