Skip to content

Commit a57c99c

Browse files
authored
Fix: Wrong ATA init instruction generation (#1020)
* fix wrong arg on create_associated_token_account * changeset
1 parent 0bff540 commit a57c99c

File tree

2 files changed

+169
-32
lines changed

2 files changed

+169
-32
lines changed

.changeset/icy-aliens-enjoy.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@orca-so/whirlpools-rust": patch
3+
---
4+
5+
Fix wrong ATA init instruction generation

rust-sdk/whirlpool/src/token.rs

Lines changed: 164 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ pub(crate) async fn prepare_token_accounts_instructions(
9393
}
9494

9595
create_instructions.push(create_associated_token_account(
96-
&owner,
97-
&ata_address,
96+
// ATA address will be derived in the function
97+
&owner, // funder
98+
&owner, // owner
9899
&mint_address,
99100
&mint_account_infos[i].owner,
100101
));
@@ -366,7 +367,7 @@ mod tests {
366367
setup_mint_te_fee, RpcContext,
367368
};
368369
use serial_test::serial;
369-
use spl_associated_token_account::instruction::create_associated_token_account_idempotent;
370+
370371
use std::str::FromStr;
371372

372373
// 1. Basic Utility Tests
@@ -395,6 +396,9 @@ mod tests {
395396

396397
// Verify empty result
397398
assert_eq!(result.token_account_addresses.len(), 0);
399+
assert_eq!(result.create_instructions.len(), 0);
400+
assert_eq!(result.cleanup_instructions.len(), 0);
401+
assert_eq!(result.additional_signers.len(), 0);
398402
}
399403

400404
#[tokio::test]
@@ -417,24 +421,90 @@ mod tests {
417421
.await
418422
.unwrap();
419423

424+
// Verify result
425+
assert_eq!(result.token_account_addresses.len(), 1);
420426
assert_eq!(result.token_account_addresses[&mint], ata);
427+
assert_eq!(result.create_instructions.len(), 1);
428+
assert_eq!(result.cleanup_instructions.len(), 0);
429+
assert_eq!(result.additional_signers.len(), 0);
430+
431+
// Verify uninitialized state
432+
let account = ctx.rpc.get_account(&ata).await;
433+
assert!(account
434+
.err()
435+
.unwrap()
436+
.to_string()
437+
.contains("AccountNotFound"));
421438

422-
// Use idempotent version of create ATA
423-
let mut instructions = vec![create_associated_token_account_idempotent(
424-
&ctx.signer.pubkey(),
439+
// Verify instruction
440+
ctx.send_transaction(result.create_instructions)
441+
.await
442+
.unwrap();
443+
444+
// Verify initialized account
445+
let account = ctx.rpc.get_account(&ata).await.unwrap();
446+
let token_account = Account::unpack(&account.data).unwrap();
447+
assert_eq!(token_account.amount, 0);
448+
assert_eq!(token_account.mint, mint);
449+
assert_eq!(token_account.owner, ctx.signer.pubkey());
450+
}
451+
452+
#[tokio::test]
453+
#[serial]
454+
async fn test_token_without_balance_multiple_with_te() {
455+
let ctx = RpcContext::new().await;
456+
let mint0 = setup_mint(&ctx).await.unwrap();
457+
let mint1 = setup_mint_te(&ctx, &[]).await.unwrap();
458+
459+
let ata0 = get_associated_token_address_with_program_id(
425460
&ctx.signer.pubkey(),
426-
&mint,
461+
&mint0,
427462
&TOKEN_PROGRAM_ID,
428-
)];
429-
instructions.extend(result.create_instructions);
463+
);
464+
let ata1 = get_associated_token_address_with_program_id(
465+
&ctx.signer.pubkey(),
466+
&mint1,
467+
&TOKEN_2022_PROGRAM_ID,
468+
);
469+
470+
let result = prepare_token_accounts_instructions(
471+
&ctx.rpc,
472+
ctx.signer.pubkey(),
473+
vec![
474+
TokenAccountStrategy::WithoutBalance(mint0),
475+
TokenAccountStrategy::WithoutBalance(mint1),
476+
],
477+
)
478+
.await
479+
.unwrap();
430480

431-
ctx.send_transaction(instructions).await.unwrap();
481+
// Verify result
482+
assert_eq!(result.token_account_addresses.len(), 2);
483+
assert_eq!(result.token_account_addresses[&mint0], ata0);
484+
assert_eq!(result.token_account_addresses[&mint1], ata1);
485+
assert_eq!(result.create_instructions.len(), 2);
486+
assert_eq!(result.cleanup_instructions.len(), 0);
487+
assert_eq!(result.additional_signers.len(), 0);
432488

433-
let account = ctx.rpc.get_account(&ata).await.unwrap();
489+
// Verify instruction
490+
ctx.send_transaction(result.create_instructions)
491+
.await
492+
.unwrap();
493+
494+
// Verify initialized account
495+
let account = ctx.rpc.get_account(&ata0).await.unwrap();
496+
assert_eq!(account.owner, TOKEN_PROGRAM_ID);
434497
let token_account = Account::unpack(&account.data).unwrap();
435498
assert_eq!(token_account.amount, 0);
436-
assert_eq!(token_account.mint, mint);
499+
assert_eq!(token_account.mint, mint0);
437500
assert_eq!(token_account.owner, ctx.signer.pubkey());
501+
502+
let account = ctx.rpc.get_account(&ata1).await.unwrap();
503+
assert_eq!(account.owner, TOKEN_2022_PROGRAM_ID);
504+
let token_account = StateWithExtensions::<Account>::unpack(&account.data).unwrap();
505+
assert_eq!(token_account.base.amount, 0);
506+
assert_eq!(token_account.base.mint, mint1);
507+
assert_eq!(token_account.base.owner, ctx.signer.pubkey());
438508
}
439509

440510
#[tokio::test]
@@ -458,6 +528,13 @@ mod tests {
458528
.await
459529
.unwrap();
460530

531+
// Verify result
532+
assert_eq!(result.token_account_addresses.len(), 1);
533+
assert_eq!(result.token_account_addresses[&mint], ata);
534+
assert_eq!(result.create_instructions.len(), 0);
535+
assert_eq!(result.cleanup_instructions.len(), 0);
536+
assert_eq!(result.additional_signers.len(), 0);
537+
461538
// Verify account state
462539
let account = ctx.rpc.get_account(&ata).await.unwrap();
463540
let token_account = Account::unpack(&account.data).unwrap();
@@ -592,6 +669,13 @@ mod tests {
592669
.await
593670
.unwrap();
594671

672+
// Verify result
673+
assert_eq!(result.token_account_addresses.len(), 1);
674+
assert_eq!(result.token_account_addresses[&mint], ata);
675+
assert_eq!(result.create_instructions.len(), 0);
676+
assert_eq!(result.cleanup_instructions.len(), 0);
677+
assert_eq!(result.additional_signers.len(), 0);
678+
595679
// Verify account wasn't modified
596680
let final_account = ctx.rpc.get_account(&ata).await.unwrap();
597681
assert_eq!(initial_account.data, final_account.data);
@@ -618,22 +702,32 @@ mod tests {
618702
.await
619703
.unwrap();
620704

705+
// Verify result
706+
assert_eq!(result.token_account_addresses.len(), 1);
621707
assert_eq!(result.token_account_addresses[&native_mint::ID], ata);
708+
assert_eq!(result.create_instructions.len(), 1);
709+
assert_eq!(result.cleanup_instructions.len(), 0);
710+
assert_eq!(result.additional_signers.len(), 0);
711+
712+
// Verify uninitialized state
713+
let account = ctx.rpc.get_account(&ata).await;
714+
assert!(account
715+
.err()
716+
.unwrap()
717+
.to_string()
718+
.contains("AccountNotFound"));
622719

623-
// Use idempotent version of create ATA
624-
let mut instructions = vec![create_associated_token_account_idempotent(
625-
&ctx.signer.pubkey(),
626-
&ctx.signer.pubkey(),
627-
&native_mint::ID,
628-
&TOKEN_PROGRAM_ID,
629-
)];
630-
instructions.extend(result.create_instructions);
631-
632-
ctx.send_transaction(instructions).await.unwrap();
720+
// Verify instruction
721+
ctx.send_transaction(result.create_instructions)
722+
.await
723+
.unwrap();
633724

725+
// Verify initialized account
634726
let account = ctx.rpc.get_account(&ata).await.unwrap();
635727
let token_account = Account::unpack(&account.data).unwrap();
636728
assert_eq!(token_account.amount, 0);
729+
assert_eq!(token_account.mint, native_mint::ID);
730+
assert_eq!(token_account.owner, ctx.signer.pubkey());
637731
}
638732

639733
#[tokio::test]
@@ -656,24 +750,41 @@ mod tests {
656750
.await
657751
.unwrap();
658752

753+
// Verify result
754+
assert_eq!(result.token_account_addresses.len(), 1);
659755
assert_eq!(result.token_account_addresses[&native_mint::ID], ata);
756+
assert_eq!(result.create_instructions.len(), 1);
757+
assert_eq!(result.cleanup_instructions.len(), 1);
758+
assert_eq!(result.additional_signers.len(), 0);
759+
760+
// Verify uninitialized state
761+
let account = ctx.rpc.get_account(&ata).await;
762+
assert!(account
763+
.err()
764+
.unwrap()
765+
.to_string()
766+
.contains("AccountNotFound"));
660767

661-
// Use idempotent version of create ATA
662-
let mut instructions = vec![create_associated_token_account_idempotent(
663-
&ctx.signer.pubkey(),
664-
&ctx.signer.pubkey(),
665-
&native_mint::ID,
666-
&TOKEN_PROGRAM_ID,
667-
)];
668-
instructions.extend(result.create_instructions);
669-
670-
ctx.send_transaction(instructions).await.unwrap();
768+
// Verify instruction
769+
ctx.send_transaction(result.create_instructions)
770+
.await
771+
.unwrap();
671772

773+
// Verify initialized account
672774
let account = ctx.rpc.get_account(&ata).await.unwrap();
673775
let token_account = Account::unpack(&account.data).unwrap();
674776
assert_eq!(token_account.amount, 0);
675777
assert_eq!(token_account.mint, native_mint::ID);
676778
assert_eq!(token_account.owner, ctx.signer.pubkey());
779+
780+
// Execute cleanup instructions
781+
ctx.send_transaction(result.cleanup_instructions)
782+
.await
783+
.unwrap();
784+
785+
// Verify account was cleaned up
786+
let accounts = ctx.rpc.get_multiple_accounts(&[ata]).await.unwrap();
787+
assert!(accounts[0].is_none() || accounts[0].as_ref().unwrap().data.is_empty());
677788
}
678789

679790
#[tokio::test]
@@ -692,10 +803,14 @@ mod tests {
692803
.unwrap();
693804

694805
// Verify token account address is mapped correctly
806+
assert_eq!(result.token_account_addresses.len(), 1);
695807
assert!(result
696808
.token_account_addresses
697809
.contains_key(&native_mint::ID));
698810
let token_address = result.token_account_addresses[&native_mint::ID];
811+
assert_eq!(result.create_instructions.len(), 2); // create account + initialize (token) account 3
812+
assert_eq!(result.cleanup_instructions.len(), 1);
813+
assert_eq!(result.additional_signers.len(), 1);
699814

700815
// Execute create instructions
701816
ctx.send_transaction_with_signers(
@@ -747,10 +862,14 @@ mod tests {
747862
.unwrap();
748863

749864
// Verify token account address is mapped correctly
865+
assert_eq!(result.token_account_addresses.len(), 1);
750866
assert!(result
751867
.token_account_addresses
752868
.contains_key(&native_mint::ID));
753869
let token_address = result.token_account_addresses[&native_mint::ID];
870+
assert_eq!(result.create_instructions.len(), 2); // create account with seed + initialize (token) account 3
871+
assert_eq!(result.cleanup_instructions.len(), 1);
872+
assert_eq!(result.additional_signers.len(), 0);
754873

755874
// Execute and verify using get_multiple_accounts
756875
ctx.send_transaction_with_signers(
@@ -768,6 +887,19 @@ mod tests {
768887
let account = accounts[0].as_ref().unwrap();
769888
let token_account = Account::unpack(&account.data).unwrap();
770889
assert_eq!(token_account.amount, amount);
890+
891+
// Execute cleanup instructions
892+
ctx.send_transaction(result.cleanup_instructions)
893+
.await
894+
.unwrap();
895+
896+
// Verify account was cleaned up
897+
let accounts = ctx
898+
.rpc
899+
.get_multiple_accounts(&[token_address])
900+
.await
901+
.unwrap();
902+
assert!(accounts[0].is_none() || accounts[0].as_ref().unwrap().data.is_empty());
771903
}
772904

773905
#[tokio::test]

0 commit comments

Comments
 (0)