Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
8b9effb
token-wrap: Add interface description for wrapping program between tw…
joncinque Jun 30, 2023
e7b8d3c
build(deps): bump num_enum from 0.5.11 to 0.6.1 (#4666)
dependabot[bot] Jul 3, 2023
9a2b501
Upgrade to solana 1.16.3 (#4679)
samkim-crypto Jul 13, 2023
ff49790
build(deps): bump num_enum from 0.6.1 to 0.7.0 (#5003)
dependabot[bot] Aug 14, 2023
0aedd9c
release: Bump token-2022 and all dependencies (#5189)
joncinque Sep 1, 2023
b1a72d3
build(deps): bump bytemuck from 1.13.1 to 1.14.0 (#5210)
dependabot[bot] Sep 12, 2023
2f6bd0a
Bump repo to 1.16.13 (#5324)
joncinque Sep 21, 2023
d0c593c
release: Bump tlv-account-resolution and dependents (#5367)
joncinque Sep 26, 2023
6b22a64
chore: Bump Solana crates to 1.16.16 (#5494)
joncinque Oct 11, 2023
3778fca
ci: Bump repo to Solana 1.17 (#5575)
joncinque Oct 19, 2023
4303d05
rustfmt: use entrypoint full path
Nov 8, 2023
7f61401
rustfmt: format comments
Nov 8, 2023
0129f63
repo: Update to 1.17.6 (#5863)
joncinque Nov 29, 2023
3e69d86
token-2022: Bump to 1.0.0 for prod release (#5954)
joncinque Dec 8, 2023
a63f79e
token 2022: upgrade sdk to 1.17.13 (#6147)
0x0ece Jan 18, 2024
9837f55
build(deps): bump bytemuck from 1.14.0 to 1.14.1 (#6179)
dependabot[bot] Jan 25, 2024
1bf7ad6
Update solana dependency version to allow 2.0.0 (#6182)
willhickey Jan 26, 2024
89c4c3c
token-2022: Bump to v2 (#6187)
joncinque Jan 26, 2024
5379ac4
Upgrade to solana 1.17.17 (#6189)
samkim-crypto Feb 1, 2024
4c608a5
build(deps): bump bytemuck from 1.14.1 to 1.14.2 (#6231)
dependabot[bot] Feb 7, 2024
982a0a4
build(deps): bump bytemuck from 1.14.2 to 1.14.3 (#6240)
dependabot[bot] Feb 10, 2024
17715e9
Upgrade to Solana 1.18.2 (#6278)
samkim-crypto Feb 29, 2024
af99b43
build(deps): bump bytemuck from 1.14.3 to 1.15.0 (#6415)
dependabot[bot] Mar 13, 2024
74c9288
bump: Bump everything up for new token cli (#6507)
joncinque Mar 28, 2024
e69544d
Bump all crates for token-cli release (#6516)
joncinque Mar 28, 2024
d6ed0cd
Bump solana version to 1.18.11 (#6624)
samkim-crypto Apr 24, 2024
024d5d7
build(deps): bump bytemuck from 1.15.0 to 1.16.0 (#6729)
dependabot[bot] May 14, 2024
9234ad6
build(deps): bump bytemuck from 1.16.0 to 1.16.1 (#6875)
dependabot[bot] Jun 20, 2024
9ca89bd
token: Update to v5 for solana-program 2.0 compatibility (#6907)
joncinque Jun 24, 2024
30a8bcc
deps: Upgrade to Solana v2 (#6908)
joncinque Jun 25, 2024
6f62e0e
token: Bump to v6 for Solana v2 compatibility (#6918)
joncinque Jun 25, 2024
e46f86d
token-2022: Bump to v4 for Solana v2 compatibility (#6930)
joncinque Jun 25, 2024
f183c6b
associated-token-account: Bump to v4 for Solana v2 (#6933)
joncinque Jun 25, 2024
700e068
ci: Bump crates to Solana 2.0.3 (#7047)
joncinque Jul 25, 2024
ce5bd9f
build(deps): bump bytemuck from 1.16.1 to 1.16.3 (#7077)
dependabot[bot] Jul 31, 2024
ff5fe5e
build(deps): bump bytemuck from 1.16.3 to 1.17.0 (#7159)
dependabot[bot] Aug 16, 2024
f020dc9
Publish token-2022 v5.0.0
github-actions[bot] Aug 27, 2024
ad6d473
build(deps): bump bytemuck from 1.17.0 to 1.17.1 (#7209)
dependabot[bot] Aug 28, 2024
fa4bf64
Publish token-2022 v5.0.1
github-actions[bot] Aug 28, 2024
2ddbc4a
Publish token-2022 v5.0.2
github-actions[bot] Sep 3, 2024
32625c1
Publish associated-token-account v4.0.1
github-actions[bot] Sep 3, 2024
6d77050
Publish associated-token-account v5.0.1
github-actions[bot] Sep 3, 2024
ccf9958
build(deps): bump bytemuck from 1.17.1 to 1.18.0 (#7244)
dependabot[bot] Sep 6, 2024
019a022
build(deps): bump bytemuck from 1.18.0 to 1.19.0 (#7345)
dependabot[bot] Oct 14, 2024
79a333a
CI: Update to Solana v2.1 crates (#7416)
joncinque Oct 31, 2024
a01f26a
Publish spl-token v7.0.0
github-actions[bot] Nov 1, 2024
ed1f733
Publish spl-token-2022 v6.0.0
github-actions[bot] Nov 1, 2024
c620ddf
Publish spl-associated-token-account v6.0.0
github-actions[bot] Nov 1, 2024
22c0391
build(deps): bump thiserror from 1.0.68 to 2.0.0 (#7462)
dependabot[bot] Nov 6, 2024
be74dc0
build(deps): bump bytemuck from 1.19.0 to 1.20.0 (#7507)
dependabot[bot] Nov 20, 2024
3ae1930
build(deps): bump bytemuck from 1.20.0 to 1.21.0 (#7608)
dependabot[bot] Dec 23, 2024
0814fe5
Update existing code to use non-local dependencies
joncinque Jan 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "spl-token-wrap"
version = "0.1.0"
description = "Solana Program Library Token Wrap"
authors = ["Solana Maintainers <[email protected]>"]
repository = "https://github.com/solana-labs/solana-program-library"
license = "Apache-2.0"
edition = "2018"

[features]
no-entrypoint = []
test-sbf = []

[dependencies]
bytemuck = { version = "1.21.0", features = ["derive"] }
num_enum = "0.7"
solana-program = "2.1.0"
spl-associated-token-account = { version = "6.0.0", features = ["no-entrypoint"] }
spl-token = { version = "7.0", features = ["no-entrypoint"] }
spl-token-2022 = { version = "6.0.0", features = ["no-entrypoint"] }
thiserror = "2.0"

[lib]
crate-type = ["cdylib", "lib"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[lints]
workspace = true
14 changes: 14 additions & 0 deletions program/src/entrypoint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//! Program entrypoint

#![cfg(all(target_os = "solana", not(feature = "no-entrypoint")))]

use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey};

solana_program::entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
crate::processor::process_instruction(program_id, accounts, instruction_data)
}
81 changes: 81 additions & 0 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! Program instructions

use num_enum::{IntoPrimitive, TryFromPrimitive};

/// Instructions supported by the Token Wrap program
#[derive(Clone, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
#[repr(u8)]
pub enum TokenWrapInstruction {
/// Create a wrapped token mint
///
/// Accounts expected by this instruction:
///
/// 0. `[writeable,signer]` Funding account for mint and backpointer (must
/// be a system account)
/// 1. `[writeable]` Unallocated wrapped mint account to create, address
/// must be: `get_wrapped_mint_address(unwrapped_mint_address,
/// wrapped_token_program_id)`
/// 2. `[writeable]` Unallocated wrapped backpointer account to create
/// `get_wrapped_mint_backpointer_address(wrapped_mint_address)`
/// 3. `[]` Existing unwrapped mint
/// 4. `[]` System program
/// 5. `[]` SPL Token program for wrapped mint
///
/// Data expected by this instruction:
/// * bool: true = idempotent creation, false = non-idempotent creation
CreateMint,

/// Wrap tokens
///
/// Move a user's unwrapped tokens into an escrow account and mint the same
/// number of wrapped tokens into the provided account.
///
/// Accounts expected by this instruction:
///
/// 0. `[writeable]` Unwrapped token account to wrap
/// 1. `[writeable]` Escrow of unwrapped tokens, must be owned by:
/// `get_wrapped_mint_authority(wrapped_mint_address)`
/// 2. `[]` Unwrapped token mint
/// 3. `[writeable]` Wrapped mint, must be initialized, address must be:
/// `get_wrapped_mint_address(unwrapped_mint_address,
/// wrapped_token_program_id)`
/// 4. `[writeable]` Recipient wrapped token account
/// 5. `[]` Escrow mint authority, address must be:
/// `get_wrapped_mint_authority(wrapped_mint)`
/// 6. `[]` SPL Token program for unwrapped mint
/// 7. `[]` SPL Token program for wrapped mint
/// 8. `[signer]` Transfer authority on unwrapped token account
/// 9. ..8+M. `[signer]` (Optional) M multisig signers on unwrapped token
/// account
///
/// Data expected by this instruction:
/// * little-endian u64 representing the amount to wrap
Wrap,

/// Unwrap tokens
///
/// Burn user wrapped tokens and transfer the same amount of unwrapped
/// tokens from the escrow account to the provided account.
///
/// Accounts expected by this instruction:
///
/// 0. `[writeable]` Wrapped token account to unwrap
/// 1. `[writeable]` Wrapped mint, address must be:
/// `get_wrapped_mint_address(unwrapped_mint_address,
/// wrapped_token_program_id)`
/// 2. `[writeable]` Escrow of unwrapped tokens, must be owned by:
/// `get_wrapped_mint_authority(wrapped_mint_address)`
/// 3. `[writeable]` Recipient unwrapped tokens
/// 4. `[]` Unwrapped token mint
/// 5. `[]` Escrow unwrapped token authority
/// `get_wrapped_mint_authority(wrapped_mint)`
/// 6. `[]` SPL Token program for wrapped mint
/// 7. `[]` SPL Token program for unwrapped mint
/// 8. `[signer]` Transfer authority on wrapped token account
/// 9. ..8+M. `[signer]` (Optional) M multisig signers on wrapped token
/// account
///
/// Data expected by this instruction:
/// * little-endian u64 representing the amount to unwrap
Unwrap,
}
116 changes: 116 additions & 0 deletions program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//! Token Wrap program
#![deny(missing_docs)]
#![forbid(unsafe_code)]

mod entrypoint;
pub mod instruction;
pub mod processor;
pub mod state;

// Export current SDK types for downstream users building with a different SDK
// version
pub use solana_program;
use solana_program::pubkey::Pubkey;

solana_program::declare_id!("TwRapQCDhWkZRrDaHfZGuHxkZ91gHDRkyuzNqeU5MgR");

const WRAPPED_MINT_SEED: &[u8] = br"mint";

pub(crate) fn get_wrapped_mint_address_with_seed(
unwrapped_mint: &Pubkey,
wrapped_token_program_id: &Pubkey,
) -> (Pubkey, u8) {
Pubkey::find_program_address(
&get_wrapped_mint_seeds(unwrapped_mint, wrapped_token_program_id),
&id(),
)
}

pub(crate) fn get_wrapped_mint_seeds<'a>(
unwrapped_mint: &'a Pubkey,
wrapped_token_program_id: &'a Pubkey,
) -> [&'a [u8]; 3] {
[
WRAPPED_MINT_SEED,
unwrapped_mint.as_ref(),
wrapped_token_program_id.as_ref(),
]
}

pub(crate) fn _get_wrapped_mint_signer_seeds<'a>(
unwrapped_mint: &'a Pubkey,
wrapped_token_program_id: &'a Pubkey,
bump_seed: &'a [u8],
) -> [&'a [u8]; 4] {
[
WRAPPED_MINT_SEED,
unwrapped_mint.as_ref(),
wrapped_token_program_id.as_ref(),
bump_seed,
]
}

/// Derive the SPL Token wrapped mint address associated with an unwrapped mint
pub fn get_wrapped_mint_address(
unwrapped_mint: &Pubkey,
wrapped_token_program_id: &Pubkey,
) -> Pubkey {
get_wrapped_mint_address_with_seed(unwrapped_mint, wrapped_token_program_id).0
}

const WRAPPED_MINT_AUTHORITY_SEED: &[u8] = br"authority";

pub(crate) fn get_wrapped_mint_authority_seeds(wrapped_mint: &Pubkey) -> [&[u8]; 2] {
[WRAPPED_MINT_AUTHORITY_SEED, wrapped_mint.as_ref()]
}

pub(crate) fn _get_wrapped_mint_authority_signer_seeds<'a>(
wrapped_mint: &'a Pubkey,
bump_seed: &'a [u8],
) -> [&'a [u8]; 3] {
[
WRAPPED_MINT_AUTHORITY_SEED,
wrapped_mint.as_ref(),
bump_seed,
]
}

pub(crate) fn get_wrapped_mint_authority_with_seed(wrapped_mint: &Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(&get_wrapped_mint_authority_seeds(wrapped_mint), &id())
}

/// Derive the SPL Token wrapped mint authority address
pub fn get_wrapped_mint_authority(wrapped_mint: &Pubkey) -> Pubkey {
get_wrapped_mint_authority_with_seed(wrapped_mint).0
}

const WRAPPED_MINT_BACKPOINTER_SEED: &[u8] = br"backpointer";

pub(crate) fn get_wrapped_mint_backpointer_address_seeds(wrapped_mint: &Pubkey) -> [&[u8]; 2] {
[WRAPPED_MINT_BACKPOINTER_SEED, wrapped_mint.as_ref()]
}

pub(crate) fn _get_wrapped_mint_backpointer_address_signer_seeds<'a>(
wrapped_mint: &'a Pubkey,
bump_seed: &'a [u8],
) -> [&'a [u8]; 3] {
[
WRAPPED_MINT_BACKPOINTER_SEED,
wrapped_mint.as_ref(),
bump_seed,
]
}

pub(crate) fn get_wrapped_mint_backpointer_address_with_seed(
wrapped_mint: &Pubkey,
) -> (Pubkey, u8) {
Pubkey::find_program_address(
&get_wrapped_mint_backpointer_address_seeds(wrapped_mint),
&id(),
)
}

/// Derive the SPL Token wrapped mint backpointer address
pub fn get_wrapped_mint_backpointer_address(wrapped_mint: &Pubkey) -> Pubkey {
get_wrapped_mint_backpointer_address_with_seed(wrapped_mint).0
}
26 changes: 26 additions & 0 deletions program/src/processor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Program state processor

use {
crate::instruction::TokenWrapInstruction,
solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey},
spl_token_2022::instruction::decode_instruction_type,
};

/// Instruction processor
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
input: &[u8],
) -> ProgramResult {
match decode_instruction_type(input)? {
TokenWrapInstruction::CreateMint => {
unimplemented!();
}
TokenWrapInstruction::Wrap => {
unimplemented!();
}
TokenWrapInstruction::Unwrap => {
unimplemented!();
}
}
}
24 changes: 24 additions & 0 deletions program/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//! Program state

use {
bytemuck::{Pod, Zeroable},
solana_program::pubkey::Pubkey,
};

/// Backpointer
///
/// Since the backpointer account address is derived from the wrapped mint, it
/// allows clients to easily work with wrapped tokens.
///
/// Try to fetch the account at `get_wrapped_mint_backpointer_address`.
/// * if it doesn't exist, then the token is not wrapped
/// * if it exists, read the data in the account as the unwrapped mint address
///
/// With this info, clients can easily unwrap tokens, even if they don't know
/// the origin.
#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
#[repr(transparent)]
pub struct Backpointer {
/// Address that the wrapped mint is wrapping
pub unwrapped_mint: Pubkey,
}