Assessment reports>SPL Token Wrap Program>Threat Model>Program: Token Wrap

Program: Token Wrap

Instruction: CreateMint

This instruction creates a wrapped token mint, enabling the wrapping of tokens between the SPL Token and the Token 2022 programs. It establishes a wrapped mint and a backpointer account to link the wrapped mint to its unwrapped counterpart. The caller must prefund the wrapped mint and backpointer accounts with sufficient lamports to cover rent exemption.

Input parameters

  • idempotent: bool: Determines the instruction's behavior if the wrapped mint or backpointer accounts already exist. If true, the instruction is idempotent and will not fail if the accounts are already initialized. If false, it fails if either account is already initialized.

Accounts

  • wrapped_mint_account: The unallocated account that will become the wrapped mint.

    • Signer: No.

    • Init: Yes, the instruction initializes this account as a mint.

    • PDA: Yes, derived using get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id).

    • Mutable: Yes, the account is written to during initialization.

    • Constraints: Must be unallocated initially, address must match the PDA derivation, and must be prefunded with enough lamports to be rent-exempt.

  • wrapped_backpointer_account: The unallocated account that will store the backpointer to the unwrapped mint.

    • Signer: No.

    • Init: Yes, the instruction initializes this account.

    • PDA: Yes, derived using get_wrapped_mint_backpointer_address(wrapped_mint_address).

    • Mutable: Yes, the account is written to during initialization.

    • Constraints: Must be unallocated initially, address must match the PDA derivation, and must be prefunded with enough lamports to be rent-exempt.

  • unwrapped_mint_account: The existing mint account being wrapped.

    • Signer: No.

    • Init: No, it must already exist.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be an initialized mint account.

  • system_program_account: The Solana system program.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the system program ID (solana_system_interface::program::id()).

  • wrapped_token_program_account: The SPL Token program that will manage the wrapped mint (e.g., Token 2022 or the legacy SPL Token program).

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be a valid SPL Token program account.

Additional checks and behavior

  • PDA derivation validation: It verifies that the wrapped_mint_account and wrapped_backpointer_account addresses match their expected PDA derivations based on the unwrapped_mint_address and wrapped_token_program_id, or wrapped_mint_address, respectively.

  • Idempotency: If idempotent is true, the instruction skips initialization if the accounts are already initialized and owned correctly (wrapped mint by the token program, backpointer by the program ID). If false, it fails if either account is initialized.

  • Rent checks: It ensures both wrapped_mint_account and wrapped_backpointer_account have sufficient lamports to meet the rent-exemption threshold for their respective sizes (Mint size and Backpointer size).

  • Mint initialization: The wrapped mint is initialized with the same decimals and freeze authority as the unwrapped mint. The mint authority is set to a PDA derived from the wrapped mint address (get_wrapped_mint_authority).

  • Backpointer initialization: The backpointer account is set to store the unwrapped_mint_address, enabling reverse lookup from wrapped to unwrapped mint.

  • Ownership checks: If idempotent, it verifies that the initialized wrapped_mint_account is owned by the wrapped_token_program_account and the wrapped_backpointer_account is owned by the program ID.

CPI

  • Allocate and assign: It calls allocate and assign via CPI to allocate space and assign ownership of the wrapped_mint_account to the wrapped_token_program_account and the wrapped_backpointer_account to the program ID. These are signed with the PDA seeds.

  • Initialize mint: It calls initialize_mint2 via CPI to initialize the wrapped_mint_account as a mint with the specified decimals, mint authority, and freeze authority.

Instruction: Wrap

This instruction wraps tokens by transferring a specified amount of unwrapped tokens from a user's account to an escrow account, then minting an equivalent amount of wrapped tokens to a recipient account. It facilitates the transition of tokens from one program (e.g., legacy SPL Token) to another (e.g., Token 2022).

Input parameters

  • amount: u64: The number of tokens to wrap. Must be greater than zero.

Accounts

  • recipient_wrapped_token_account: The token account that will receive the newly minted wrapped tokens.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: No.

    • Mutable: Yes, wrapped tokens are minted to this account.

    • Constraints: Must be associated with the wrapped_mint.

  • wrapped_mint: The mint account for the wrapped tokens.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: Yes, derived using get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id).

    • Mutable: Yes, its supply increases as tokens are minted.

    • Constraints: Must be initialized and match the PDA derivation.

  • wrapped_mint_authority: The authority that controls minting for the wrapped mint.

    • Signer: No.

    • Init: No.

    • PDA: Yes, derived using get_wrapped_mint_authority(wrapped_mint_address).

    • Mutable: No.

    • Constraints: Must match the PDA derivation.

  • unwrapped_token_program: The SPL Token program managing the unwrapped tokens (e.g., legacy SPL Token or Token 2022).

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the token program ID for the unwrapped tokens.

  • wrapped_token_program: The SPL Token program managing the wrapped tokens.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the token program ID for the wrapped tokens.

  • unwrapped_token_account: The user's token account containing the unwrapped tokens to wrap.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: Yes, tokens are transferred out of this account.

    • Constraints: Must be associated with the unwrapped_mint.

  • unwrapped_mint: The mint account for the unwrapped tokens.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the mint for the unwrapped tokens.

  • unwrapped_escrow: The escrow account that holds unwrapped tokens after wrapping.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: No.

    • Mutable: Yes, tokens are transferred into this account.

    • Constraints: Must be owned by the wrapped_mint_authority.

  • transfer_authority: The authority that can transfer tokens from the unwrapped_token_account.

    • Signer: Yes, unless it is a multi-sig (then optional).

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must have authority to transfer tokens from the unwrapped_token_account.

  • multisig_signer_pubkeys: Optional additional signers for a multi-sig transfer authority.

    • Signer: Yes, if present.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Required if transfer_authority is a multi-sig — the number of signers must match the multi-sig requirements.

Additional checks and behavior

  • Amount validation: It ensures amount is greater than zero to prevent invalid wraps.

  • Account validation: It verifies that wrapped_mint matches the PDA derived from unwrapped_mint and wrapped_token_program. It confirms wrapped_mint_authority matches the PDA derived from wrapped_mint.

  • Escrow ownership: It checks that unwrapped_escrow is owned by the wrapped_mint_authority.

  • Token transfer: It transfers amount of unwrapped tokens from unwrapped_token_account to unwrapped_escrow.

  • Token minting: It mints amount of wrapped tokens to recipient_wrapped_token_account using the wrapped_mint_authority.

CPI

  • Transfer checked: It calls invoke_transfer_checked to transfer amount of unwrapped tokens from unwrapped_token_account to unwrapped_escrow, using the transfer_authority and any multi-sig signers.

  • Mint to: It calls mint_to via CPI, signed with the wrapped_mint_authority PDA seeds, to mint amount of wrapped tokens to recipient_wrapped_token_account.

Instruction: Unwrap

This instruction unwraps tokens by burning a specified amount of wrapped tokens from a user's account and transferring an equivalent amount of unwrapped tokens from an escrow account to a recipient account. It reverses the wrapping process, returning tokens to their original form.

Input parameters

  • amount: u64: The number of tokens to unwrap. Must be greater than zero.

Accounts

  • unwrapped_escrow: The escrow account holding unwrapped tokens.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: No.

    • Mutable: Yes, tokens are transferred out of this account.

    • Constraints: Must be owned by the wrapped_mint_authority.

  • recipient_unwrapped_token: The token account that will receive the unwrapped tokens.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: No.

    • Mutable: Yes, tokens are transferred into this account.

    • Constraints: Must be associated with the unwrapped_mint.

  • wrapped_mint_authority: The authority that controls the wrapped mint.

    • Signer: No.

    • Init: No.

    • PDA: Yes, derived using get_wrapped_mint_authority(wrapped_mint_address).

    • Mutable: No.

    • Constraints: Must match the PDA derivation.

  • unwrapped_mint: The mint account for the unwrapped tokens.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the mint for the unwrapped tokens.

  • wrapped_token_program: The SPL Token program managing the wrapped tokens.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the token program ID for the wrapped tokens.

  • unwrapped_token_program: The SPL Token program managing the unwrapped tokens.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must be the token program ID for the unwrapped tokens.

  • wrapped_token_account: The user's token account containing the wrapped tokens to unwrap.

    • Signer: No.

    • Init: No.

    • PDA: No.

    • Mutable: Yes, tokens are burned from this account.

    • Constraints: Must be associated with the wrapped_mint.

  • wrapped_mint: The mint account for the wrapped tokens.

    • Signer: No.

    • Init: No, must be preinitialized.

    • PDA: Yes, derived using get_wrapped_mint_address(unwrapped_mint_address, wrapped_token_program_id).

    • Mutable: Yes, its supply decreases as tokens are burned.

    • Constraints: Must be initialized and match the PDA derivation.

  • transfer_authority: The authority that can burn tokens from the wrapped_token_account.

    • Signer: Yes, unless it is a multi-sig (then optional).

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Must have authority to burn tokens from the wrapped_token_account.

  • multisig_signer_pubkeys: Optional additional signers for a multi-sig transfer authority.

    • Signer: Yes, if present.

    • Init: No.

    • PDA: No.

    • Mutable: No.

    • Constraints: Required if transfer_authority is a multi-sig — the number of signers must match the multi-sig requirements.

Additional checks and behavior

  • Amount validation: It ensures amount is greater than zero to prevent invalid unwraps.

  • Account validation: It verifies that wrapped_mint matches the PDA derived from unwrapped_mint and wrapped_token_program. It confirms wrapped_mint_authority matches the PDA derived from wrapped_mint.

  • Token burning: It burns amount of wrapped tokens from wrapped_token_account using the transfer_authority.

  • Token transfer: It transfers amount of unwrapped tokens from unwrapped_escrow to recipient_unwrapped_token using the wrapped_mint_authority.

CPI

  • Burn: It calls burn via CPI to burn amount of wrapped tokens from wrapped_token_account, authorized by transfer_authority and any multi-sig signers.

  • Transfer checked: It calls invoke_transfer_checked to transfer amount of unwrapped tokens from unwrapped_escrow to recipient_unwrapped_token, signed with the wrapped_mint_authority PDA seeds.

Zellic © 2025Back to top ↑