Skip to content

Commit 6df9663

Browse files
committed
fix(solana/base): fix support for legacy tokens (CHAIN-1552)
1 parent 130ab80 commit 6df9663

5 files changed

Lines changed: 88 additions & 29 deletions

File tree

base/src/libraries/SVMTokenBridgeLib.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@ library SVMTokenBridgeLib {
88
/// Constants ///
99
//////////////////////////////////////////////////////////////
1010

11-
/// @notice The TokenProgram 2022 ID on Solana.
11+
/// @notice The TokenProgram ID on Solana (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA).
12+
Pubkey private constant _TOKEN_PROGRAM_ID =
13+
Pubkey.wrap(0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9);
14+
15+
/// @notice The TokenProgram 2022 ID on Solana (TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb).
1216
Pubkey private constant _TOKEN_PROGRAM_2022_ID =
1317
Pubkey.wrap(0x06ddf6e1ee758fde18425dbce46ccddab61afc4d83b90d27febdf928d8a18bfc);
1418

@@ -99,7 +103,9 @@ library SVMTokenBridgeLib {
99103
_tokenVaultIxAccount({remoteBridge: remoteBridge, localToken: localToken, remoteToken: remoteToken}); // token_vault
100104
serializedAccounts[2] = SVMLib.serializePubkeyAccount({pubkey: to, isWritable: true, isSigner: false}); // to_token_account
101105
serializedAccounts[3] =
102-
SVMLib.serializePubkeyAccount({pubkey: _TOKEN_PROGRAM_2022_ID, isWritable: false, isSigner: false}); // token_program
106+
SVMLib.serializePubkeyAccount({pubkey: _TOKEN_PROGRAM_ID, isWritable: false, isSigner: false}); // token_program
107+
serializedAccounts[4] =
108+
SVMLib.serializePubkeyAccount({pubkey: _TOKEN_PROGRAM_2022_ID, isWritable: false, isSigner: false}); // token_program_2022
103109

104110
return Ix({
105111
programId: remoteBridge,

solana/programs/token_bridge/src/instructions/base_to_solana/finalize_bridge_spl.rs

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use anchor_lang::prelude::*;
2-
use anchor_spl::token_interface::{self, Mint, TokenAccount, TokenInterface, TransferChecked};
2+
use anchor_spl::{
3+
token::Token,
4+
token_2022::Token2022,
5+
token_interface::{self, Mint, TokenAccount, TransferChecked},
6+
};
37

48
use portal::constants::PORTAL_AUTHORITY_SEED;
59

@@ -31,7 +35,8 @@ pub struct FinalizeBridgeSpl<'info> {
3135
#[account(mut)]
3236
pub to_token_account: InterfaceAccount<'info, TokenAccount>,
3337

34-
pub token_program: Interface<'info, TokenInterface>,
38+
pub token_program: Program<'info, Token>,
39+
pub token_program_2022: Program<'info, Token2022>,
3540
}
3641

3742
pub fn finalize_bridge_spl_handler(
@@ -47,8 +52,15 @@ pub fn finalize_bridge_spl_handler(
4752
&[ctx.bumps.token_vault],
4853
]];
4954

55+
let token_program_info = if ctx.accounts.mint.to_account_info().owner == &anchor_spl::token::ID
56+
{
57+
ctx.accounts.token_program.to_account_info()
58+
} else {
59+
ctx.accounts.token_program_2022.to_account_info()
60+
};
61+
5062
let cpi_ctx = CpiContext::new_with_signer(
51-
ctx.accounts.token_program.to_account_info(),
63+
token_program_info,
5264
TransferChecked {
5365
mint: ctx.accounts.mint.to_account_info(),
5466
from: ctx.accounts.token_vault.to_account_info(),
@@ -64,7 +76,7 @@ pub fn finalize_bridge_spl_handler(
6476
mod tests {
6577
use super::*;
6678

67-
use anchor_lang::InstructionData;
79+
use anchor_lang::{solana_program::native_token::LAMPORTS_PER_SOL, InstructionData};
6880
use anchor_spl::token::spl_token::state::Account as TokenAccount;
6981
use litesvm::LiteSVM;
7082
use solana_instruction::Instruction;
@@ -79,15 +91,21 @@ mod tests {
7991
use crate::{
8092
test_utils::{
8193
mock_mint, mock_remote_call, mock_token_account, mock_token_vault, portal_authority,
82-
SPL_TOKEN_PROGRAM_ID,
8394
},
8495
ID as TOKEN_BRIDGE_PROGRAM_ID,
8596
};
8697

87-
const LAMPORTS_PER_SOL: u64 = 1_000_000_000;
98+
#[test]
99+
fn test_finalize_bridge_spl_success_token() {
100+
test_finalize_bridge_spl_success_token_impl(anchor_spl::token::ID);
101+
}
88102

89103
#[test]
90-
fn test_finalize_bridge_spl_success() {
104+
fn test_finalize_bridge_spl_success_token_2022() {
105+
test_finalize_bridge_spl_success_token_impl(anchor_spl::token_2022::ID);
106+
}
107+
108+
fn test_finalize_bridge_spl_success_token_impl(token_program_id: Pubkey) {
91109
let mut svm = LiteSVM::new();
92110
svm.add_program_from_file(
93111
TOKEN_BRIDGE_PROGRAM_ID,
@@ -113,14 +131,27 @@ mod tests {
113131

114132
// Create mint
115133
let mint = Keypair::new().pubkey();
116-
mock_mint(&mut svm, mint, decimals);
134+
mock_mint(&mut svm, mint, decimals, token_program_id);
117135

118136
// Create token vault with funds
119-
let token_vault = mock_token_vault(&mut svm, mint, remote_token, vault_initial_balance);
137+
let token_vault = mock_token_vault(
138+
&mut svm,
139+
mint,
140+
remote_token,
141+
vault_initial_balance,
142+
token_program_id,
143+
);
120144

121145
// Create destination token account
122146
let to_token_account = Keypair::new().pubkey();
123-
mock_token_account(&mut svm, to_token_account, mint, recipient_pk, 0);
147+
mock_token_account(
148+
&mut svm,
149+
to_token_account,
150+
mint,
151+
recipient_pk,
152+
0,
153+
token_program_id,
154+
);
124155

125156
// Compute the portal authority PDA
126157
let portal_authority = portal_authority();
@@ -131,7 +162,8 @@ mod tests {
131162
mint,
132163
token_vault,
133164
to_token_account,
134-
token_program: SPL_TOKEN_PROGRAM_ID,
165+
token_program: anchor_spl::token::ID,
166+
token_program_2022: anchor_spl::token_2022::ID,
135167
}
136168
.to_account_metas(None)
137169
.into_iter()

solana/programs/token_bridge/src/instructions/base_to_solana/finalize_bridge_token.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,7 @@ mod tests {
8080
use portal::{internal::Ix, ID as PORTAL_PROGRAM_ID};
8181

8282
use crate::{
83-
test_utils::{
84-
mock_remote_call, mock_token_account, mock_wrapped_mint, portal_authority,
85-
SPL_TOKEN_PROGRAM_ID,
86-
},
83+
test_utils::{mock_remote_call, mock_token_account, mock_wrapped_mint, portal_authority},
8784
ID as TOKEN_BRIDGE_PROGRAM_ID,
8885
};
8986

@@ -121,7 +118,14 @@ mod tests {
121118

122119
// Create destination token account (starts with 0 tokens)
123120
let to_token_account = Keypair::new().pubkey();
124-
mock_token_account(&mut svm, to_token_account, wrapped_mint, recipient_pk, 0);
121+
mock_token_account(
122+
&mut svm,
123+
to_token_account,
124+
wrapped_mint,
125+
recipient_pk,
126+
0,
127+
anchor_spl::token_2022::ID,
128+
);
125129

126130
// Compute the portal authority PDA
127131
let portal_authority = portal_authority();
@@ -131,7 +135,7 @@ mod tests {
131135
portal_authority,
132136
mint: wrapped_mint,
133137
to_token_account,
134-
token_program: SPL_TOKEN_PROGRAM_ID,
138+
token_program: anchor_spl::token_2022::ID,
135139
}
136140
.to_account_metas(None)
137141
.into_iter()

solana/programs/token_bridge/src/instructions/base_to_solana/wrap_token.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ mod tests {
224224
use solana_transaction::Transaction;
225225

226226
use crate::{
227-
test_utils::{bridge_authority, mock_messenger, SPL_TOKEN_PROGRAM_ID},
227+
test_utils::{bridge_authority, mock_messenger},
228228
ID as TOKEN_BRIDGE_PROGRAM_ID,
229229
};
230230

@@ -241,6 +241,12 @@ mod tests {
241241
svm.add_program_from_file(PORTAL_PROGRAM_ID, "../../target/deploy/portal.so")
242242
.unwrap();
243243

244+
println!(
245+
"token_2022: {:?}",
246+
hex::encode(anchor_spl::token_2022::ID.to_bytes())
247+
);
248+
println!("token: {:?}", hex::encode(anchor_spl::token::ID.to_bytes()));
249+
244250
// Test parameters
245251
let partial_token_metadata = PartialTokenMetadata {
246252
remote_token: [0x42u8; 20],
@@ -271,7 +277,7 @@ mod tests {
271277
let wrap_token_accounts = crate::accounts::WrapToken {
272278
payer: payer.pubkey(),
273279
mint: wrapped_mint,
274-
token_program: SPL_TOKEN_PROGRAM_ID,
280+
token_program: anchor_spl::token_2022::ID,
275281
bridge_authority: bridge_authority(),
276282
portal: PORTAL_PROGRAM_ID,
277283
gas_fee_receiver: GAS_FEE_RECEIVER,
@@ -303,7 +309,7 @@ mod tests {
303309

304310
// Verify that the mint was created correctly
305311
let mint_account = svm.get_account(&wrapped_mint).unwrap();
306-
assert_eq!(mint_account.owner, SPL_TOKEN_PROGRAM_ID);
312+
assert_eq!(mint_account.owner, anchor_spl::token_2022::ID);
307313

308314
// Deserialize and verify mint properties
309315
let mint_data = mint_account.data;

solana/programs/token_bridge/src/test_utils.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ use crate::{
3030
};
3131
use portal::ID as PORTAL_PROGRAM_ID;
3232

33-
pub const SPL_TOKEN_PROGRAM_ID: Pubkey = anchor_spl::token_2022::ID;
34-
3533
pub fn portal_authority() -> Pubkey {
3634
let (portal_authority, _) = Pubkey::find_program_address(
3735
&[PORTAL_AUTHORITY_SEED, REMOTE_BRIDGE.as_ref()],
@@ -143,8 +141,12 @@ pub fn mock_wrapped_mint(
143141
ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::MetadataPointer])
144142
.unwrap();
145143

144+
println!("account_size: {:?}", account_size);
145+
146146
account_size += token_metadata.tlv_size_of().unwrap();
147147

148+
println!("account_size: {:?}", account_size);
149+
148150
// Full buffer for the mint account
149151
let mut mint_data = vec![0u8; account_size];
150152

@@ -180,7 +182,7 @@ pub fn mock_wrapped_mint(
180182
Account {
181183
lamports: 100 * LAMPORTS_PER_SOL,
182184
data: mint_data,
183-
owner: SPL_TOKEN_PROGRAM_ID,
185+
owner: anchor_spl::token_2022::ID,
184186
executable: false,
185187
rent_epoch: 0,
186188
},
@@ -190,7 +192,7 @@ pub fn mock_wrapped_mint(
190192
wrapped_mint
191193
}
192194

193-
pub fn mock_mint(svm: &mut LiteSVM, mint: Pubkey, decimals: u8) {
195+
pub fn mock_mint(svm: &mut LiteSVM, mint: Pubkey, decimals: u8, token_program_id: Pubkey) {
194196
let mut mint_data = vec![0u8; Mint::LEN];
195197
Mint {
196198
mint_authority: COption::Some(mint),
@@ -206,7 +208,7 @@ pub fn mock_mint(svm: &mut LiteSVM, mint: Pubkey, decimals: u8) {
206208
Account {
207209
lamports: 100 * LAMPORTS_PER_SOL,
208210
data: mint_data,
209-
owner: SPL_TOKEN_PROGRAM_ID,
211+
owner: token_program_id,
210212
executable: false,
211213
rent_epoch: 0,
212214
},
@@ -219,13 +221,21 @@ pub fn mock_token_vault(
219221
mint: Pubkey,
220222
remote_token: [u8; 20],
221223
amount: u64,
224+
token_program_id: Pubkey,
222225
) -> Pubkey {
223226
let (token_vault, _) = Pubkey::find_program_address(
224227
&[TOKEN_VAULT_SEED, mint.as_ref(), remote_token.as_ref()],
225228
&TOKEN_BRIDGE_PROGRAM_ID,
226229
);
227230

228-
mock_token_account(svm, token_vault, mint, token_vault, amount);
231+
mock_token_account(
232+
svm,
233+
token_vault,
234+
mint,
235+
token_vault,
236+
amount,
237+
token_program_id,
238+
);
229239
token_vault
230240
}
231241

@@ -235,6 +245,7 @@ pub fn mock_token_account(
235245
mint: Pubkey,
236246
owner: Pubkey,
237247
amount: u64,
248+
token_program_id: Pubkey,
238249
) {
239250
// Create token account data (SPL Token Account layout)
240251
let mut token_account_data = vec![0u8; 165]; // Token account size
@@ -255,7 +266,7 @@ pub fn mock_token_account(
255266
Account {
256267
lamports: 100 * LAMPORTS_PER_SOL,
257268
data: token_account_data,
258-
owner: SPL_TOKEN_PROGRAM_ID,
269+
owner: token_program_id,
259270
executable: false,
260271
rent_epoch: 0,
261272
},

0 commit comments

Comments
 (0)