diff --git a/tokens/token-swap/native/program/src/instructions/mod.rs b/tokens/token-swap/native/program/src/instructions/mod.rs new file mode 100644 index 000000000..4549cafa1 --- /dev/null +++ b/tokens/token-swap/native/program/src/instructions/mod.rs @@ -0,0 +1,11 @@ +mod create_amm; +mod create_pool; +mod deposit_liquidity; +mod swap_exact_tokens_for_tokens; +mod withdraw_liquidity; + +pub use create_amm::*; +pub use create_pool::*; +pub use deposit_liquidity::*; +pub use swap_exact_tokens_for_tokens::*; +pub use withdraw_liquidity::*; \ No newline at end of file diff --git a/tokens/token-swap/native/program/src/lib.rs b/tokens/token-swap/native/program/src/lib.rs new file mode 100644 index 000000000..26b3bf6da --- /dev/null +++ b/tokens/token-swap/native/program/src/lib.rs @@ -0,0 +1,15 @@ +use solana_program::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); + +fn process_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> ProgramResult { + msg!("Token Swap Program Entry"); + // Aqui você adiciona a lógica para processar as instruções + Ok(()) +} \ No newline at end of file diff --git a/tokens/token-swap/native/tests/test.ts b/tokens/token-swap/native/tests/test.ts new file mode 100644 index 000000000..15bddeabd --- /dev/null +++ b/tokens/token-swap/native/tests/test.ts @@ -0,0 +1,144 @@ +import { + type Address, + appendTransactionMessageInstruction, + createTransactionMessage, + generateKeyPairSigner, + getAddressEncoder, + getProgramDerivedAddress, + type Instruction, + type KeyPairSigner, + lamports, + pipe, + setTransactionMessageFeePayerSigner, + signTransactionMessageWithSigners, + unwrapOption, +} from '@solana/kit'; +import { findAssociatedTokenPda, getMintDecoder, getTokenDecoder, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token'; +import { assert } from 'chai'; +import { FailedTransactionMetadata, LiteSVM } from 'litesvm'; +import { + createCreateAmmInstruction, + createCreatePoolInstruction, + createDepositLiquidityInstruction, + createSwapExactTokensForTokensInstruction, + createWithdrawLiquidityInstruction, +} from '../ts'; + +const addressEncoder = getAddressEncoder(); + +describe('Token Swap', () => { + const svm = new LiteSVM(); + let programId: Address; + let payer: KeyPairSigner; + let tokenMintKeypair1: KeyPairSigner; + let tokenMintKeypair2: KeyPairSigner; + let ammKeypair: KeyPairSigner; + let poolKeypair: KeyPairSigner; + + before(async () => { + programId = (await generateKeyPairSigner()).address; + svm.addProgramFromFile(programId, 'tests/fixtures/token_swap_program.so'); + + payer = await generateKeyPairSigner(); + svm.airdrop(payer.address, lamports(10_000_000_000n)); + + tokenMintKeypair1 = await generateKeyPairSigner(); + tokenMintKeypair2 = await generateKeyPairSigner(); + ammKeypair = await generateKeyPairSigner(); + poolKeypair = await generateKeyPairSigner(); + }); + + async function sendTransaction(ix: Instruction) { + const transactionMessage = pipe( + createTransactionMessage({ version: 0 }), + m => setTransactionMessageFeePayerSigner(payer, m), + m => svm.setTransactionMessageLifetimeUsingLatestBlockhash(m), + m => appendTransactionMessageInstruction(ix, m), + ); + const signedTx = await signTransactionMessageWithSigners(transactionMessage); + const result = svm.sendTransaction(signedTx); + assert(!(result instanceof FailedTransactionMetadata), `transaction failed: ${result.toString()}`); + } + + it('Create AMM!', async () => { + const ix = createCreateAmmInstruction( + ammKeypair, + payer.address, + programId, + ); + + await sendTransaction(ix); + + const ammInfo = svm.getAccount(ammKeypair.address); + assert(ammInfo.exists, 'amm account not created'); + }); + + it('Create Pool!', async () => { + const ix = createCreatePoolInstruction( + poolKeypair, + payer.address, + ammKeypair.address, + tokenMintKeypair1.address, + tokenMintKeypair2.address, + payer, + programId, + ); + + await sendTransaction(ix); + + const poolInfo = svm.getAccount(poolKeypair.address); + assert(poolInfo.exists, 'pool account not created'); + }); + + it('Deposit Liquidity!', async () => { + const ix = createDepositLiquidityInstruction( + poolKeypair.address, + payer.address, + tokenMintKeypair1.address, + tokenMintKeypair2.address, + payer, + programId, + 100n, + 100n, + ); + + await sendTransaction(ix); + + const poolInfo = svm.getAccount(poolKeypair.address); + assert(poolInfo.exists, 'pool account not updated'); + }); + + it('Swap Exact Tokens For Tokens!', async () => { + const ix = createSwapExactTokensForTokensInstruction( + poolKeypair.address, + payer.address, + tokenMintKeypair1.address, + tokenMintKeypair2.address, + payer, + programId, + 50n, + ); + + await sendTransaction(ix); + + const poolInfo = svm.getAccount(poolKeypair.address); + assert(poolInfo.exists, 'pool account not updated'); + }); + + it('Withdraw Liquidity!', async () => { + const ix = createWithdrawLiquidityInstruction( + poolKeypair.address, + payer.address, + tokenMintKeypair1.address, + tokenMintKeypair2.address, + payer, + programId, + 50n, + ); + + await sendTransaction(ix); + + const poolInfo = svm.getAccount(poolKeypair.address); + assert(poolInfo.exists, 'pool account not updated'); + }); +}); \ No newline at end of file