12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292 |
- //! Instruction types
- use crate::{check_program_account, error::TokenError};
- use solana_program::{
- instruction::{AccountMeta, Instruction},
- program_error::ProgramError,
- program_option::COption,
- pubkey::Pubkey,
- sysvar,
- };
- use std::convert::TryInto;
- use std::mem::size_of;
- /// Minimum number of multisignature signers (min N)
- pub const MIN_SIGNERS: usize = 1;
- /// Maximum number of multisignature signers (max N)
- pub const MAX_SIGNERS: usize = 11;
- /// Instructions supported by the token program.
- #[repr(C)]
- #[derive(Clone, Debug, PartialEq)]
- pub enum TokenInstruction {
- /// Initializes a new mint and optionally deposits all the newly minted
- /// tokens in an account.
- ///
- /// The `InitializeMint` instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The mint to initialize.
- /// 1. `[]` Rent sysvar
- ///
- InitializeMint {
- /// Number of base 10 digits to the right of the decimal place.
- decimals: u8,
- /// The authority/multisignature to mint tokens.
- mint_authority: Pubkey,
- /// The freeze authority/multisignature of the mint.
- freeze_authority: COption<Pubkey>,
- },
- /// Initializes a new account to hold tokens. If this account is associated
- /// with the native mint then the token balance of the initialized account
- /// will be equal to the amount of SOL in the account. If this account is
- /// associated with another mint, that mint must be initialized before this
- /// command can succeed.
- ///
- /// The `InitializeAccount` instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- /// 1. `[]` The mint this account will be associated with.
- /// 2. `[]` The new account's owner/multisignature.
- /// 3. `[]` Rent sysvar
- InitializeAccount,
- /// Initializes a multisignature account with N provided signers.
- ///
- /// Multisignature accounts can used in place of any single owner/delegate
- /// accounts in any token instruction that require an owner/delegate to be
- /// present. The variant field represents the number of signers (M)
- /// required to validate this multisignature account.
- ///
- /// The `InitializeMultisig` instruction requires no signers and MUST be
- /// included within the same Transaction as the system program's
- /// `CreateAccount` instruction that creates the account being initialized.
- /// Otherwise another party can acquire ownership of the uninitialized
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The multisignature account to initialize.
- /// 1. `[]` Rent sysvar
- /// 2. ..2+N. `[]` The signer accounts, must equal to N where 1 <= N <=
- /// 11.
- InitializeMultisig {
- /// The number of signers (M) required to validate this multisignature
- /// account.
- m: u8,
- },
- /// Transfers tokens from one account to another either directly or via a
- /// delegate. If this account is associated with the native mint then equal
- /// amounts of SOL and Tokens will be transferred to the destination
- /// account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[writable]` The destination account.
- /// 2. `[signer]` The source account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[writable]` The destination account.
- /// 2. `[]` The source account's multisignature owner/delegate.
- /// 3. ..3+M `[signer]` M signer accounts.
- Transfer {
- /// The amount of tokens to transfer.
- amount: u64,
- },
- /// Approves a delegate. A delegate is given the authority over tokens on
- /// behalf of the source account's owner.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The delegate.
- /// 2. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The delegate.
- /// 2. `[]` The source account's multisignature owner.
- /// 3. ..3+M `[signer]` M signer accounts
- Approve {
- /// The amount of tokens the delegate is approved for.
- amount: u64,
- },
- /// Revokes the delegate's authority.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The source account's multisignature owner.
- /// 2. ..2+M `[signer]` M signer accounts
- Revoke,
- /// Sets a new authority of a mint or account.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint or account to change the authority of.
- /// 1. `[signer]` The current authority of the mint or account.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint or account to change the authority of.
- /// 1. `[]` The mint's or account's current multisignature authority.
- /// 2. ..2+M `[signer]` M signer accounts
- SetAuthority {
- /// The type of authority to update.
- authority_type: AuthorityType,
- /// The new authority
- new_authority: COption<Pubkey>,
- },
- /// Mints new tokens to an account. The native mint does not support
- /// minting.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[signer]` The mint's minting authority.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[]` The mint's multisignature mint-tokens authority.
- /// 3. ..3+M `[signer]` M signer accounts.
- MintTo {
- /// The amount of new tokens to mint.
- amount: u64,
- },
- /// Burns tokens by removing them from an account. `Burn` does not support
- /// accounts associated with the native mint, use `CloseAccount` instead.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[signer]` The account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[]` The account's multisignature owner/delegate.
- /// 3. ..3+M `[signer]` M signer accounts.
- Burn {
- /// The amount of tokens to burn.
- amount: u64,
- },
- /// Close an account by transferring all its SOL to the destination account.
- /// Non-native accounts may only be closed if its token amount is zero.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to close.
- /// 1. `[writable]` The destination account.
- /// 2. `[signer]` The account's owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to close.
- /// 1. `[writable]` The destination account.
- /// 2. `[]` The account's multisignature owner.
- /// 3. ..3+M `[signer]` M signer accounts.
- CloseAccount,
- /// Freeze an Initialized account using the Mint's freeze_authority (if
- /// set).
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[signer]` The mint freeze authority.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[]` The mint's multisignature freeze authority.
- /// 3. ..3+M `[signer]` M signer accounts.
- FreezeAccount,
- /// Thaw a Frozen account using the Mint's freeze_authority (if set).
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[signer]` The mint freeze authority.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The account to freeze.
- /// 1. `[]` The token mint.
- /// 2. `[]` The mint's multisignature freeze authority.
- /// 3. ..3+M `[signer]` M signer accounts.
- ThawAccount,
- /// Transfers tokens from one account to another either directly or via a
- /// delegate. If this account is associated with the native mint then equal
- /// amounts of SOL and Tokens will be transferred to the destination
- /// account.
- ///
- /// This instruction differs from Transfer in that the token mint and
- /// decimals value is checked by the caller. This may be useful when
- /// creating transactions offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[writable]` The destination account.
- /// 3. `[signer]` The source account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[writable]` The destination account.
- /// 3. `[]` The source account's multisignature owner/delegate.
- /// 4. ..4+M `[signer]` M signer accounts.
- TransferChecked {
- /// The amount of tokens to transfer.
- amount: u64,
- /// Expected number of base 10 digits to the right of the decimal place.
- decimals: u8,
- },
- /// Approves a delegate. A delegate is given the authority over tokens on
- /// behalf of the source account's owner.
- ///
- /// This instruction differs from Approve in that the token mint and
- /// decimals value is checked by the caller. This may be useful when
- /// creating transactions offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[]` The delegate.
- /// 3. `[signer]` The source account owner.
- ///
- /// * Multisignature owner
- /// 0. `[writable]` The source account.
- /// 1. `[]` The token mint.
- /// 2. `[]` The delegate.
- /// 3. `[]` The source account's multisignature owner.
- /// 4. ..4+M `[signer]` M signer accounts
- ApproveChecked {
- /// The amount of tokens the delegate is approved for.
- amount: u64,
- /// Expected number of base 10 digits to the right of the decimal place.
- decimals: u8,
- },
- /// Mints new tokens to an account. The native mint does not support
- /// minting.
- ///
- /// This instruction differs from MintTo in that the decimals value is
- /// checked by the caller. This may be useful when creating transactions
- /// offline or within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[signer]` The mint's minting authority.
- ///
- /// * Multisignature authority
- /// 0. `[writable]` The mint.
- /// 1. `[writable]` The account to mint tokens to.
- /// 2. `[]` The mint's multisignature mint-tokens authority.
- /// 3. ..3+M `[signer]` M signer accounts.
- MintToChecked {
- /// The amount of new tokens to mint.
- amount: u64,
- /// Expected number of base 10 digits to the right of the decimal place.
- decimals: u8,
- },
- /// Burns tokens by removing them from an account. `BurnChecked` does not
- /// support accounts associated with the native mint, use `CloseAccount`
- /// instead.
- ///
- /// This instruction differs from Burn in that the decimals value is checked
- /// by the caller. This may be useful when creating transactions offline or
- /// within a hardware wallet.
- ///
- /// Accounts expected by this instruction:
- ///
- /// * Single owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[signer]` The account's owner/delegate.
- ///
- /// * Multisignature owner/delegate
- /// 0. `[writable]` The account to burn from.
- /// 1. `[writable]` The token mint.
- /// 2. `[]` The account's multisignature owner/delegate.
- /// 3. ..3+M `[signer]` M signer accounts.
- BurnChecked {
- /// The amount of tokens to burn.
- amount: u64,
- /// Expected number of base 10 digits to the right of the decimal place.
- decimals: u8,
- },
- /// Like InitializeAccount, but the owner pubkey is passed via instruction data
- /// rather than the accounts list. This variant may be preferable when using
- /// Cross Program Invocation from an instruction that does not need the owner's
- /// `AccountInfo` otherwise.
- ///
- /// Accounts expected by this instruction:
- ///
- /// 0. `[writable]` The account to initialize.
- /// 1. `[]` The mint this account will be associated with.
- /// 3. `[]` Rent sysvar
- InitializeAccount2 {
- /// The new account's owner/multisignature.
- owner: Pubkey,
- },
- }
- impl TokenInstruction {
- /// Unpacks a byte buffer into a [TokenInstruction](enum.TokenInstruction.html).
- pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
- use TokenError::InvalidInstruction;
- let (&tag, rest) = input.split_first().ok_or(InvalidInstruction)?;
- Ok(match tag {
- 0 => {
- let (&decimals, rest) = rest.split_first().ok_or(InvalidInstruction)?;
- let (mint_authority, rest) = Self::unpack_pubkey(rest)?;
- let (freeze_authority, _rest) = Self::unpack_pubkey_option(rest)?;
- Self::InitializeMint {
- mint_authority,
- freeze_authority,
- decimals,
- }
- }
- 1 => Self::InitializeAccount,
- 2 => {
- let &m = rest.get(0).ok_or(InvalidInstruction)?;
- Self::InitializeMultisig { m }
- }
- 3 | 4 | 7 | 8 => {
- let amount = rest
- .get(..8)
- .and_then(|slice| slice.try_into().ok())
- .map(u64::from_le_bytes)
- .ok_or(InvalidInstruction)?;
- match tag {
- 3 => Self::Transfer { amount },
- 4 => Self::Approve { amount },
- 7 => Self::MintTo { amount },
- 8 => Self::Burn { amount },
- _ => unreachable!(),
- }
- }
- 5 => Self::Revoke,
- 6 => {
- let (authority_type, rest) = rest
- .split_first()
- .ok_or_else(|| ProgramError::from(InvalidInstruction))
- .and_then(|(&t, rest)| Ok((AuthorityType::from(t)?, rest)))?;
- let (new_authority, _rest) = Self::unpack_pubkey_option(rest)?;
- Self::SetAuthority {
- authority_type,
- new_authority,
- }
- }
- 9 => Self::CloseAccount,
- 10 => Self::FreezeAccount,
- 11 => Self::ThawAccount,
- 12 => {
- let (amount, rest) = rest.split_at(8);
- let amount = amount
- .try_into()
- .ok()
- .map(u64::from_le_bytes)
- .ok_or(InvalidInstruction)?;
- let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
- Self::TransferChecked { amount, decimals }
- }
- 13 => {
- let (amount, rest) = rest.split_at(8);
- let amount = amount
- .try_into()
- .ok()
- .map(u64::from_le_bytes)
- .ok_or(InvalidInstruction)?;
- let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
- Self::ApproveChecked { amount, decimals }
- }
- 14 => {
- let (amount, rest) = rest.split_at(8);
- let amount = amount
- .try_into()
- .ok()
- .map(u64::from_le_bytes)
- .ok_or(InvalidInstruction)?;
- let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
- Self::MintToChecked { amount, decimals }
- }
- 15 => {
- let (amount, rest) = rest.split_at(8);
- let amount = amount
- .try_into()
- .ok()
- .map(u64::from_le_bytes)
- .ok_or(InvalidInstruction)?;
- let (&decimals, _rest) = rest.split_first().ok_or(InvalidInstruction)?;
- Self::BurnChecked { amount, decimals }
- }
- 16 => {
- let (owner, _rest) = Self::unpack_pubkey(rest)?;
- Self::InitializeAccount2 { owner }
- }
- _ => return Err(TokenError::InvalidInstruction.into()),
- })
- }
- /// Packs a [TokenInstruction](enum.TokenInstruction.html) into a byte buffer.
- pub fn pack(&self) -> Vec<u8> {
- let mut buf = Vec::with_capacity(size_of::<Self>());
- match self {
- &Self::InitializeMint {
- ref mint_authority,
- ref freeze_authority,
- decimals,
- } => {
- buf.push(0);
- buf.push(decimals);
- buf.extend_from_slice(mint_authority.as_ref());
- Self::pack_pubkey_option(freeze_authority, &mut buf);
- }
- Self::InitializeAccount => buf.push(1),
- &Self::InitializeMultisig { m } => {
- buf.push(2);
- buf.push(m);
- }
- &Self::Transfer { amount } => {
- buf.push(3);
- buf.extend_from_slice(&amount.to_le_bytes());
- }
- &Self::Approve { amount } => {
- buf.push(4);
- buf.extend_from_slice(&amount.to_le_bytes());
- }
- &Self::MintTo { amount } => {
- buf.push(7);
- buf.extend_from_slice(&amount.to_le_bytes());
- }
- &Self::Burn { amount } => {
- buf.push(8);
- buf.extend_from_slice(&amount.to_le_bytes());
- }
- Self::Revoke => buf.push(5),
- Self::SetAuthority {
- authority_type,
- ref new_authority,
- } => {
- buf.push(6);
- buf.push(authority_type.into());
- Self::pack_pubkey_option(new_authority, &mut buf);
- }
- Self::CloseAccount => buf.push(9),
- Self::FreezeAccount => buf.push(10),
- Self::ThawAccount => buf.push(11),
- &Self::TransferChecked { amount, decimals } => {
- buf.push(12);
- buf.extend_from_slice(&amount.to_le_bytes());
- buf.push(decimals);
- }
- &Self::ApproveChecked { amount, decimals } => {
- buf.push(13);
- buf.extend_from_slice(&amount.to_le_bytes());
- buf.push(decimals);
- }
- &Self::MintToChecked { amount, decimals } => {
- buf.push(14);
- buf.extend_from_slice(&amount.to_le_bytes());
- buf.push(decimals);
- }
- &Self::BurnChecked { amount, decimals } => {
- buf.push(15);
- buf.extend_from_slice(&amount.to_le_bytes());
- buf.push(decimals);
- }
- &Self::InitializeAccount2 { owner } => {
- buf.push(16);
- buf.extend_from_slice(owner.as_ref());
- }
- };
- buf
- }
- fn unpack_pubkey(input: &[u8]) -> Result<(Pubkey, &[u8]), ProgramError> {
- if input.len() >= 32 {
- let (key, rest) = input.split_at(32);
- let pk = Pubkey::new(key);
- Ok((pk, rest))
- } else {
- Err(TokenError::InvalidInstruction.into())
- }
- }
- fn unpack_pubkey_option(input: &[u8]) -> Result<(COption<Pubkey>, &[u8]), ProgramError> {
- match input.split_first() {
- Option::Some((&0, rest)) => Ok((COption::None, rest)),
- Option::Some((&1, rest)) if rest.len() >= 32 => {
- let (key, rest) = rest.split_at(32);
- let pk = Pubkey::new(key);
- Ok((COption::Some(pk), rest))
- }
- _ => Err(TokenError::InvalidInstruction.into()),
- }
- }
- fn pack_pubkey_option(value: &COption<Pubkey>, buf: &mut Vec<u8>) {
- match *value {
- COption::Some(ref key) => {
- buf.push(1);
- buf.extend_from_slice(&key.to_bytes());
- }
- COption::None => buf.push(0),
- }
- }
- }
- /// Specifies the authority type for SetAuthority instructions
- #[repr(u8)]
- #[derive(Clone, Debug, PartialEq)]
- pub enum AuthorityType {
- /// Authority to mint new tokens
- MintTokens,
- /// Authority to freeze any account associated with the Mint
- FreezeAccount,
- /// Owner of a given token account
- AccountOwner,
- /// Authority to close a token account
- CloseAccount,
- }
- impl AuthorityType {
- fn into(&self) -> u8 {
- match self {
- AuthorityType::MintTokens => 0,
- AuthorityType::FreezeAccount => 1,
- AuthorityType::AccountOwner => 2,
- AuthorityType::CloseAccount => 3,
- }
- }
- fn from(index: u8) -> Result<Self, ProgramError> {
- match index {
- 0 => Ok(AuthorityType::MintTokens),
- 1 => Ok(AuthorityType::FreezeAccount),
- 2 => Ok(AuthorityType::AccountOwner),
- 3 => Ok(AuthorityType::CloseAccount),
- _ => Err(TokenError::InvalidInstruction.into()),
- }
- }
- }
- /// Creates a `InitializeMint` instruction.
- pub fn initialize_mint(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- mint_authority_pubkey: &Pubkey,
- freeze_authority_pubkey: Option<&Pubkey>,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let freeze_authority = freeze_authority_pubkey.cloned().into();
- let data = TokenInstruction::InitializeMint {
- mint_authority: *mint_authority_pubkey,
- freeze_authority,
- decimals,
- }
- .pack();
- let accounts = vec![
- AccountMeta::new(*mint_pubkey, false),
- AccountMeta::new_readonly(sysvar::rent::id(), false),
- ];
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `InitializeAccount` instruction.
- pub fn initialize_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::InitializeAccount.pack();
- let accounts = vec![
- AccountMeta::new(*account_pubkey, false),
- AccountMeta::new_readonly(*mint_pubkey, false),
- AccountMeta::new_readonly(*owner_pubkey, false),
- AccountMeta::new_readonly(sysvar::rent::id(), false),
- ];
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `InitializeAccount2` instruction.
- pub fn initialize_account2(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::InitializeAccount2 {
- owner: *owner_pubkey,
- }
- .pack();
- let accounts = vec![
- AccountMeta::new(*account_pubkey, false),
- AccountMeta::new_readonly(*mint_pubkey, false),
- AccountMeta::new_readonly(sysvar::rent::id(), false),
- ];
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `InitializeMultisig` instruction.
- pub fn initialize_multisig(
- token_program_id: &Pubkey,
- multisig_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- m: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- if !is_valid_signer_index(m as usize)
- || !is_valid_signer_index(signer_pubkeys.len())
- || m as usize > signer_pubkeys.len()
- {
- return Err(ProgramError::MissingRequiredSignature);
- }
- let data = TokenInstruction::InitializeMultisig { m }.pack();
- let mut accounts = Vec::with_capacity(1 + 1 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*multisig_pubkey, false));
- accounts.push(AccountMeta::new_readonly(sysvar::rent::id(), false));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, false));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Transfer` instruction.
- pub fn transfer(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::Transfer { amount }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates an `Approve` instruction.
- pub fn approve(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- delegate_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::Approve { amount }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Revoke` instruction.
- pub fn revoke(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::Revoke.pack();
- let mut accounts = Vec::with_capacity(2 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `SetAuthority` instruction.
- pub fn set_authority(
- token_program_id: &Pubkey,
- owned_pubkey: &Pubkey,
- new_authority_pubkey: Option<&Pubkey>,
- authority_type: AuthorityType,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let new_authority = new_authority_pubkey.cloned().into();
- let data = TokenInstruction::SetAuthority {
- authority_type,
- new_authority,
- }
- .pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*owned_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `MintTo` instruction.
- pub fn mint_to(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- account_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::MintTo { amount }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `Burn` instruction.
- pub fn burn(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::Burn { amount }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `CloseAccount` instruction.
- pub fn close_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::CloseAccount.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `FreezeAccount` instruction.
- pub fn freeze_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::FreezeAccount.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `ThawAccount` instruction.
- pub fn thaw_account(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::ThawAccount.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `TransferChecked` instruction.
- #[allow(clippy::too_many_arguments)]
- pub fn transfer_checked(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- destination_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::TransferChecked { amount, decimals }.pack();
- let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*destination_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates an `ApproveChecked` instruction.
- #[allow(clippy::too_many_arguments)]
- pub fn approve_checked(
- token_program_id: &Pubkey,
- source_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- delegate_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::ApproveChecked { amount, decimals }.pack();
- let mut accounts = Vec::with_capacity(4 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*source_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(*delegate_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `MintToChecked` instruction.
- pub fn mint_to_checked(
- token_program_id: &Pubkey,
- mint_pubkey: &Pubkey,
- account_pubkey: &Pubkey,
- owner_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::MintToChecked { amount, decimals }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *owner_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Creates a `BurnChecked` instruction.
- pub fn burn_checked(
- token_program_id: &Pubkey,
- account_pubkey: &Pubkey,
- mint_pubkey: &Pubkey,
- authority_pubkey: &Pubkey,
- signer_pubkeys: &[&Pubkey],
- amount: u64,
- decimals: u8,
- ) -> Result<Instruction, ProgramError> {
- check_program_account(token_program_id)?;
- let data = TokenInstruction::BurnChecked { amount, decimals }.pack();
- let mut accounts = Vec::with_capacity(3 + signer_pubkeys.len());
- accounts.push(AccountMeta::new(*account_pubkey, false));
- accounts.push(AccountMeta::new(*mint_pubkey, false));
- accounts.push(AccountMeta::new_readonly(
- *authority_pubkey,
- signer_pubkeys.is_empty(),
- ));
- for signer_pubkey in signer_pubkeys.iter() {
- accounts.push(AccountMeta::new_readonly(**signer_pubkey, true));
- }
- Ok(Instruction {
- program_id: *token_program_id,
- accounts,
- data,
- })
- }
- /// Utility function that checks index is between MIN_SIGNERS and MAX_SIGNERS
- pub fn is_valid_signer_index(index: usize) -> bool {
- (MIN_SIGNERS..=MAX_SIGNERS).contains(&index)
- }
- #[cfg(test)]
- mod test {
- use super::*;
- #[test]
- fn test_instruction_packing() {
- let check = TokenInstruction::InitializeMint {
- decimals: 2,
- mint_authority: Pubkey::new(&[1u8; 32]),
- freeze_authority: COption::None,
- };
- let packed = check.pack();
- let mut expect = Vec::from([0u8, 2]);
- expect.extend_from_slice(&[1u8; 32]);
- expect.extend_from_slice(&[0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeMint {
- decimals: 2,
- mint_authority: Pubkey::new(&[2u8; 32]),
- freeze_authority: COption::Some(Pubkey::new(&[3u8; 32])),
- };
- let packed = check.pack();
- let mut expect = vec![0u8, 2];
- expect.extend_from_slice(&[2u8; 32]);
- expect.extend_from_slice(&[1]);
- expect.extend_from_slice(&[3u8; 32]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeAccount;
- let packed = check.pack();
- let expect = Vec::from([1u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeMultisig { m: 1 };
- let packed = check.pack();
- let expect = Vec::from([2u8, 1]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Transfer { amount: 1 };
- let packed = check.pack();
- let expect = Vec::from([3u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Approve { amount: 1 };
- let packed = check.pack();
- let expect = Vec::from([4u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Revoke;
- let packed = check.pack();
- let expect = Vec::from([5u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::SetAuthority {
- authority_type: AuthorityType::FreezeAccount,
- new_authority: COption::Some(Pubkey::new(&[4u8; 32])),
- };
- let packed = check.pack();
- let mut expect = Vec::from([6u8, 1]);
- expect.extend_from_slice(&[1]);
- expect.extend_from_slice(&[4u8; 32]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::MintTo { amount: 1 };
- let packed = check.pack();
- let expect = Vec::from([7u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::Burn { amount: 1 };
- let packed = check.pack();
- let expect = Vec::from([8u8, 1, 0, 0, 0, 0, 0, 0, 0]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::CloseAccount;
- let packed = check.pack();
- let expect = Vec::from([9u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::FreezeAccount;
- let packed = check.pack();
- let expect = Vec::from([10u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::ThawAccount;
- let packed = check.pack();
- let expect = Vec::from([11u8]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::TransferChecked {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack();
- let expect = Vec::from([12u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::ApproveChecked {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack();
- let expect = Vec::from([13u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::MintToChecked {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack();
- let expect = Vec::from([14u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::BurnChecked {
- amount: 1,
- decimals: 2,
- };
- let packed = check.pack();
- let expect = Vec::from([15u8, 1, 0, 0, 0, 0, 0, 0, 0, 2]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- let check = TokenInstruction::InitializeAccount2 {
- owner: Pubkey::new(&[2u8; 32]),
- };
- let packed = check.pack();
- let mut expect = vec![16u8];
- expect.extend_from_slice(&[2u8; 32]);
- assert_eq!(packed, expect);
- let unpacked = TokenInstruction::unpack(&expect).unwrap();
- assert_eq!(unpacked, check);
- }
- }
|