Skip to content

Commit 37729ba

Browse files
authored
chore: use spl-* crates (#212)
(XC-297) This is a follow-up to #197. Now that the `solana-sdk` dependencies are upgraded to v3, use the `spl_associated_token_account_interface` crate to compute associated token addresses (ATAs) and `spl-token-interface` crate to create an SPL transfer instruction in the `basic_solana` example and integration tests.
1 parent f141f90 commit 37729ba

File tree

12 files changed

+77
-245
lines changed

12 files changed

+77
-245
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ jobs:
3434
- name: 'Check Cargo.toml'
3535
run: cargo sort --workspace --check
3636

37-
# TODO XC-XXX: Re-enable once `sol_rpc_client` v3.0.0 is released and ICP Ninja deployment of `basic_solana` is reverted
37+
# TODO XC-456: Re-enable once `sol_rpc_client` v3.0.0 is released and ICP Ninja deployment of `basic_solana` is reverted
3838
# check-ninja-cargo-toml:
3939
# runs-on: ubuntu-latest
4040
# steps:

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ solana-system-interface = "2.0.0"
8282
solana-transaction = "3.0.0"
8383
solana-transaction-error = "3.0.0"
8484
solana-transaction-status-client-types = "3.0.0"
85+
spl-associated-token-account-interface = "2.0.0"
8586
strum = { version = "0.27.2", features = ["derive"] }
8687
thiserror = "2.0.12"
8788
tokio = "1.47.0"

examples/basic_solana/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ solana-pubkey = { workspace = true, features = ["curve25519"] }
2626
solana-signature = { workspace = true }
2727
solana-system-interface = { workspace = true, features = ["bincode"] }
2828
solana-transaction = { workspace = true, features = ["bincode"] }
29+
spl-associated-token-account-interface = { workspace = true }
2930

3031
[dev-dependencies]
3132
candid = { workspace = true }

examples/basic_solana/src/main.rs

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use basic_solana::{
2-
client, solana_wallet::SolanaWallet, spl, state::init_state, validate_caller_not_anonymous,
3-
InitArg,
2+
client, solana_wallet::SolanaWallet, spl::transfer_instruction_with_program_id,
3+
state::init_state, validate_caller_not_anonymous, InitArg,
44
};
55
use candid::{Nat, Principal};
66
use ic_cdk::{init, post_upgrade, update};
@@ -12,6 +12,10 @@ use solana_message::Message;
1212
use solana_pubkey::Pubkey;
1313
use solana_system_interface::instruction;
1414
use solana_transaction::Transaction;
15+
use spl_associated_token_account_interface::{
16+
address::get_associated_token_address_with_program_id,
17+
instruction::create_associated_token_account_idempotent,
18+
};
1519
use std::str::FromStr;
1620

1721
#[init]
@@ -45,7 +49,7 @@ pub async fn associated_token_account(owner: Option<Principal>, mint_account: St
4549
let owner = owner.unwrap_or_else(validate_caller_not_anonymous);
4650
let wallet = SolanaWallet::new(owner).await;
4751
let mint = Pubkey::from_str(&mint_account).unwrap();
48-
spl::get_associated_token_address(
52+
get_associated_token_address_with_program_id(
4953
wallet.solana_account().as_ref(),
5054
&mint,
5155
&get_account_owner(&mint).await,
@@ -175,30 +179,15 @@ pub async fn create_associated_token_account(
175179
let payer = wallet.solana_account();
176180
let mint = Pubkey::from_str(&mint_account).unwrap();
177181

178-
let (associated_token_account, instruction) = spl::create_associated_token_account_instruction(
182+
let account_owner = get_account_owner(&mint).await;
183+
184+
let instruction = create_associated_token_account_idempotent(
179185
payer.as_ref(),
180186
payer.as_ref(),
181187
&mint,
182-
&get_account_owner(&mint).await,
188+
&account_owner,
183189
);
184190

185-
if let Some(_account) = client
186-
.get_account_info(associated_token_account)
187-
.with_encoding(GetAccountInfoEncoding::Base64)
188-
.send()
189-
.await
190-
.expect_consistent()
191-
.unwrap_or_else(|e| {
192-
panic!("Call to `getAccountInfo` for {associated_token_account} failed: {e}")
193-
})
194-
{
195-
ic_cdk::println!(
196-
"[create_associated_token_account]: Account {} already exists. Skipping creation of associated token account",
197-
associated_token_account
198-
);
199-
return associated_token_account.to_string();
200-
}
201-
202191
let message = Message::new_with_blockhash(
203192
&[instruction],
204193
Some(payer.as_ref()),
@@ -219,7 +208,7 @@ pub async fn create_associated_token_account(
219208
.expect("Call to `sendTransaction` failed")
220209
.to_string();
221210

222-
associated_token_account.to_string()
211+
get_associated_token_address_with_program_id(payer.as_ref(), &mint, &account_owner).to_string()
223212
}
224213

225214
#[update]
@@ -317,16 +306,11 @@ pub async fn send_spl_token(
317306

318307
let token_program = get_account_owner(&mint).await;
319308

320-
let from = spl::get_associated_token_address(payer.as_ref(), &mint, &token_program);
321-
let to = spl::get_associated_token_address(&recipient, &mint, &token_program);
309+
let from = get_associated_token_address_with_program_id(payer.as_ref(), &mint, &token_program);
310+
let to = get_associated_token_address_with_program_id(&recipient, &mint, &token_program);
322311

323-
let instruction = spl::transfer_instruction_with_program_id(
324-
&from,
325-
&to,
326-
payer.as_ref(),
327-
amount,
328-
&token_program,
329-
);
312+
let instruction =
313+
transfer_instruction_with_program_id(&from, &to, payer.as_ref(), amount, &token_program);
330314

331315
let message = Message::new_with_blockhash(
332316
&[instruction],

examples/basic_solana/src/spl.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use solana_instruction::{AccountMeta, Instruction};
2+
use solana_pubkey::Pubkey;
3+
4+
/// Creates an instruction to run the [`Transfer` instruction](https://github.com/solana-program/token/blob/main/interface/src/instruction.rs)
5+
/// in the SPL Token program.
6+
pub fn transfer_instruction_with_program_id(
7+
source_address: &Pubkey,
8+
destination_address: &Pubkey,
9+
authority_address: &Pubkey,
10+
amount: u64,
11+
token_program_id: &Pubkey,
12+
) -> Instruction {
13+
Instruction {
14+
program_id: *token_program_id,
15+
accounts: vec![
16+
AccountMeta::new(*source_address, false),
17+
AccountMeta::new(*destination_address, false),
18+
AccountMeta::new_readonly(*authority_address, true),
19+
],
20+
data: [vec![3], amount.to_le_bytes().to_vec()].concat(), // SPL token program "transfer" instruction
21+
}
22+
}

examples/basic_solana/src/spl/mod.rs

Lines changed: 0 additions & 83 deletions
This file was deleted.

examples/basic_solana/src/spl/tests.rs

Lines changed: 0 additions & 42 deletions
This file was deleted.

integration_tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ solana-signature = { workspace = true }
4040
solana-signer = { workspace = true }
4141
solana-transaction = { workspace = true }
4242
solana-transaction-status-client-types = { workspace = true }
43+
spl-associated-token-account-interface = { workspace = true }
4344
tokio = { workspace = true }
4445
url = { workspace = true }
4546

integration_tests/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use std::{
2525
};
2626

2727
pub mod mock;
28-
pub mod spl;
2928
pub mod wallet;
3029

3130
use mock::{MockOutcall, MockOutcallBuilder};

0 commit comments

Comments
 (0)