Skip to content

Commit e917f4b

Browse files
author
tilo-14
committed
feat: add native program examples for compressed tokens
- Program instructions: mint, transfer, approve, revoke, burn, freeze, thaw, close - Rust SBF integration tests - TypeScript tests using light-sdk
1 parent d89ade0 commit e917f4b

40 files changed

Lines changed: 11885 additions & 0 deletions

program-examples/native/Cargo.lock

Lines changed: 8651 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program-examples/native/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[workspace]
2+
members = ["program"]
3+
resolver = "2"
4+
5+
[workspace.dependencies]
6+
# Pin to match light-protocol Cargo.lock
7+
constant_time_eq = "=0.3.1"
8+
blake3 = "=1.5.5"
9+
10+
[profile.release]
11+
overflow-checks = true
12+
lto = "fat"
13+
codegen-units = 1
14+
15+
[profile.release.build-override]
16+
opt-level = 3
17+
incremental = false
18+
codegen-units = 1
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "light-token-examples-native",
3+
"version": "1.0.0",
4+
"license": "MIT",
5+
"scripts": {
6+
"test:ts": "ts-mocha -p ./tsconfig.json -t 1000000 ts-tests/*.test.ts"
7+
},
8+
"dependencies": {
9+
"@coral-xyz/anchor": "0.30.1",
10+
"@lightprotocol/stateless.js": "0.22.1-alpha.7",
11+
"@lightprotocol/compressed-token": "0.22.1-alpha.8",
12+
"dotenv": "^16.5.0"
13+
},
14+
"devDependencies": {
15+
"@types/bn.js": "^5.1.0",
16+
"@types/chai": "^4.3.0",
17+
"@types/mocha": "^9.0.0",
18+
"chai": "^4.3.4",
19+
"mocha": "^9.0.3",
20+
"ts-mocha": "^10.1.0",
21+
"typescript": "^5.0.0"
22+
}
23+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "light-token-ops"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib", "lib"]
8+
9+
[features]
10+
no-entrypoint = []
11+
test-sbf = []
12+
default = []
13+
14+
[dependencies]
15+
light-token-sdk = { git = "https://github.com/Lightprotocol/light-protocol", branch = "jorrit/chore-fix-token-sdk" }
16+
solana-program = "2.2"
17+
borsh = "0.10.4"
18+
19+
[dev-dependencies]
20+
light-program-test = { git = "https://github.com/Lightprotocol/light-protocol", branch = "jorrit/chore-fix-token-sdk", features = ["v2"] }
21+
light-client = { git = "https://github.com/Lightprotocol/light-protocol", branch = "jorrit/chore-fix-token-sdk", features = ["v2"] }
22+
light-token-interface = { git = "https://github.com/Lightprotocol/light-protocol", branch = "jorrit/chore-fix-token-sdk" }
23+
tokio = { version = "1", features = ["full"] }
24+
solana-sdk = "2"
25+
anchor-spl = "0.31"
26+
spl-token = "7"
27+
spl-token-2022 = "7"
28+
spl-pod = "0.5"
29+
blake3 = "=1.5.5"
30+
31+
[lints.rust.unexpected_cfgs]
32+
level = "allow"
33+
check-cfg = [
34+
'cfg(target_os, values("solana"))',
35+
'cfg(feature, values("frozen-abi", "no-entrypoint"))',
36+
]
37+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use super::authority_seeds;
2+
use light_token_sdk::token::ApproveCpi;
3+
use solana_program::{
4+
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
5+
};
6+
7+
pub fn process(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
8+
let [token_account, delegate, owner, system_program, _token_program] = accounts else {
9+
return Err(ProgramError::NotEnoughAccountKeys);
10+
};
11+
12+
let amount = u64::from_le_bytes(
13+
data.try_into()
14+
.map_err(|_| ProgramError::InvalidInstructionData)?,
15+
);
16+
17+
ApproveCpi {
18+
token_account: token_account.clone(),
19+
delegate: delegate.clone(),
20+
owner: owner.clone(),
21+
system_program: system_program.clone(),
22+
amount,
23+
}
24+
.invoke()
25+
}
26+
27+
pub fn process_signed(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
28+
let [token_account, delegate, owner, system_program, _token_program] = accounts else {
29+
return Err(ProgramError::NotEnoughAccountKeys);
30+
};
31+
32+
if data.len() < 9 {
33+
return Err(ProgramError::InvalidInstructionData);
34+
}
35+
36+
let amount = u64::from_le_bytes(data[0..8].try_into().unwrap());
37+
let bump = data[8];
38+
let signer_seeds = authority_seeds!(bump);
39+
40+
ApproveCpi {
41+
token_account: token_account.clone(),
42+
delegate: delegate.clone(),
43+
owner: owner.clone(),
44+
system_program: system_program.clone(),
45+
amount,
46+
}
47+
.invoke_signed(&[signer_seeds])
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use super::authority_seeds;
2+
use light_token_sdk::token::BurnCpi;
3+
use solana_program::{
4+
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
5+
};
6+
7+
pub fn process(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
8+
let [source, mint, authority, _token_program] = accounts else {
9+
return Err(ProgramError::NotEnoughAccountKeys);
10+
};
11+
12+
let amount = u64::from_le_bytes(
13+
data.try_into()
14+
.map_err(|_| ProgramError::InvalidInstructionData)?,
15+
);
16+
17+
BurnCpi {
18+
source: source.clone(),
19+
mint: mint.clone(),
20+
amount,
21+
authority: authority.clone(),
22+
max_top_up: None,
23+
}
24+
.invoke()
25+
}
26+
27+
pub fn process_signed(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
28+
let [source, mint, authority, _token_program] = accounts else {
29+
return Err(ProgramError::NotEnoughAccountKeys);
30+
};
31+
32+
if data.len() < 9 {
33+
return Err(ProgramError::InvalidInstructionData);
34+
}
35+
36+
let amount = u64::from_le_bytes(data[0..8].try_into().unwrap());
37+
let bump = data[8];
38+
let signer_seeds = authority_seeds!(bump);
39+
40+
BurnCpi {
41+
source: source.clone(),
42+
mint: mint.clone(),
43+
amount,
44+
authority: authority.clone(),
45+
max_top_up: None,
46+
}
47+
.invoke_signed(&[signer_seeds])
48+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use super::authority_seeds;
2+
use light_token_sdk::token::CloseAccountCpi;
3+
use solana_program::{
4+
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
5+
};
6+
7+
pub fn process(accounts: &[AccountInfo], _data: &[u8]) -> ProgramResult {
8+
let [token_program, account, destination, owner, rent_sponsor] = accounts else {
9+
return Err(ProgramError::NotEnoughAccountKeys);
10+
};
11+
12+
CloseAccountCpi {
13+
token_program: token_program.clone(),
14+
account: account.clone(),
15+
destination: destination.clone(),
16+
owner: owner.clone(),
17+
rent_sponsor: rent_sponsor.clone(),
18+
}
19+
.invoke()
20+
}
21+
22+
pub fn process_signed(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
23+
let [token_program, account, destination, owner, rent_sponsor] = accounts else {
24+
return Err(ProgramError::NotEnoughAccountKeys);
25+
};
26+
27+
if data.is_empty() {
28+
return Err(ProgramError::InvalidInstructionData);
29+
}
30+
31+
let bump = data[0];
32+
let signer_seeds = authority_seeds!(bump);
33+
34+
CloseAccountCpi {
35+
token_program: token_program.clone(),
36+
account: account.clone(),
37+
destination: destination.clone(),
38+
owner: owner.clone(),
39+
rent_sponsor: rent_sponsor.clone(),
40+
}
41+
.invoke_signed(&[signer_seeds])
42+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use super::authority_seeds;
2+
use light_token_sdk::token::{CompressibleParamsCpi, CreateAssociatedAccountCpi};
3+
use solana_program::{
4+
account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError,
5+
};
6+
7+
pub fn process(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
8+
let [owner, mint, payer, associated_token_account, system_program, compressible_config, rent_sponsor, _token_program] =
9+
accounts
10+
else {
11+
return Err(ProgramError::NotEnoughAccountKeys);
12+
};
13+
14+
if data.is_empty() {
15+
return Err(ProgramError::InvalidInstructionData);
16+
}
17+
18+
let bump = data[0];
19+
let idempotent = data.get(1).copied().unwrap_or(0) != 0;
20+
21+
let compressible = CompressibleParamsCpi::new_ata(
22+
compressible_config.clone(),
23+
rent_sponsor.clone(),
24+
system_program.clone(),
25+
);
26+
27+
CreateAssociatedAccountCpi {
28+
owner: owner.clone(),
29+
mint: mint.clone(),
30+
payer: payer.clone(),
31+
associated_token_account: associated_token_account.clone(),
32+
system_program: system_program.clone(),
33+
bump,
34+
compressible,
35+
idempotent,
36+
}
37+
.invoke()
38+
}
39+
40+
pub fn process_signed(accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
41+
let [owner, mint, payer, associated_token_account, system_program, compressible_config, rent_sponsor, _token_program] =
42+
accounts
43+
else {
44+
return Err(ProgramError::NotEnoughAccountKeys);
45+
};
46+
47+
if data.len() < 3 {
48+
return Err(ProgramError::InvalidInstructionData);
49+
}
50+
51+
let bump = data[0];
52+
let idempotent = data[1] != 0;
53+
let authority_bump = data[2];
54+
let signer_seeds = authority_seeds!(authority_bump);
55+
56+
let compressible = CompressibleParamsCpi::new_ata(
57+
compressible_config.clone(),
58+
rent_sponsor.clone(),
59+
system_program.clone(),
60+
);
61+
62+
CreateAssociatedAccountCpi {
63+
owner: owner.clone(),
64+
mint: mint.clone(),
65+
payer: payer.clone(),
66+
associated_token_account: associated_token_account.clone(),
67+
system_program: system_program.clone(),
68+
bump,
69+
compressible,
70+
idempotent,
71+
}
72+
.invoke_signed(&[signer_seeds])
73+
}

0 commit comments

Comments
 (0)