-
Notifications
You must be signed in to change notification settings - Fork 7
Replace @loris-sandbox/litesvm-kit with litesvm v1
#178
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
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,5 @@ | ||
| --- | ||
| '@solana/kit-plugin-litesvm': minor | ||
| --- | ||
|
|
||
| Replace the temporary `@loris-sandbox/litesvm-kit` dependency with the official `litesvm` v1 package. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,3 @@ | ||
| import type { FailedTransactionMetadata, LiteSVM, TransactionMetadata } from '@loris-sandbox/litesvm-kit'; | ||
| import { | ||
| Address, | ||
| appendTransactionMessageInstruction, | ||
|
|
@@ -19,14 +18,12 @@ import { | |
| SolanaError, | ||
| } from '@solana/kit'; | ||
| import { getTransferSolInstruction } from '@solana-program/system'; | ||
| import type { FailedTransactionMetadata, LiteSVM, TransactionMetadata } from 'litesvm'; | ||
| import { describe, expect, it, vi } from 'vitest'; | ||
|
|
||
| import { litesvm, litesvmTransactionPlanExecutor, litesvmTransactionPlanner } from '../src'; | ||
|
|
||
| const MOCK_BLOCKHASH = { blockhash: '11111111111111111111111111111111', lastValidBlockHeight: 0n }; | ||
| const MOCK_INSTRUCTION = { | ||
| programAddress: '11111111111111111111111111111111' as Address, | ||
| }; | ||
| const MOCK_INSTRUCTION = { programAddress: '11111111111111111111111111111111' as Address }; | ||
|
|
||
| describe('litesvmTransactionPlanExecutor', () => { | ||
| describe('with mocks', () => { | ||
|
|
@@ -40,10 +37,10 @@ describe('litesvmTransactionPlanExecutor', () => { | |
|
|
||
| it('uses the SVM instance to send transactions', async () => { | ||
| const payer = await generateKeyPairSigner(); | ||
| const latestBlockhashLifetime = vi.fn().mockReturnValueOnce(MOCK_BLOCKHASH); | ||
| const setTransactionMessageLifetimeUsingLatestBlockhash = vi.fn().mockImplementation(<T>(m: T) => m); | ||
| // Return a success result (no `.err` property). | ||
| const sendTransaction = vi.fn().mockReturnValue({ signature: () => new Uint8Array(64) }); | ||
| const svm = { latestBlockhashLifetime, sendTransaction } as unknown as LiteSVM; | ||
| const svm = { sendTransaction, setTransactionMessageLifetimeUsingLatestBlockhash } as unknown as LiteSVM; | ||
| const client = createEmptyClient() | ||
| .use(() => ({ payer, svm })) | ||
| .use(litesvmTransactionPlanner()) | ||
|
|
@@ -55,16 +52,16 @@ describe('litesvmTransactionPlanExecutor', () => { | |
| transactionPlan, | ||
| )) as SingleTransactionPlanResult; | ||
| expect(transactionPlanResult.kind).toBe('single'); | ||
| expect(latestBlockhashLifetime).toHaveBeenCalledOnce(); | ||
| expect(setTransactionMessageLifetimeUsingLatestBlockhash).toHaveBeenCalledOnce(); | ||
| expect(sendTransaction).toHaveBeenCalledOnce(); | ||
| }); | ||
|
|
||
| it('includes transactionMetadata in the result context on success', async () => { | ||
| const payer = await generateKeyPairSigner(); | ||
| const latestBlockhashLifetime = vi.fn().mockReturnValueOnce(MOCK_BLOCKHASH); | ||
| const setTransactionMessageLifetimeUsingLatestBlockhash = vi.fn().mockImplementation(<T>(m: T) => m); | ||
| const mockMetadata = { logs: () => ['log1'], signature: () => new Uint8Array(64) }; | ||
| const sendTransaction = vi.fn().mockReturnValue(mockMetadata); | ||
| const svm = { latestBlockhashLifetime, sendTransaction } as unknown as LiteSVM; | ||
| const svm = { sendTransaction, setTransactionMessageLifetimeUsingLatestBlockhash } as unknown as LiteSVM; | ||
| const client = createEmptyClient() | ||
| .use(() => ({ payer, svm })) | ||
| .use(litesvmTransactionPlanner()) | ||
|
|
@@ -78,10 +75,10 @@ describe('litesvmTransactionPlanExecutor', () => { | |
|
|
||
| it('includes transactionMetadata in the result context on failure', async () => { | ||
| const payer = await generateKeyPairSigner(); | ||
| const latestBlockhashLifetime = vi.fn().mockReturnValueOnce(MOCK_BLOCKHASH); | ||
| const setTransactionMessageLifetimeUsingLatestBlockhash = vi.fn().mockImplementation(<T>(m: T) => m); | ||
| const mockMetadata = { err: () => 2 }; | ||
| const sendTransaction = vi.fn().mockReturnValue(mockMetadata); | ||
| const svm = { latestBlockhashLifetime, sendTransaction } as unknown as LiteSVM; | ||
| const svm = { sendTransaction, setTransactionMessageLifetimeUsingLatestBlockhash } as unknown as LiteSVM; | ||
| const client = createEmptyClient() | ||
| .use(() => ({ payer, svm })) | ||
| .use(litesvmTransactionPlanExecutor()); | ||
|
|
@@ -98,10 +95,10 @@ describe('litesvmTransactionPlanExecutor', () => { | |
|
|
||
| it('throws a SolanaError when the transaction fails', async () => { | ||
| const payer = await generateKeyPairSigner(); | ||
| const latestBlockhashLifetime = vi.fn().mockReturnValueOnce(MOCK_BLOCKHASH); | ||
| const setTransactionMessageLifetimeUsingLatestBlockhash = vi.fn().mockImplementation(<T>(m: T) => m); | ||
| // Return a failed result with a fieldless error (AccountNotFound = 2). | ||
| const sendTransaction = vi.fn().mockReturnValue({ err: () => 2 }); | ||
| const svm = { latestBlockhashLifetime, sendTransaction } as unknown as LiteSVM; | ||
| const svm = { sendTransaction, setTransactionMessageLifetimeUsingLatestBlockhash } as unknown as LiteSVM; | ||
| const client = createEmptyClient() | ||
| .use(() => ({ payer, svm })) | ||
| .use(litesvmTransactionPlanExecutor()); | ||
|
|
@@ -124,15 +121,15 @@ describe('litesvmTransactionPlanExecutor', () => { | |
|
|
||
| it('throws a SolanaError for instruction errors', async () => { | ||
| const payer = await generateKeyPairSigner(); | ||
| const latestBlockhashLifetime = vi.fn().mockReturnValueOnce(MOCK_BLOCKHASH); | ||
| const setTransactionMessageLifetimeUsingLatestBlockhash = vi.fn().mockImplementation(<T>(m: T) => m); | ||
| // Return a failed result with an instruction error. | ||
| const instructionError = { | ||
| constructor: { name: 'TransactionErrorInstructionError' }, | ||
| err: () => 2, // InstructionErrorFieldless.InvalidInstructionData | ||
| index: 0, | ||
| }; | ||
| const sendTransaction = vi.fn().mockReturnValue({ err: () => instructionError }); | ||
| const svm = { latestBlockhashLifetime, sendTransaction } as unknown as LiteSVM; | ||
| const svm = { sendTransaction, setTransactionMessageLifetimeUsingLatestBlockhash } as unknown as LiteSVM; | ||
| const client = createEmptyClient() | ||
| .use(() => ({ payer, svm })) | ||
| .use(litesvmTransactionPlanExecutor()); | ||
|
|
@@ -194,10 +191,10 @@ describe('litesvmTransactionPlanExecutor', () => { | |
| .use(client => extendClient(client, { payer })) | ||
| .use(litesvmTransactionPlanner()) | ||
| .use(litesvmTransactionPlanExecutor()); | ||
| client.svm.airdrop(payer.address, lamports(1_000_000_000n)); | ||
| client.svm.airdrop(payer.address, lamports(1_000_000_000n)); // 1 SOL | ||
|
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. The bump from 1,000 to 100,000,000 lamports — is this needed because the v1 runtime now enforces minimum rent-exempt balances or fee requirements that the old version didn't? Might be worth a brief comment explaining why this specific amount was chosen.
Member
Author
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. @trevor-cortex That's exactly right. The test transferred 1,000 lamports to a fresh destination address but the minimum balance for a 0-data account is 890,880 lamports. The official 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. Makes sense, thanks for the context! Good that the official v1 enforces rent-exemption properly — better to catch that in tests than have it silently pass. |
||
|
|
||
| const instruction = getTransferSolInstruction({ | ||
| amount: lamports(1_000n), | ||
| amount: lamports(100_000_000n), // 0.1 SOL | ||
| destination: destination.address, | ||
| source: payer, | ||
| }); | ||
|
|
||
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.
Nice — this is a cleaner API. The old two-step pattern (
latestBlockhashLifetime()→setTransactionMessageLifetimeUsingBlockhash()) was easy to misuse if the blockhash went stale between the two calls. Having the SVM instance handle it atomically is a good improvement.