diff --git a/.gitignore b/.gitignore index 7d7e12e..1806442 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,6 @@ */node_modules js/lib -cli/target -cli/target/.rustc_info.json /node_modules js/dist diff --git a/README.md b/README.md index 5567d85..3fc35f5 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,6 @@ The [Bonfida Token Vesting UI](https://vesting.bonfida.org) can be used to unloc

Structure


-- `cli` : CLI tool to interact with on-chain token vesting contract - `js` : JavaScript binding to interact with on-chain token vesting contract - `program` : The BPF compatible token vesting on-chain program/smart contract diff --git a/js/README.md b/js/README.md index a170a62..e9e6d16 100644 --- a/js/README.md +++ b/js/README.md @@ -22,7 +22,6 @@ The code allows you to - Create vesting instructions for any SPL token: `createCreateInstruction` - Create unlock instructions: `createUnlockInstruction` -- Change the destination of the vested tokens: `createChangeDestinationInstruction` (To import Solana accounts created with [Sollet](https://sollet.io) you can use `getAccountFromSeed`) @@ -37,7 +36,4 @@ Fetching contract r2p2mLJvyrTzetxxsttQ54CS1m18zMgYqKSRzxP9WpE ✅ Successfully created unlocking instructions 🚚 Transaction signature: 2Vg3W1w8WBdRAWBEwFTn2BtMkKPD3Xor7SRvzC193UnsUnhmneUChPHe7vLF9Lfw9BKxWH5JbbJmnda4XztHMVHz -Fetching contract r2p2mLJvyrTzetxxsttQ54CS1m18zMgYqKSRzxP9WpE -✅ Successfully changed destination -🚚 Transaction signature: 4tgPgCdM5ubaSKNLKD1WrfAJPZgRajxRSnmcPkHcN1TCeCRmq3cUCYVdCzsYwr63JRf4D2K1UZnt8rwu2pkGxeYe ``` diff --git a/js/src/instructions.ts b/js/src/instructions.ts index f4f9e2f..cc96473 100644 --- a/js/src/instructions.ts +++ b/js/src/instructions.ts @@ -201,45 +201,3 @@ export function createInitializeUnlockInstruction( data, }); } - -export function createChangeDestinationInstruction( - vestingProgramId: PublicKey, - vestingAccountKey: PublicKey, - currentDestinationTokenAccountOwner: PublicKey, - currentDestinationTokenAccount: PublicKey, - targetDestinationTokenAccount: PublicKey, - seeds: Array, -): TransactionInstruction { - const data = Buffer.concat([ - Buffer.from(Int8Array.from([4]).buffer), - Buffer.concat(seeds), - ]); - - const keys = [ - { - pubkey: vestingAccountKey, - isSigner: false, - isWritable: true, - }, - { - pubkey: currentDestinationTokenAccount, - isSigner: false, - isWritable: false, - }, - { - pubkey: currentDestinationTokenAccountOwner, - isSigner: true, - isWritable: false, - }, - { - pubkey: targetDestinationTokenAccount, - isSigner: false, - isWritable: false, - }, - ]; - return new TransactionInstruction({ - keys, - programId: vestingProgramId, - data, - }); -} diff --git a/js/src/main.ts b/js/src/main.ts index 5efae1b..1d60ea9 100644 --- a/js/src/main.ts +++ b/js/src/main.ts @@ -11,7 +11,6 @@ import { getAssociatedTokenAddress, } from '@solana/spl-token'; import { - createChangeDestinationInstruction, createCreateInstruction, createInitInstruction, createUnlockInstruction, @@ -229,55 +228,4 @@ export async function getContractInfo( throw new Error('Vesting contract account is not initialized'); } return info!; -} - -/** - * This function can be used to transfer a vesting account to a new wallet. It requires the current owner to sign. - * @param connection The Solana RPC connection object - * @param programId The token vesting program ID - * @param currentDestinationTokenAccountPublicKey The current token account to which the vested tokens are transfered to as they unlock - * @param newDestinationTokenAccountOwner The new owner of the vesting account - * @param newDestinationTokenAccount The new token account to which the vested tokens will be transfered to as they unlock - * @param vestingSeed Seed words used to derive the vesting account - * @returns An array of `TransactionInstruction` - */ -export async function changeDestination( - connection: Connection, - programId: PublicKey, - currentDestinationTokenAccountPublicKey: PublicKey, - newDestinationTokenAccountOwner: PublicKey | undefined, - newDestinationTokenAccount: PublicKey | undefined, - vestingSeed: Array, -): Promise> { - let seedWord = vestingSeed[0]; - seedWord = seedWord.slice(0, 31); - const [vestingAccountKey, bump] = await PublicKey.findProgramAddress( - [seedWord], - programId, - ); - seedWord = Buffer.from(seedWord.toString('hex') + bump.toString(16), 'hex'); - - const contractInfo = await getContractInfo(connection, vestingAccountKey); - if (!newDestinationTokenAccount) { - assert( - !!newDestinationTokenAccountOwner, - 'At least one of newDestinationTokenAccount and newDestinationTokenAccountOwner must be provided!', - ); - newDestinationTokenAccount = await getAssociatedTokenAddress( - contractInfo.mintAddress, - newDestinationTokenAccountOwner!, - true, - ); - } - - return [ - createChangeDestinationInstruction( - programId, - vestingAccountKey, - currentDestinationTokenAccountPublicKey, - contractInfo.destinationAddress, - newDestinationTokenAccount, - [seedWord], - ), - ]; -} +} \ No newline at end of file diff --git a/program/fuzz/src/vesting_fuzz.rs b/program/fuzz/src/vesting_fuzz.rs index 28dcde8..181c75b 100644 --- a/program/fuzz/src/vesting_fuzz.rs +++ b/program/fuzz/src/vesting_fuzz.rs @@ -11,7 +11,7 @@ use solana_sdk::{signature::Keypair, signature::Signer, system_instruction, tran use arbitrary::Arbitrary; use std::collections::HashMap; use token_vesting::{instruction::{Schedule, VestingInstruction}, processor::Processor}; -use token_vesting::instruction::{init, unlock, change_destination, create}; +use token_vesting::instruction::{init, unlock, create}; use solana_sdk::{account::Account, instruction::InstructionError, transaction::TransactionError}; struct TokenVestingEnv { system_program_id: Pubkey, @@ -327,59 +327,6 @@ fn run_fuzz_instruction( clone_keypair(&token_vesting_testenv.mint_authority), clone_keypair(source_token_account_owner_key), ]); - }, - - FuzzInstruction { - instruction: VestingInstruction::ChangeDestination{ .. }, - .. - } => { - let mut instructions_acc = vec![init( - &token_vesting_testenv.system_program_id, - &token_vesting_testenv.rent_program_id, - &token_vesting_testenv.vesting_program_id, - &correct_payer.pubkey(), - &correct_vesting_account_key, - correct_seeds, - fuzz_instruction.number_of_schedules as u32 - ).unwrap()]; - let mut create_instructions = create_fuzzinstruction( - token_vesting_testenv, - fuzz_instruction, - correct_payer, - &correct_source_token_account_key, - source_token_account_owner_key, - destination_token_key, - &destination_token_owner_key.pubkey(), - &correct_vesting_account_key, - &correct_vesting_token_key, - correct_seeds, - mint_key, - fuzz_instruction.source_token_amount - ); - instructions_acc.append(&mut create_instructions); - - let new_destination_instruction = create_associated_token_account( - &correct_payer.pubkey(), - &Pubkey::new_unique(), // Arbitrary - &mint_key.pubkey() - ); - instructions_acc.push(new_destination_instruction); - - let change_instruction = change_destination( - &token_vesting_testenv.vesting_program_id, - &correct_vesting_account_key, - &destination_token_owner_key.pubkey(), - &destination_token_key, - new_destination_token_key, - correct_seeds - ).unwrap(); - instructions_acc.push(change_instruction); - return (instructions_acc, vec![ - clone_keypair(mint_key), - clone_keypair(&token_vesting_testenv.mint_authority), - clone_keypair(source_token_account_owner_key), - clone_keypair(destination_token_owner_key), - ]); } }; @@ -441,24 +388,6 @@ fn run_fuzz_instruction( vec![unlock_instruction], vec![] ); - }, - - FuzzInstruction { - instruction: VestingInstruction::ChangeDestination{ .. }, - .. - } => { - let change_instruction = change_destination( - &token_vesting_testenv.vesting_program_id, - vesting_account_key, - &destination_token_owner_key.pubkey(), - &destination_token_key, - new_destination_token_key, - fuzz_instruction.seeds, - ).unwrap(); - return ( - vec![change_instruction], - vec![clone_keypair(destination_token_owner_key)] - ); } }; } diff --git a/program/src/instruction.rs b/program/src/instruction.rs index f40dd70..f8ccd9a 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -17,7 +17,7 @@ use arbitrary::Arbitrary; impl Arbitrary for VestingInstruction { fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { let seeds: [u8; 32] = u.arbitrary()?; - let choice = u.choose(&[0, 1, 2, 3, 4])?; + let choice = u.choose(&[0, 1, 2, 3])?; match choice { 0 => { return Ok(Self::Init { @@ -29,17 +29,14 @@ impl Arbitrary for VestingInstruction { let key_bytes: [u8; 32] = u.arbitrary()?; let mint_address: Pubkey = Pubkey::new_from_array(key_bytes); let key_bytes: [u8; 32] = u.arbitrary()?; - let destination_token_address: Pubkey = Pubkey::new_from_array(key_bytes); return Ok(Self::Create { seeds, mint_address, - destination_token_address, schedule: schedule, }); } 2 => return Ok(Self::Unlock { seeds }), - 3 => return Ok(Self::InitializeUnlock { seeds }), - _ => return Ok(Self::ChangeDestination { seeds }), + _ => return Ok(Self::InitializeUnlock { seeds }), } } } @@ -84,7 +81,6 @@ pub enum VestingInstruction { Create { seeds: [u8; 32], mint_address: Pubkey, - destination_token_address: Pubkey, schedule: Schedule, }, /// Unlocks a simple vesting contract (SVC) - can only be invoked by the program itself @@ -108,18 +104,6 @@ pub enum VestingInstruction { /// 2. `[writable]` The vesting spl-token account /// 3. `[writable]` The destination spl-token account InitializeUnlock { seeds: [u8; 32] }, - - /// Change the destination account of a given simple vesting contract (SVC) - /// - can only be invoked by the present destination address of the contract. - /// - /// Accounts expected by this instruction: - /// - /// * Single owner - /// 0. `[]` The vesting account - /// 1. `[]` The current destination token account - /// 2. `[signer]` The destination spl-token account owner - /// 3. `[]` The new destination spl-token account - ChangeDestination { seeds: [u8; 32] }, } impl VestingInstruction { @@ -146,12 +130,7 @@ impl VestingInstruction { .and_then(|slice| slice.try_into().ok()) .map(Pubkey::new_from_array) .ok_or(InvalidInstruction)?; - let destination_token_address = rest - .get(64..96) - .and_then(|slice| slice.try_into().ok()) - .map(Pubkey::new_from_array) - .ok_or(InvalidInstruction)?; - let offset = 96; + let offset = 64; let release_time = rest .get(offset..offset + 8) .and_then(|slice| slice.try_into().ok()) @@ -169,19 +148,17 @@ impl VestingInstruction { Self::Create { seeds, mint_address, - destination_token_address, schedule, } } - 2 | 3 | 4 => { + 2 | 3 => { let seeds: [u8; 32] = rest .get(..32) .and_then(|slice| slice.try_into().ok()) .unwrap(); match tag { 2 => Self::Unlock { seeds }, - 3 => Self::InitializeUnlock { seeds }, - _ => Self::ChangeDestination { seeds }, + _ => Self::InitializeUnlock { seeds }, } } _ => { @@ -203,13 +180,11 @@ impl VestingInstruction { Self::Create { seeds, mint_address, - destination_token_address, schedule, } => { buf.push(1); buf.extend_from_slice(seeds); buf.extend_from_slice(&mint_address.to_bytes()); - buf.extend_from_slice(&destination_token_address.to_bytes()); buf.extend_from_slice(&schedule.release_time.to_le_bytes()); buf.extend_from_slice(&schedule.amount.to_le_bytes()); } @@ -221,10 +196,6 @@ impl VestingInstruction { buf.push(3); buf.extend_from_slice(&seeds); } - &Self::ChangeDestination { seeds } => { - buf.push(4); - buf.extend_from_slice(&seeds); - } }; buf } @@ -264,7 +235,6 @@ pub fn create( vesting_token_account_key: &Pubkey, source_token_account_owner_key: &Pubkey, source_token_account_key: &Pubkey, - destination_token_account_key: &Pubkey, mint_address: &Pubkey, schedule: Schedule, seeds: [u8; 32], @@ -272,7 +242,6 @@ pub fn create( let data = VestingInstruction::Create { mint_address: *mint_address, seeds, - destination_token_address: *destination_token_account_key, schedule, } .pack(); @@ -340,28 +309,6 @@ pub fn initialize_unlock( }) } -pub fn change_destination( - vesting_program_id: &Pubkey, - vesting_account_key: &Pubkey, - current_destination_token_account_owner: &Pubkey, - current_destination_token_account: &Pubkey, - target_destination_token_account: &Pubkey, - seeds: [u8; 32], -) -> Result { - let data = VestingInstruction::ChangeDestination { seeds }.pack(); - let accounts = vec![ - AccountMeta::new(*vesting_account_key, false), - AccountMeta::new_readonly(*current_destination_token_account, false), - AccountMeta::new_readonly(*current_destination_token_account_owner, true), - AccountMeta::new_readonly(*target_destination_token_account, false), - ]; - Ok(Instruction { - program_id: *vesting_program_id, - accounts, - data, - }) -} - #[cfg(test)] mod test { use super::*; @@ -369,7 +316,6 @@ mod test { #[test] fn test_instruction_packing() { let mint_address = Pubkey::new_unique(); - let destination_token_address = Pubkey::new_unique(); let original_create = VestingInstruction::Create { seeds: [50u8; 32], @@ -378,7 +324,6 @@ mod test { release_time: 250, }, mint_address: mint_address.clone(), - destination_token_address, }; let packed_create = original_create.pack(); let unpacked_create = VestingInstruction::unpack(&packed_create).unwrap(); @@ -397,11 +342,5 @@ mod test { original_init, VestingInstruction::unpack(&original_init.pack()).unwrap() ); - - let original_change = VestingInstruction::ChangeDestination { seeds: [50u8; 32] }; - assert_eq!( - original_change, - VestingInstruction::unpack(&original_change.pack()).unwrap() - ); } } diff --git a/program/src/processor.rs b/program/src/processor.rs index 311de6a..e16b07a 100644 --- a/program/src/processor.rs +++ b/program/src/processor.rs @@ -73,7 +73,6 @@ impl Processor { accounts: &[AccountInfo], seeds: [u8; 32], mint_address: &Pubkey, - destination_token_address: &Pubkey, schedule: Schedule, ) -> ProgramResult { let accounts_iter = &mut accounts.iter(); @@ -127,25 +126,24 @@ impl Processor { } let state_header = VestingScheduleHeader { - destination_address: *destination_token_address, + destination_address: *source_token_account.key, mint_address: *mint_address, is_initialized: true, }; let mut data = vesting_account.data.borrow_mut(); if data.len() != VestingScheduleHeader::LEN + VestingSchedule::LEN { - return Err(ProgramError::InvalidAccountData); + return Err(ProgramError::InvalidAccountData) } state_header.pack_into_slice(&mut data); - let offset = VestingScheduleHeader::LEN; let mut total_amount: u64 = 0; let state_schedule = VestingSchedule { release_time: schedule.release_time, amount: schedule.amount, }; - state_schedule.pack_into_slice(&mut data[offset..]); + state_schedule.pack_into_slice(&mut data[VestingScheduleHeader::LEN..]); let delta = total_amount.checked_add(schedule.amount); match delta { Some(n) => total_amount = n, @@ -336,56 +334,6 @@ impl Processor { Ok(()) } - pub fn process_change_destination( - program_id: &Pubkey, - accounts: &[AccountInfo], - seeds: [u8; 32], - ) -> ProgramResult { - let accounts_iter = &mut accounts.iter(); - - let vesting_account = next_account_info(accounts_iter)?; - let destination_token_account = next_account_info(accounts_iter)?; - let destination_token_account_owner = next_account_info(accounts_iter)?; - let new_destination_token_account = next_account_info(accounts_iter)?; - - if vesting_account.data.borrow().len() < VestingScheduleHeader::LEN { - return Err(ProgramError::InvalidAccountData); - } - let vesting_account_key = Pubkey::create_program_address(&[&seeds], program_id)?; - let state = VestingScheduleHeader::unpack( - &vesting_account.data.borrow()[..VestingScheduleHeader::LEN], - )?; - - if vesting_account_key != *vesting_account.key { - msg!("Invalid vesting account key"); - return Err(ProgramError::InvalidArgument); - } - - if state.destination_address != *destination_token_account.key { - msg!("Contract destination account does not matched provided account"); - return Err(ProgramError::InvalidArgument); - } - - if !destination_token_account_owner.is_signer { - msg!("Destination token account owner should be a signer."); - return Err(ProgramError::InvalidArgument); - } - - let destination_token_account = Account::unpack(&destination_token_account.data.borrow())?; - - if destination_token_account.owner != *destination_token_account_owner.key { - msg!("The current destination token account isn't owned by the provided owner"); - return Err(ProgramError::InvalidArgument); - } - - let mut new_state = state; - new_state.destination_address = *new_destination_token_account.key; - new_state - .pack_into_slice(&mut vesting_account.data.borrow_mut()[..VestingScheduleHeader::LEN]); - - Ok(()) - } - pub fn process_instruction( program_id: &Pubkey, accounts: &[AccountInfo], @@ -395,7 +343,9 @@ impl Processor { let instruction = VestingInstruction::unpack(instruction_data)?; msg!("Instruction unpacked"); match instruction { - VestingInstruction::Init { seeds } => { + VestingInstruction::Init { + seeds, + } => { msg!("Instruction: Init"); Self::process_init(program_id, accounts, seeds) } @@ -407,14 +357,9 @@ impl Processor { msg!("Instruction: InitializeUnlock"); Self::process_initialize_unlock(program_id, accounts, seeds) } - VestingInstruction::ChangeDestination { seeds } => { - msg!("Instruction: Change Destination"); - Self::process_change_destination(program_id, accounts, seeds) - } VestingInstruction::Create { seeds, mint_address, - destination_token_address, schedule, } => { msg!("Instruction: Create Schedule"); @@ -423,7 +368,6 @@ impl Processor { accounts, seeds, &mint_address, - &destination_token_address, schedule, ) } diff --git a/program/src/state.rs b/program/src/state.rs index e5c3e08..69ef1d0 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -91,16 +91,14 @@ impl IsInitialized for VestingScheduleHeader { } pub fn unpack_schedule(input: &[u8]) -> Result { - let offset = 0; let output: VestingSchedule = VestingSchedule::unpack_from_slice( - &input[offset..offset + VestingSchedule::LEN], + &input[..VestingSchedule::LEN], )?; Ok(output) } pub fn pack_schedule_into_slice(schedule: VestingSchedule, target: &mut [u8]) { - let offset = 0; - schedule.pack_into_slice(&mut target[offset..]); + schedule.pack_into_slice(target); } #[cfg(test)] diff --git a/program/tests/functional.rs b/program/tests/functional.rs index 74d8307..33a9dff 100644 --- a/program/tests/functional.rs +++ b/program/tests/functional.rs @@ -1,21 +1,13 @@ #![cfg(feature = "test-bpf")] use std::str::FromStr; -use solana_program::{ - hash::Hash, pubkey::Pubkey, rent::Rent, system_program, sysvar, -}; -use solana_program_test::{processor, ProgramTest, ProgramTestContext}; -use solana_sdk::{ - account::Account, signature::Keypair, signature::Signer, system_instruction, - transaction::Transaction, -}; +use solana_program::{hash::Hash, pubkey::Pubkey, rent::Rent, system_program, sysvar}; use solana_test_framework::ProgramTestContextExtension; -use spl_token::{ - self, - instruction::{initialize_account, initialize_mint, mint_to}, -}; -use token_vesting::instruction::{create, init, initialize_unlock, unlock}; +use solana_program_test::{processor, ProgramTest, ProgramTestContext}; +use solana_sdk::{account::Account, signature::Keypair, signature::Signer, system_instruction, transaction::Transaction}; use token_vesting::{entrypoint::process_instruction, instruction::Schedule}; +use token_vesting::instruction::{init, unlock, create, initialize_unlock}; +use spl_token::{self, instruction::{initialize_mint, initialize_account, mint_to}}; #[tokio::test] async fn test_token_vesting() { @@ -27,12 +19,6 @@ async fn test_token_vesting() { let source_account = Keypair::new(); let source_token_account = Keypair::new(); - let destination_account = Keypair::new(); - let destination_token_account = Keypair::new(); - - let new_destination_account = Keypair::new(); - let new_destination_token_account = Keypair::new(); - let mut seeds = [42u8; 32]; let (vesting_account_key, bump) = Pubkey::find_program_address(&[&seeds[..31]], &program_id); seeds[31] = bump; @@ -72,15 +58,13 @@ async fn test_token_vesting() { .unwrap(); // Initialize the token accounts - banks_client - .process_transaction(mint_init_transaction( + banks_client.process_transaction(mint_init_transaction( &payer, &mint, &mint_authority, recent_blockhash, )) - .await - .unwrap(); + .await.unwrap(); banks_client .process_transaction(create_token_account( @@ -102,26 +86,6 @@ async fn test_token_vesting() { )) .await .unwrap(); - banks_client - .process_transaction(create_token_account( - &payer, - &mint, - recent_blockhash, - &destination_token_account, - &destination_account.pubkey(), - )) - .await - .unwrap(); - banks_client - .process_transaction(create_token_account( - &payer, - &mint, - recent_blockhash, - &new_destination_token_account, - &new_destination_account.pubkey(), - )) - .await - .unwrap(); // Create and process the vesting transactions let setup_instructions = [mint_to( @@ -147,7 +111,6 @@ async fn test_token_vesting() { &vesting_token_account.pubkey(), &source_account.pubkey(), &source_token_account.pubkey(), - &destination_token_account.pubkey(), &mint.pubkey(), schedule, seeds.clone(), @@ -159,7 +122,7 @@ async fn test_token_vesting() { &sysvar::clock::id(), &vesting_account_key, &vesting_token_account.pubkey(), - &destination_token_account.pubkey(), + &source_token_account.pubkey(), seeds.clone(), ) .unwrap(), @@ -196,12 +159,6 @@ async fn test_token_unlocking() { let source_account = Keypair::new(); let source_token_account = Keypair::new(); - let destination_account = Keypair::new(); - let destination_token_account = Keypair::new(); - - let new_destination_account = Keypair::new(); - let new_destination_token_account = Keypair::new(); - let mut seeds = [42u8; 32]; let (vesting_account_key, bump) = Pubkey::find_program_address(&[&seeds[..31]], &program_id); seeds[31] = bump; @@ -277,26 +234,6 @@ async fn test_token_unlocking() { )) .await .unwrap(); - banks_client - .process_transaction(create_token_account( - &payer, - &mint, - recent_blockhash, - &destination_token_account, - &destination_account.pubkey(), - )) - .await - .unwrap(); - banks_client - .process_transaction(create_token_account( - &payer, - &mint, - recent_blockhash, - &new_destination_token_account, - &new_destination_account.pubkey(), - )) - .await - .unwrap(); // Create and process the vesting transactions let setup_instructions = [mint_to( @@ -322,7 +259,6 @@ async fn test_token_unlocking() { &vesting_token_account.pubkey(), &source_account.pubkey(), &source_token_account.pubkey(), - &destination_token_account.pubkey(), &mint.pubkey(), schedule, seeds.clone(), @@ -334,7 +270,7 @@ async fn test_token_unlocking() { &sysvar::clock::id(), &vesting_account_key, &vesting_token_account.pubkey(), - &destination_token_account.pubkey(), + &source_token_account.pubkey(), seeds.clone(), ) .unwrap(), @@ -345,7 +281,7 @@ async fn test_token_unlocking() { &sysvar::clock::id(), &vesting_account_key, &vesting_token_account.pubkey(), - &destination_token_account.pubkey(), + &source_token_account.pubkey(), seeds.clone(), ) .unwrap() @@ -387,7 +323,7 @@ async fn test_token_unlocking() { // &sysvar::clock::id(), // &vesting_account_key, // &vesting_token_account.pubkey(), - // &destination_token_account.pubkey(), + // &source_token_account.pubkey(), // seeds.clone(), // ) // .unwrap()];