-
Notifications
You must be signed in to change notification settings - Fork 51
Adding execute rust test and fixing freeze_execute test #238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| //! Integration tests for the ExecuteV1 instruction. | ||
| #![cfg(feature = "test-sbf")] | ||
|
|
||
| pub mod setup; | ||
| use mpl_core::instructions::ExecuteV1Builder; | ||
| use setup::*; | ||
|
|
||
| use solana_program::{ | ||
| instruction::AccountMeta, pubkey::Pubkey, system_instruction, system_program, | ||
| }; | ||
| use solana_program_test::tokio; | ||
| use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; | ||
|
|
||
| const EXECUTE_PREFIX: &str = "mpl-core-execute"; | ||
|
|
||
| #[tokio::test] | ||
| async fn test_execute() { | ||
| // ---------------------------------- | ||
| // 0. Test setup | ||
| // ---------------------------------- | ||
| let mut context = program_test().start_with_context().await; | ||
|
|
||
| // Fund payer so we can deposit SOL to the asset later. | ||
| let payer_key = context.payer.pubkey(); | ||
| airdrop(&mut context, &payer_key, 2_000_000_000) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| // ---------------------------------- | ||
| // 1. Mint an asset | ||
| // ---------------------------------- | ||
| let asset = Keypair::new(); | ||
| create_asset( | ||
| &mut context, | ||
| CreateAssetHelperArgs { | ||
| owner: None, | ||
| payer: None, | ||
| asset: &asset, | ||
| data_state: None, | ||
| name: None, | ||
| uri: None, | ||
| authority: None, | ||
| update_authority: None, | ||
| collection: None, | ||
| plugins: vec![], | ||
| external_plugin_adapters: vec![], | ||
| }, | ||
| ) | ||
| .await | ||
| .unwrap(); | ||
|
|
||
| assert_asset( | ||
| &mut context, | ||
| AssertAssetHelperArgs { | ||
| asset: asset.pubkey(), | ||
| owner: payer_key, | ||
| update_authority: None, | ||
| name: None, | ||
| uri: None, | ||
| plugins: vec![], | ||
| external_plugin_adapters: vec![], | ||
| }, | ||
| ) | ||
| .await; | ||
|
|
||
| // ---------------------------------- | ||
| // 2. Deposit backing SOL into the asset account (simulate 0.5 SOL backing) | ||
| // ---------------------------------- | ||
| let (asset_signer, _) = Pubkey::find_program_address( | ||
| &[EXECUTE_PREFIX.as_bytes(), asset.pubkey().as_ref()], | ||
| &mpl_core::ID, | ||
| ); | ||
|
|
||
| let backing_amount: u64 = 500_000_000; // 0.5 SOL | ||
| let transfer_ix = system_instruction::transfer(&payer_key, &asset_signer, backing_amount); | ||
| let tx = Transaction::new_signed_with_payer( | ||
| &[transfer_ix], | ||
| Some(&payer_key), | ||
| &[&context.payer], | ||
| context.last_blockhash, | ||
| ); | ||
| context.banks_client.process_transaction(tx).await.unwrap(); | ||
|
|
||
| // Capture lamports held by the asset account after deposit. | ||
| let lamports_in_asset = context | ||
| .banks_client | ||
| .get_balance(asset_signer) | ||
| .await | ||
| .expect("get_balance failed"); | ||
|
|
||
| // Verify that the deposit was successful. | ||
| assert_eq!(lamports_in_asset, backing_amount); | ||
|
|
||
| // ---------------------------------- | ||
| // 3. Execute → Transfer funds from asset_signer to payer. | ||
| // ---------------------------------- | ||
| let execute_transfer_ix = | ||
| system_instruction::transfer(&asset_signer, &payer_key, lamports_in_asset); | ||
|
|
||
| let execute_ix = ExecuteV1Builder::new() | ||
| .asset(asset.pubkey()) | ||
| .collection(None) | ||
| .asset_signer(asset_signer) | ||
| .payer(payer_key) | ||
| .authority(Some(payer_key)) | ||
| .system_program(system_program::ID) | ||
| .program_id(system_program::ID) // use system program as harmless target | ||
| .instruction_data(execute_transfer_ix.data) | ||
| .add_remaining_accounts(&[ | ||
| AccountMeta { | ||
| pubkey: asset_signer, | ||
| is_signer: false, | ||
| is_writable: true, | ||
| }, | ||
| AccountMeta { | ||
| pubkey: payer_key, | ||
| is_signer: false, | ||
| is_writable: true, | ||
| }, | ||
| ]) | ||
| .instruction(); | ||
|
|
||
| let tx = Transaction::new_signed_with_payer( | ||
| &[execute_ix], | ||
| Some(&payer_key), | ||
| &[&context.payer], | ||
| context.last_blockhash, | ||
| ); | ||
|
|
||
| context.banks_client.process_transaction(tx).await.unwrap(); | ||
|
|
||
| // Verify that the transfer was successful. | ||
| let lamports_in_asset_after_execute = context | ||
| .banks_client | ||
| .get_balance(asset_signer) | ||
| .await | ||
| .expect("get_balance failed"); | ||
|
|
||
| // Verify that the transfer was successful. | ||
| assert_eq!(lamports_in_asset_after_execute, 0); | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -10,7 +10,9 @@ use mpl_core::{ | |||
| }; | ||||
| use setup::*; | ||||
|
|
||||
| use solana_program::{pubkey::Pubkey, system_instruction, system_program}; | ||||
| use solana_program::{ | ||||
| instruction::AccountMeta, pubkey::Pubkey, system_instruction, system_program, | ||||
| }; | ||||
| use solana_program_test::tokio; | ||||
| use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; | ||||
|
|
||||
|
|
@@ -75,8 +77,13 @@ async fn test_freeze_execute_backed_nft_flow() { | |||
| // ---------------------------------- | ||||
| // 2. Deposit backing SOL into the asset account (simulate 0.5 SOL backing) | ||||
| // ---------------------------------- | ||||
| let (asset_signer, _) = Pubkey::find_program_address( | ||||
| &[FREEZE_EXECUTE_PREFIX.as_bytes(), asset.pubkey().as_ref()], | ||||
| &mpl_core::ID, | ||||
| ); | ||||
|
|
||||
| let backing_amount: u64 = 500_000_000; // 0.5 SOL | ||||
| let transfer_ix = system_instruction::transfer(&payer_key, &asset.pubkey(), backing_amount); | ||||
| let transfer_ix = system_instruction::transfer(&payer_key, &asset_signer, backing_amount); | ||||
| let tx = Transaction::new_signed_with_payer( | ||||
| &[transfer_ix], | ||||
| Some(&payer_key), | ||||
|
|
@@ -86,21 +93,22 @@ async fn test_freeze_execute_backed_nft_flow() { | |||
| context.banks_client.process_transaction(tx).await.unwrap(); | ||||
|
|
||||
| // Capture lamports held by the asset account after deposit. | ||||
| let asset_account_after_deposit = context | ||||
| let lamports_in_asset = context | ||||
| .banks_client | ||||
| .get_account(asset.pubkey()) | ||||
| .get_balance(asset_signer) | ||||
| .await | ||||
| .expect("get_account") | ||||
| .expect("asset account not found"); | ||||
| let lamports_in_asset = asset_account_after_deposit.lamports; | ||||
| .expect("get_balance failed"); | ||||
|
|
||||
| // Verify that the deposit was successful. | ||||
| assert_eq!(lamports_in_asset, backing_amount); | ||||
|
|
||||
| // ---------------------------------- | ||||
| // 3. Attempt Execute → should fail because plugin is frozen. | ||||
| // ---------------------------------- | ||||
| let (asset_signer, _) = Pubkey::find_program_address( | ||||
| &[FREEZE_EXECUTE_PREFIX.as_bytes(), asset.pubkey().as_ref()], | ||||
| &mpl_core::ID, | ||||
| ); | ||||
| let execute_transfer_ix = | ||||
| system_instruction::transfer(&asset_signer, &payer_key, lamports_in_asset); | ||||
|
|
||||
| println!("execute_transfer_ix: {:#?}", execute_transfer_ix); | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick (assertive) Remove debug print statement. The debug print appears to be left over from development/debugging and should be removed before merging. - println!("execute_transfer_ix: {:#?}", execute_transfer_ix);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||
|
|
||||
| let execute_ix = ExecuteV1Builder::new() | ||||
| .asset(asset.pubkey()) | ||||
|
|
@@ -110,7 +118,19 @@ async fn test_freeze_execute_backed_nft_flow() { | |||
| .authority(Some(payer_key)) | ||||
| .system_program(system_program::ID) | ||||
| .program_id(system_program::ID) // use system program as harmless target | ||||
| .instruction_data(Vec::new()) | ||||
| .instruction_data(execute_transfer_ix.data) | ||||
| .add_remaining_accounts(&[ | ||||
| AccountMeta { | ||||
| pubkey: asset_signer, | ||||
| is_signer: false, | ||||
| is_writable: true, | ||||
| }, | ||||
| AccountMeta { | ||||
| pubkey: payer_key, | ||||
| is_signer: false, | ||||
| is_writable: true, | ||||
| }, | ||||
| ]) | ||||
| .instruction(); | ||||
|
|
||||
| let tx = Transaction::new_signed_with_payer( | ||||
|
|
@@ -149,12 +169,15 @@ async fn test_freeze_execute_backed_nft_flow() { | |||
| ); | ||||
| context.banks_client.process_transaction(tx).await.unwrap(); | ||||
|
|
||||
| // Asset account should be closed or at least drained. | ||||
| let _asset_account_after_burn = context | ||||
| // Verify that the transfer was successful. | ||||
| let lamports_in_asset_after_execute = context | ||||
| .banks_client | ||||
| .get_account(asset.pubkey()) | ||||
| .get_balance(asset_signer) | ||||
| .await | ||||
| .unwrap(); | ||||
| .expect("get_balance failed"); | ||||
|
|
||||
| // Verify that the asset balance has not changed. | ||||
| assert_eq!(lamports_in_asset_after_execute, lamports_in_asset); | ||||
|
|
||||
| // Verify payer balance increased (should receive refund though exact amount may be reduced by rent/taxes). | ||||
| let payer_balance_after_burn = context.banks_client.get_balance(payer_key).await.unwrap(); | ||||
|
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick (assertive)
Consider using a shared constant for PDA prefix.
The constant
EXECUTE_PREFIXuses the same value asFREEZE_EXECUTE_PREFIXin the freeze_execute.rs file. Consider extracting this to a shared module to maintain consistency and avoid duplication.You could create a shared constants module:
🤖 Prompt for AI Agents