"""SPL token instructions.""" # pylint: disable=too-many-lines from enum import IntEnum from typing import Any, List, NamedTuple, Optional, Union from solana.publickey import PublicKey from solana.system_program import SYS_PROGRAM_ID from solana.sysvar import SYSVAR_RENT_PUBKEY from solana.transaction import AccountMeta, TransactionInstruction from solana.utils.validate import validate_instruction_keys, validate_instruction_type from spl.token._layouts import INSTRUCTIONS_LAYOUT, InstructionType from spl.token.constants import ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID class AuthorityType(IntEnum): """Specifies the authority type for SetAuthority instructions.""" MINT_TOKENS = 0 """"Authority to mint new tokens.""" FREEZE_ACCOUNT = 1 """Authority to freeze any account associated with the Mint.""" ACCOUNT_OWNER = 2 """Owner of a given token account.""" CLOSE_ACCOUNT = 3 """Authority to close a token account.""" # Instruction Params class InitializeMintParams(NamedTuple): """Initialize token mint transaction params.""" decimals: int """Number of base 10 digits to the right of the decimal place.""" program_id: PublicKey """SPL Token program account.""" mint: PublicKey """Public key of the minter account.""" mint_authority: PublicKey """The authority/multisignature to mint tokens.""" freeze_authority: Optional[PublicKey] = None """The freeze authority/multisignature of the mint.""" class InitializeAccountParams(NamedTuple): """Initialize token account transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Public key of the new account.""" mint: PublicKey """Public key of the minter account.""" owner: PublicKey """Owner of the new account.""" class InitializeMultisigParams(NamedTuple): """Initialize multisig token account transaction params.""" program_id: PublicKey """SPL Token program account.""" multisig: PublicKey """New multisig account address.""" m: int """The number of signers (M) required to validate this multisignature account.""" signers: List[PublicKey] = [] """Addresses of multisig signers.""" class TransferParams(NamedTuple): """Transfer token transaction params.""" program_id: PublicKey """SPL Token program account.""" source: PublicKey """Source account.""" dest: PublicKey """Destination account.""" owner: PublicKey """Owner of the source account.""" amount: int """Number of tokens to transfer.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig.""" class ApproveParams(NamedTuple): """Approve token transaction params.""" program_id: PublicKey """SPL Token program account.""" source: PublicKey """Source account.""" delegate: PublicKey """Delegate account authorized to perform a transfer of tokens from the source account.""" owner: PublicKey """Owner of the source account.""" amount: int """Maximum number of tokens the delegate may transfer.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig.""" class RevokeParams(NamedTuple): """Revoke token transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Source account for which transfer authority is being revoked.""" owner: PublicKey """Owner of the source account.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig.""" class SetAuthorityParams(NamedTuple): """Set token authority transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Public key of the token account.""" authority: AuthorityType """The type of authority to update.""" current_authority: PublicKey """Current authority of the specified type.""" signers: List[PublicKey] = [] """Signing accounts if `current_authority` is a multiSig.""" new_authority: Optional[PublicKey] = None """New authority of the account.""" class MintToParams(NamedTuple): """Mint token transaction params.""" program_id: PublicKey """SPL Token program account.""" mint: PublicKey """Public key of the minter account.""" dest: PublicKey """Public key of the account to mint to.""" mint_authority: PublicKey """The mint authority.""" amount: int """Amount to mint.""" signers: List[PublicKey] = [] """Signing accounts if `mint_authority` is a multiSig.""" class BurnParams(NamedTuple): """Burn token transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Account to burn tokens from.""" mint: PublicKey """Public key of the minter account.""" owner: PublicKey """Owner of the account.""" amount: int """Amount to burn.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig""" class CloseAccountParams(NamedTuple): """Close token account transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Address of account to close.""" dest: PublicKey """Address of account to receive the remaining balance of the closed account.""" owner: PublicKey """Owner of the account.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig""" class FreezeAccountParams(NamedTuple): """Freeze token account transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Account to freeze.""" mint: PublicKey """Public key of the minter account.""" authority: PublicKey """Mint freeze authority""" multi_signers: List[PublicKey] = [] """Signing accounts if `authority` is a multiSig""" class ThawAccountParams(NamedTuple): """Thaw token account transaction params.""" program_id: PublicKey """SPL Token program account.""" account: PublicKey """Account to thaw.""" mint: PublicKey """Public key of the minter account.""" authority: PublicKey """Mint freeze authority""" multi_signers: List[PublicKey] = [] """Signing accounts if `authority` is a multiSig""" class TransferCheckedParams(NamedTuple): """TransferChecked token transaction params.""" program_id: PublicKey """SPL Token program account.""" source: PublicKey """Source account.""" mint: PublicKey """Public key of the minter account.""" dest: PublicKey """Destination account.""" owner: PublicKey """Owner of the source account.""" amount: int """Number of tokens to transfer.""" decimals: int """Amount decimals.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig.""" class ApproveCheckedParams(NamedTuple): """ApproveChecked token transaction params.""" program_id: PublicKey """SPL Token program account.""" source: PublicKey """Source account.""" mint: PublicKey """Public key of the minter account.""" delegate: PublicKey """Delegate account authorized to perform a transfer of tokens from the source account.""" owner: PublicKey """Owner of the source account.""" amount: int """Maximum number of tokens the delegate may transfer.""" decimals: int """Amount decimals.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig.""" class MintToCheckedParams(NamedTuple): """MintToChecked token transaction params.""" program_id: PublicKey """SPL Token program account.""" mint: PublicKey """Public key of the minter account.""" dest: PublicKey """Public key of the account to mint to.""" mint_authority: PublicKey """The mint authority.""" amount: int """Amount to mint.""" decimals: int """Amount decimals.""" signers: List[PublicKey] = [] """Signing accounts if `mint_authority` is a multiSig.""" class BurnCheckedParams(NamedTuple): """BurnChecked token transaction params.""" program_id: PublicKey """SPL Token program account.""" mint: PublicKey """Public key of the minter account.""" account: PublicKey """Account to burn tokens from.""" owner: PublicKey """Owner of the account.""" amount: int """Amount to burn.""" decimals: int """Amount decimals.""" signers: List[PublicKey] = [] """Signing accounts if `owner` is a multiSig""" def __parse_and_validate_instruction( instruction: TransactionInstruction, expected_keys: int, expected_type: InstructionType, ) -> Any: # Returns a Construct container. validate_instruction_keys(instruction, expected_keys) data = INSTRUCTIONS_LAYOUT.parse(instruction.data) validate_instruction_type(data, expected_type) return data def decode_initialize_mint(instruction: TransactionInstruction) -> InitializeMintParams: """Decode an initialize mint token instruction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 2, InstructionType.INITIALIZE_MINT) return InitializeMintParams( decimals=parsed_data.args.decimals, program_id=instruction.program_id, mint=instruction.keys[0].pubkey, mint_authority=PublicKey(parsed_data.args.mint_authority), freeze_authority=PublicKey(parsed_data.args.freeze_authority) if parsed_data.args.freeze_authority_option else None, ) def decode_initialize_account(instruction: TransactionInstruction) -> InitializeAccountParams: """Decode an initialize account token instruction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ _ = __parse_and_validate_instruction(instruction, 4, InstructionType.INITIALIZE_ACCOUNT) return InitializeAccountParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, ) def decode_initialize_multisig(instruction: TransactionInstruction) -> InitializeMultisigParams: """Decode an initialize multisig account token instruction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 2, InstructionType.INITIALIZE_MULTISIG) num_signers = parsed_data.args.m validate_instruction_keys(instruction, 2 + num_signers) return InitializeMultisigParams( program_id=instruction.program_id, multisig=instruction.keys[0].pubkey, signers=[signer.pubkey for signer in instruction.keys[-num_signers:]], m=num_signers, ) def decode_transfer(instruction: TransactionInstruction) -> TransferParams: """Decode a transfer token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.TRANSFER) return TransferParams( program_id=instruction.program_id, source=instruction.keys[0].pubkey, dest=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], amount=parsed_data.args.amount, ) def decode_approve(instruction: TransactionInstruction) -> ApproveParams: """Decode a approve token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.APPROVE) return ApproveParams( program_id=instruction.program_id, source=instruction.keys[0].pubkey, delegate=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], amount=parsed_data.args.amount, ) def decode_revoke(instruction: TransactionInstruction) -> RevokeParams: """Decode a revoke token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ _ = __parse_and_validate_instruction(instruction, 2, InstructionType.REVOKE) return RevokeParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, owner=instruction.keys[1].pubkey, signers=[signer.pubkey for signer in instruction.keys[2:]], ) def decode_set_authority(instruction: TransactionInstruction) -> SetAuthorityParams: """Decode a set authority token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 2, InstructionType.SET_AUTHORITY) return SetAuthorityParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, authority=AuthorityType(parsed_data.args.authority_type), new_authority=PublicKey(parsed_data.args.new_authority) if parsed_data.args.new_authority_option else None, current_authority=instruction.keys[1].pubkey, signers=[signer.pubkey for signer in instruction.keys[2:]], ) def decode_mint_to(instruction: TransactionInstruction) -> MintToParams: """Decode a mint to token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.MINT_TO) return MintToParams( program_id=instruction.program_id, amount=parsed_data.args.amount, mint=instruction.keys[0].pubkey, dest=instruction.keys[1].pubkey, mint_authority=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_burn(instruction: TransactionInstruction) -> BurnParams: """Decode a burn token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.BURN) return BurnParams( program_id=instruction.program_id, amount=parsed_data.args.amount, account=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_close_account(instruction: TransactionInstruction) -> CloseAccountParams: """Decode a close account token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ _ = __parse_and_validate_instruction(instruction, 3, InstructionType.CLOSE_ACCOUNT) return CloseAccountParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, dest=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_freeze_account(instruction: TransactionInstruction) -> FreezeAccountParams: """Decode a freeze account token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ _ = __parse_and_validate_instruction(instruction, 3, InstructionType.FREEZE_ACCOUNT) return FreezeAccountParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, authority=instruction.keys[2].pubkey, multi_signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_thaw_account(instruction: TransactionInstruction) -> ThawAccountParams: """Decode a thaw account token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ _ = __parse_and_validate_instruction(instruction, 3, InstructionType.THAW_ACCOUNT) return ThawAccountParams( program_id=instruction.program_id, account=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, authority=instruction.keys[2].pubkey, multi_signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_transfer_checked(instruction: TransactionInstruction) -> TransferCheckedParams: """Decode a transfer_checked token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 4, InstructionType.TRANSFER2) return TransferCheckedParams( program_id=instruction.program_id, amount=parsed_data.args.amount, decimals=parsed_data.args.decimals, source=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, dest=instruction.keys[2].pubkey, owner=instruction.keys[3].pubkey, signers=[signer.pubkey for signer in instruction.keys[4:]], ) def decode_approve_checked(instruction: TransactionInstruction) -> ApproveCheckedParams: """Decode a approve_checked token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 4, InstructionType.APPROVE2) return ApproveCheckedParams( program_id=instruction.program_id, amount=parsed_data.args.amount, decimals=parsed_data.args.decimals, source=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, delegate=instruction.keys[2].pubkey, owner=instruction.keys[3].pubkey, signers=[signer.pubkey for signer in instruction.keys[4:]], ) def decode_mint_to_checked(instruction: TransactionInstruction) -> MintToCheckedParams: """Decode a mintTo2 token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.MINT_TO2) return MintToCheckedParams( program_id=instruction.program_id, amount=parsed_data.args.amount, decimals=parsed_data.args.decimals, mint=instruction.keys[0].pubkey, dest=instruction.keys[1].pubkey, mint_authority=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], ) def decode_burn_checked(instruction: TransactionInstruction) -> BurnCheckedParams: """Decode a burn_checked token transaction and retrieve the instruction params. Args: instruction: The instruction to decode. Returns: The decoded instruction. """ parsed_data = __parse_and_validate_instruction(instruction, 3, InstructionType.BURN2) return BurnCheckedParams( program_id=instruction.program_id, amount=parsed_data.args.amount, decimals=parsed_data.args.decimals, account=instruction.keys[0].pubkey, mint=instruction.keys[1].pubkey, owner=instruction.keys[2].pubkey, signers=[signer.pubkey for signer in instruction.keys[3:]], ) def __add_signers(keys: List[AccountMeta], owner: PublicKey, signers: List[PublicKey]) -> None: if signers: keys.append(AccountMeta(pubkey=owner, is_signer=False, is_writable=False)) for signer in signers: keys.append(AccountMeta(pubkey=signer, is_signer=True, is_writable=False)) else: keys.append(AccountMeta(pubkey=owner, is_signer=True, is_writable=False)) def __burn_instruction(params: Union[BurnParams, BurnCheckedParams], data: Any) -> TransactionInstruction: keys = [ AccountMeta(pubkey=params.account, is_signer=False, is_writable=True), AccountMeta(pubkey=params.mint, is_signer=False, is_writable=True), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def __freeze_or_thaw_instruction( params: Union[FreezeAccountParams, ThawAccountParams], instruction_type: InstructionType ) -> TransactionInstruction: data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=instruction_type, args=None)) keys = [ AccountMeta(pubkey=params.account, is_signer=False, is_writable=True), AccountMeta(pubkey=params.mint, is_signer=False, is_writable=False), ] __add_signers(keys, params.authority, params.multi_signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def __mint_to_instruction(params: Union[MintToParams, MintToCheckedParams], data: Any) -> TransactionInstruction: keys = [ AccountMeta(pubkey=params.mint, is_signer=False, is_writable=True), AccountMeta(pubkey=params.dest, is_signer=False, is_writable=True), ] __add_signers(keys, params.mint_authority, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def initialize_mint(params: InitializeMintParams) -> TransactionInstruction: """Creates a transaction instruction to initialize a new mint newly. This instruction requires no signers and MUST be included within the same Transaction as the system program's `CreateInstruction` that creates the account being initialized. Otherwise another party can acquire ownership of the uninitialized account. Example: >>> from spl.token.constants import TOKEN_PROGRAM_ID >>> mint_account, mint_authority, freeze_authority, owner = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = InitializeMintParams( ... decimals=6, ... freeze_authority=freeze_authority, ... mint=mint_account, ... mint_authority=mint_authority, ... program_id=TOKEN_PROGRAM_ID, ... ) >>> type(initialize_mint(params)) Returns: The instruction to initialize the mint. """ # noqa: E501 # pylint: disable=line-too-long freeze_authority, opt = (params.freeze_authority, 1) if params.freeze_authority else (PublicKey(0), 0) data = INSTRUCTIONS_LAYOUT.build( dict( instruction_type=InstructionType.INITIALIZE_MINT, args=dict( decimals=params.decimals, mint_authority=bytes(params.mint_authority), freeze_authority_option=opt, freeze_authority=bytes(freeze_authority), ), ) ) return TransactionInstruction( keys=[ AccountMeta(pubkey=params.mint, is_signer=False, is_writable=True), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ], program_id=params.program_id, data=data, ) def initialize_account(params: InitializeAccountParams) -> TransactionInstruction: """Creates a transaction instruction to initialize a new account to hold tokens. This instruction requires no signers and MUST be included within the same Transaction as the system program's `CreateInstruction` that creates the account being initialized. Otherwise another party can acquire ownership of the uninitialized account. Example: >>> account, mint, owner, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = InitializeAccountParams( ... account=account, ... mint=mint, ... owner=owner, ... program_id=token, ... ) >>> type(initialize_account(params)) Returns: The instruction to initialize the account. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.INITIALIZE_ACCOUNT, args=None)) return TransactionInstruction( keys=[ AccountMeta(pubkey=params.account, is_signer=False, is_writable=True), AccountMeta(pubkey=params.mint, is_signer=False, is_writable=False), AccountMeta(pubkey=params.owner, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ], program_id=params.program_id, data=data, ) def initialize_multisig(params: InitializeMultisigParams) -> TransactionInstruction: """Creates a transaction instruction to initialize a multisignature account with N provided signers. This instruction requires no signers and MUST be included within the same Transaction as the system program's `CreateInstruction` that creates the account being initialized. Otherwise another party can acquire ownership of the uninitialized account. Example: >>> m = 2 # Two signers >>> signers = [PublicKey(i) for i in range(m)] >>> multisig_account, token = PublicKey(1), PublicKey(2) >>> params = InitializeMultisigParams( ... m=m, ... multisig=multisig_account, ... signers=signers, ... program_id=token, ... ) >>> type(initialize_multisig(params)) Returns: The instruction to initialize the multisig. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.INITIALIZE_MULTISIG, args=dict(m=params.m))) keys = [ AccountMeta(pubkey=params.multisig, is_signer=False, is_writable=True), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ] for signer in params.signers: keys.append(AccountMeta(pubkey=signer, is_signer=False, is_writable=False)) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def transfer(params: TransferParams) -> TransactionInstruction: """Creates a transaction instruction to transfers tokens from one account to another. Either directly or via a delegate. Example: >>> dest, owner, source, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = TransferParams( ... amount=1000, ... dest=dest, ... owner=owner, ... program_id=token, ... source=source, ... ) >>> type(transfer(params)) Returns: The transfer instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.TRANSFER, args=dict(amount=params.amount))) keys = [ AccountMeta(pubkey=params.source, is_signer=False, is_writable=True), AccountMeta(pubkey=params.dest, is_signer=False, is_writable=True), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def approve(params: ApproveParams) -> TransactionInstruction: """Creates a transaction instruction to approve a delegate. Example: >>> delegate, owner, source, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = ApproveParams( ... amount=123, ... delegate=delegate, ... owner=owner, ... program_id=token, ... source=source ... ) >>> type(approve(params)) Returns: The approve instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.APPROVE, args=dict(amount=params.amount))) keys = [ AccountMeta(pubkey=params.source, is_signer=False, is_writable=True), AccountMeta(pubkey=params.delegate, is_signer=False, is_writable=False), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def revoke(params: RevokeParams) -> TransactionInstruction: """Creates a transaction instruction that revokes delegate authority for a given account. Example: >>> account, owner, token = PublicKey(1), PublicKey(2), PublicKey(3) >>> params = RevokeParams( ... account=account, owner=owner, program_id=token ... ) >>> type(revoke(params)) Returns: The revoke instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.REVOKE, args=None)) keys = [AccountMeta(pubkey=params.account, is_signer=False, is_writable=True)] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def set_authority(params: SetAuthorityParams) -> TransactionInstruction: """Creates a transaction instruction to sets a new authority of a mint or account. Example: >>> account, current_authority, new_authority, token = ( ... PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) ... ) >>> params = SetAuthorityParams( ... account=account, ... authority=AuthorityType.ACCOUNT_OWNER, ... current_authority=current_authority, ... new_authority=new_authority, ... program_id=token, ... ) >>> type(set_authority(params)) Returns: The set authority instruction. """ new_authority, opt = (params.new_authority, 1) if params.new_authority else (PublicKey(0), 0) data = INSTRUCTIONS_LAYOUT.build( dict( instruction_type=InstructionType.SET_AUTHORITY, args=dict(authority_type=params.authority, new_authority_option=opt, new_authority=bytes(new_authority)), ) ) keys = [AccountMeta(pubkey=params.account, is_signer=False, is_writable=True)] __add_signers(keys, params.current_authority, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def mint_to(params: MintToParams) -> TransactionInstruction: """Creates a transaction instruction to mint new tokens to an account. The native mint does not support minting. Example: >>> dest, mint, mint_authority, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = MintToParams( ... amount=123, ... dest=dest, ... mint=mint, ... mint_authority=mint_authority, ... program_id=token, ... ) >>> type(mint_to(params)) Returns: The mint-to instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.MINT_TO, args=dict(amount=params.amount))) return __mint_to_instruction(params, data) def burn(params: BurnParams) -> TransactionInstruction: """Creates a transaction instruction to burns tokens by removing them from an account. Example: >>> account, mint, owner, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = BurnParams( ... amount=123, account=account, mint=mint, owner=owner, program_id=token, ... ) >>> type(burn(params)) Returns: The burn instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.BURN, args=dict(amount=params.amount))) return __burn_instruction(params, data) def close_account(params: CloseAccountParams) -> TransactionInstruction: """Creates a transaction instruction to 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. Example: >>> account, dest, owner, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = CloseAccountParams( ... account=account, dest=dest, owner=owner, program_id=token) >>> type(close_account(params)) Returns: The close-account instruction. """ data = INSTRUCTIONS_LAYOUT.build(dict(instruction_type=InstructionType.CLOSE_ACCOUNT, args=None)) keys = [ AccountMeta(pubkey=params.account, is_signer=False, is_writable=True), AccountMeta(pubkey=params.dest, is_signer=False, is_writable=True), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def freeze_account(params: FreezeAccountParams) -> TransactionInstruction: """Creates a transaction instruction to freeze an initialized account using the mint's freeze_authority (if set). Example: >>> account, mint, authority, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = FreezeAccountParams( ... account=account, mint=mint, authority=authority, program_id=token) >>> type(freeze_account(params)) Returns: The freeze-account instruction. """ return __freeze_or_thaw_instruction(params, InstructionType.FREEZE_ACCOUNT) def thaw_account(params: ThawAccountParams) -> TransactionInstruction: """Creates a transaction instruction to thaw a frozen account using the Mint's freeze_authority (if set). Example: >>> account, mint, authority, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = ThawAccountParams( ... account=account, mint=mint, authority=authority, program_id=token) >>> type(thaw_account(params)) Returns: The thaw-account instruction. """ return __freeze_or_thaw_instruction(params, InstructionType.THAW_ACCOUNT) def transfer_checked(params: TransferCheckedParams) -> TransactionInstruction: """This instruction differs from `transfer` in that the token mint and decimals value is asserted by the caller. Example: >>> dest, mint, owner, source, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4), PublicKey(5) >>> params = TransferCheckedParams( ... amount=1000, ... decimals=6, ... dest=dest, ... mint=mint, ... owner=owner, ... program_id=token, ... source=source, ... ) >>> type(transfer_checked(params)) Returns: The transfer-checked instruction. """ data = INSTRUCTIONS_LAYOUT.build( dict(instruction_type=InstructionType.TRANSFER2, args=dict(amount=params.amount, decimals=params.decimals)) ) keys = [ AccountMeta(pubkey=params.source, is_signer=False, is_writable=True), AccountMeta(pubkey=params.mint, is_signer=False, is_writable=False), AccountMeta(pubkey=params.dest, is_signer=False, is_writable=True), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def approve_checked(params: ApproveCheckedParams) -> TransactionInstruction: """This instruction differs from `approve` in that the token mint and decimals value is asserted by the caller. Example: >>> delegate, mint, owner, source, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4), PublicKey(5) >>> params = ApproveCheckedParams( ... amount=1000, ... decimals=6, ... delegate=delegate, ... mint=mint, ... owner=owner, ... program_id=token, ... source=source, ... ) >>> type(approve_checked(params)) Returns: The approve-checked instruction. """ data = INSTRUCTIONS_LAYOUT.build( dict(instruction_type=InstructionType.APPROVE2, args=dict(amount=params.amount, decimals=params.decimals)) ) keys = [ AccountMeta(pubkey=params.source, is_signer=False, is_writable=True), AccountMeta(pubkey=params.mint, is_signer=False, is_writable=False), AccountMeta(pubkey=params.delegate, is_signer=False, is_writable=False), ] __add_signers(keys, params.owner, params.signers) return TransactionInstruction(keys=keys, program_id=params.program_id, data=data) def mint_to_checked(params: MintToCheckedParams) -> TransactionInstruction: """This instruction differs from `mint_to` in that the decimals value is asserted by the caller. Example: >>> dest, mint, mint_authority, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = MintToCheckedParams( ... amount=123, ... decimals=6, ... dest=dest, ... mint=mint, ... mint_authority=mint_authority, ... program_id=token, ... ) >>> type(mint_to_checked(params)) Returns: The mint-to-checked instruction. """ data = INSTRUCTIONS_LAYOUT.build( dict(instruction_type=InstructionType.MINT_TO2, args=dict(amount=params.amount, decimals=params.decimals)) ) return __mint_to_instruction(params, data) def burn_checked(params: BurnCheckedParams) -> TransactionInstruction: """This instruction differs from `burn` in that the decimals value is asserted by the caller. Example: >>> account, mint, owner, token = PublicKey(1), PublicKey(2), PublicKey(3), PublicKey(4) >>> params = BurnCheckedParams( ... amount=123, account=account, decimals=6, mint=mint, owner=owner, program_id=token, ... ) >>> type(burn_checked(params)) Returns: The burn-checked instruction. """ data = INSTRUCTIONS_LAYOUT.build( dict(instruction_type=InstructionType.BURN2, args=dict(amount=params.amount, decimals=params.decimals)) ) return __burn_instruction(params, data) def get_associated_token_address(owner: PublicKey, mint: PublicKey) -> PublicKey: """Derives the associated token address for the given wallet address and token mint. Returns: The public key of the derived associated token address. """ key, _ = PublicKey.find_program_address( seeds=[bytes(owner), bytes(TOKEN_PROGRAM_ID), bytes(mint)], program_id=ASSOCIATED_TOKEN_PROGRAM_ID ) return key def create_associated_token_account(payer: PublicKey, owner: PublicKey, mint: PublicKey) -> TransactionInstruction: """Creates a transaction instruction to create an associated token account. Returns: The instruction to create the associated token account. """ associated_token_address = get_associated_token_address(owner, mint) return TransactionInstruction( keys=[ AccountMeta(pubkey=payer, is_signer=True, is_writable=True), AccountMeta(pubkey=associated_token_address, is_signer=False, is_writable=True), AccountMeta(pubkey=owner, is_signer=False, is_writable=False), AccountMeta(pubkey=mint, is_signer=False, is_writable=False), AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), ], program_id=ASSOCIATED_TOKEN_PROGRAM_ID, )