---
title: Time-Based Testing
description: Test time-dependent logic with LiteSVM clock manipulation
---

Demonstrates using `warpToSlot` to test time-dependent program logic.

## Basic Clock Manipulation

```typescript
import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";

const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());

// Enable sysvars for clock access
client.svm.withSysvars();

// Check initial clock
const initialClock = client.svm.getClock();
console.log("Initial state:");
console.log("  Slot:", initialClock.slot);
console.log("  Epoch:", initialClock.epoch);
console.log("  Unix timestamp:", initialClock.unixTimestamp);

// Warp to slot 1000
client.svm.warpToSlot(1000n);

const afterWarp = client.svm.getClock();
console.log("\nAfter warpToSlot(1000):");
console.log("  Slot:", afterWarp.slot);
console.log("  Epoch:", afterWarp.epoch);

// Warp further
client.svm.warpToSlot(100000n);

const afterWarp2 = client.svm.getClock();
console.log("\nAfter warpToSlot(100000):");
console.log("  Slot:", afterWarp2.slot);
console.log("  Epoch:", afterWarp2.epoch);
```

## Testing Time-Locked Logic

Example pattern for testing time-locked functionality:

```typescript
import {
  createClient,
  address,
  generateKeyPairSigner,
  lamports
} from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";

const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());

client.svm.withSigverify(false).withBlockhashCheck(false).withSysvars();

// Fund payer
client.svm.airdrop(client.payer.address, lamports(10_000_000_000n));

// Set up a time-locked vault account
// Structure: [u8 discriminator, u64 unlock_slot, u64 amount]
const unlockSlot = 10000n;
const lockedAmount = 5_000_000_000n;

const vaultData = new Uint8Array(1 + 8 + 8);
const view = new DataView(vaultData.buffer);
vaultData[0] = 0x01; // discriminator
view.setBigUint64(1, unlockSlot, true); // unlock_slot
view.setBigUint64(9, lockedAmount, true); // amount

const programId = address("TimeLockedVault11111111111111111111111"); // replace or generateKeyPairSigner()
const vaultAddress = address("Vault111111111111111111111111111"); // replace or generateKeyPairSigner()
const minBalance = client.svm.minimumBalanceForRentExemption(
  BigInt(vaultData.length)
);

client.svm.setAccount({
  address: vaultAddress,
  data: vaultData,
  executable: false,
  lamports: lamports(minBalance + lockedAmount),
  programAddress: programId,
  space: BigInt(vaultData.length)
});

console.log("Vault created with unlock slot:", unlockSlot);
console.log("Locked amount:", Number(lockedAmount) / 1e9, "SOL");

// Test 1: Try to withdraw before unlock (should fail)
console.log("\n--- Test 1: Before unlock ---");
const currentClock = client.svm.getClock();
console.log("Current slot:", currentClock.slot);

// In a real test, you would:
// 1. Build a withdraw instruction
// 2. Send it and expect it to fail
console.log("Withdrawal attempt: EXPECTED TO FAIL (too early)");

// Test 2: Warp to after unlock slot
console.log("\n--- Test 2: After unlock ---");
client.svm.warpToSlot(unlockSlot + 100n);

const newClock = client.svm.getClock();
console.log("Current slot:", newClock.slot);

// In a real test:
// 1. Build a withdraw instruction
// 2. Send it and expect it to succeed
console.log("Withdrawal attempt: EXPECTED TO SUCCEED (after unlock)");

// Verify vault state
const updatedVault = client.svm.getAccount(vaultAddress);
if (updatedVault.exists) {
  console.log("\nVault balance:", updatedVault.lamports);
}
```

## Reading the Epoch Schedule

You can read the epoch schedule to understand the slot/epoch relationship on the
cluster:

```typescript
import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";

const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
client.svm.withSysvars();

const epochSchedule = client.svm.getEpochSchedule();
console.log("Slots per epoch:", epochSchedule.slotsPerEpoch);
console.log("First normal epoch:", epochSchedule.firstNormalEpoch);
console.log("First normal slot:", epochSchedule.firstNormalSlot);
```

<Callout type="warn">
  `warpToSlot` advances the clock's `slot` field but does **not** automatically
  update `epoch` or `unixTimestamp`. Use `setClock` for full control over clock
  fields.
</Callout>

## Manual Clock Manipulation

When your program reads `epoch` or `unix_timestamp` from the Clock sysvar, use
`setClock` to set those fields directly:

```typescript
import { createClient, generateKeyPairSigner } from "@solana/kit";
import { litesvm } from "@solana/kit-plugin-litesvm";
import { signer } from "@solana/kit-plugin-signer";

const mySigner = await generateKeyPairSigner();
const client = createClient().use(signer(mySigner)).use(litesvm());
client.svm.withSysvars();

// Get clock, mutate, write back
const clock = client.svm.getClock();
clock.slot = 50000n;
clock.epoch = 5n;
clock.unixTimestamp = 1700000000n;
client.svm.setClock(clock);

const after = client.svm.getClock();
console.log("Slot:", after.slot); // 50000n
console.log("Epoch:", after.epoch); // 5n
console.log("Timestamp:", after.unixTimestamp); // 1700000000n
```

This mirrors the Rust `set_sysvar(&clock)` pattern. Use `warpToSlot` for simple
slot advancement, `setClock` when you need epoch or timestamp control.

## Use Cases

Time manipulation is useful for testing:

| Scenario                | Approach                           |
| ----------------------- | ---------------------------------- |
| Token vesting           | Warp past vesting cliff/milestones |
| Auction endings         | Warp past auction end slot         |
| Staking rewards         | Use `setClock` to set epoch        |
| Time-locked withdrawals | Warp past unlock slot              |
| Rate limiting           | Warp between allowed intervals     |
| Expiring orders         | Warp past order expiration         |

<Callout type="info">
  Remember that `warpToSlot` only changes the slot. The unix timestamp may not
  update proportionally depending on the SVM implementation.
</Callout>

## Key Points

1. **Enable Sysvars**: Call `withSysvars()` before using clock methods
2. **Warp Forward**: Use `warpToSlot(slot)` to advance the slot
3. **Full Control**: Use `setClock` when you need to set `epoch`,
   `unixTimestamp`, or other clock fields
4. **Read Clock**: Use `getClock()` to read current slot, epoch, timestamp
5. **Test Pattern**: Test before and after time boundaries
