typhoon-token 0.3.0

SPL token program integration and account types
Documentation
use {
    crate::TokenAccount,
    pinocchio::{cpi::Signer as CpiSigner, sysvars::rent::Rent, AccountView, Address},
    pinocchio_associated_token_account::instructions::{Create, CreateIdempotent},
    pinocchio_token::{instructions::InitializeAccount3, ID as TOKEN_PROGRAM_ID},
    typhoon_accounts::{
        Account, FromAccountInfo, FromRaw, Mut, ReadableAccount, Signer, SignerCheck,
        SystemAccount, UncheckedAccount, WritableAccount,
    },
    typhoon_errors::Error,
    typhoon_utility::create_account_with_minimum_balance_signed,
};

pub trait SplCreateToken<'a, T>
where
    Self: Sized + Into<&'a AccountView>,
    T: ReadableAccount + FromAccountInfo<'a> + FromRaw<'a>,
{
    fn create_token_account(
        self,
        rent: &Rent,
        payer: &impl WritableAccount,
        mint: &impl ReadableAccount,
        owner: &Address,
        seeds: Option<&[CpiSigner]>,
    ) -> Result<Mut<T>, Error> {
        let info = self.into();
        create_account_with_minimum_balance_signed(
            info,
            TokenAccount::LEN,
            &TOKEN_PROGRAM_ID,
            payer.as_ref(),
            rent,
            seeds.unwrap_or_default(),
        )?;

        InitializeAccount3 {
            account: info,
            mint: mint.as_ref(),
            owner,
        }
        .invoke()?;

        Ok(Mut::from_raw_info(info))
    }

    fn create_associated_token_account(
        self,
        payer: &impl WritableAccount,
        mint: &impl ReadableAccount,
        owner: &impl ReadableAccount,
        system_program: &impl ReadableAccount,
        token_program: &impl ReadableAccount,
    ) -> Result<Mut<T>, Error> {
        let info = self.into();
        Create {
            funding_account: payer.as_ref(),
            account: info,
            wallet: owner.as_ref(),
            mint: mint.as_ref(),
            system_program: system_program.as_ref(),
            token_program: token_program.as_ref(),
        }
        .invoke()?;

        Ok(Mut::from_raw_info(info))
    }

    fn create_idempotent_associated_token_account(
        self,
        payer: &impl WritableAccount,
        mint: &impl ReadableAccount,
        owner: &impl ReadableAccount,
        system_program: &impl ReadableAccount,
        token_program: &impl ReadableAccount,
    ) -> Result<Mut<T>, Error> {
        let info = self.into();
        CreateIdempotent {
            funding_account: payer.as_ref(),
            account: info,
            wallet: owner.as_ref(),
            mint: mint.as_ref(),
            system_program: system_program.as_ref(),
            token_program: token_program.as_ref(),
        }
        .invoke()?;

        Ok(Mut::from_raw_info(info))
    }
}

macro_rules! impl_trait {
    ($origin: ty) => {
        impl<'a> SplCreateToken<'a, Account<'a, TokenAccount>> for $origin {}
        impl<'a, C> SplCreateToken<'a, Signer<'a, Account<'a, TokenAccount>, C>> for $origin where
            C: SignerCheck
        {
        }
    };
}

impl_trait!(&'a AccountView);
impl_trait!(SystemAccount<'a>);
impl_trait!(UncheckedAccount<'a>);