A Solana blockchain program that provides timelock functionality for both SOL (native tokens) and SPL tokens. Users can lock their tokens for a specified period and withdraw them only after the unlock timestamp has passed.
- SOL Timelock: Lock native SOL tokens with customizable unlock timestamps
- SPL Token Timelock: Lock any SPL tokens with timelock functionality
- Secure Withdrawal: Tokens can only be withdrawn by the original owner after the unlock time
- Flexible Timing: Set any future timestamp for unlock
- Built with Anchor: Uses the modern Anchor framework for Solana development
timelock-base-wallet-program/
βββ programs/timelock-base-wallet-program/ # Main Rust program code
β βββ src/
β β βββ lib.rs # Main program entry point
β β βββ state/
β β β βββ vault.rs # Vault state definition
β β βββ instructions/
β β β βββ sol/ # SOL token instructions
β β β βββ spl/ # SPL token instructions
β β βββ error.rs # Custom error definitions
β β βββ events.rs # Program events
β β βββ constants.rs # Program constants
β βββ Cargo.toml # Rust dependencies
βββ tests/ # TypeScript tests
β βββ timelock-base-wallet-program.ts # Main test file
βββ migrations/ # Anchor migrations
βββ Anchor.toml # Anchor configuration
βββ package.json # Node.js dependencies
βββ tsconfig.json # TypeScript configuration
Before building and running this project, ensure you have the following installed:
- Rust (latest stable version)
- Solana CLI (v1.18.0 or later)
- Anchor CLI (v0.31.1 or later)
- Node.js (v18 or later)
- Yarn package manager
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Install Solana CLI
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
# Install Anchor CLI
cargo install --git https://github.com/coral-xyz/anchor anchor-cli --locked
# Install Node.js and Yarn (if not already installed)
# Visit https://nodejs.org/ for Node.js installation
npm install -g yarn-
Clone the repository:
git clone <repository-url> cd timelock-base-wallet-program
-
Install dependencies:
yarn install
-
Build the Anchor program:
anchor build
-
Generate TypeScript types (optional):
anchor idl parse -f programs/timelock-base-wallet-program/src/lib.rs > target/idl/timelock_base_wallet_program.json
The project uses TypeScript tests with Mocha and Anchor's bankrun for testing:
-
Make sure the program is built:
anchor build
-
Run the tests:
anchor testOr run tests directly:
yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts
-
Run specific test files:
yarn run ts-mocha -p ./tsconfig.json tests/timelock-base-wallet-program.ts
-
Run tests with Surfpool from txtx:
surfpool start --watch surfpool run sol-vault surfpool run spl-vault
-
Lint TypeScript code:
yarn lint
-
Fix linting issues:
yarn lint:fix
pub fn initialize_sol_lock(
ctx: Context<InitializeSolLock>,
amount: u64,
unlock_timestamp: i64,
) -> Result<()>Creates a new timelock vault for SOL tokens.
Parameters:
amount: Amount of SOL to lock (in lamports)unlock_timestamp: Unix timestamp when tokens can be withdrawn
pub fn withdraw_sol_lock(ctx: Context<WithdrawSolLock>) -> Result<()>Withdraws SOL tokens from a vault after the unlock timestamp has passed.
pub fn initialize_spl_lock(
ctx: Context<InitializeSplLock>,
amount: u64,
unlock_timestamp: i64,
) -> Result<()>Creates a new timelock vault for SPL tokens.
Parameters:
amount: Amount of SPL tokens to lockunlock_timestamp: Unix timestamp when tokens can be withdrawn
pub fn withdraw_spl_lock(ctx: Context<WithdrawSplLock>) -> Result<()>Withdraws SPL tokens from a vault after the unlock timestamp has passed.
pub struct Vault {
pub owner: Pubkey, // Owner of the locked tokens
pub amount: u64, // Amount of tokens locked
pub bump: u8, // PDA bump seed
pub unlock_timestamp: i64, // When tokens can be withdrawn
pub mint: Option<Pubkey>, // None for SOL, Some(mint) for SPL
}UnlockTimestampMustBeInFuture: Unlock timestamp must be in the futureAmountMustBeGreaterThanZero: Amount must be greater than zeroVaultLocked: Vault is still locked (current time < unlock_timestamp)VaultLocking: Vault is in locking stateInvalidVaultMint: Invalid vault mint provided
import * as anchor from '@coral-xyz/anchor';
import { TimelockBaseWalletProgram } from './target/types/timelock_base_wallet_program';
// Initialize program
const program = anchor.workspace
.TimelockBaseWalletProgram as Program<TimelockBaseWalletProgram>;
// Lock SOL for 24 hours
const unlockTimestamp = Date.now() / 1000 + 24 * 60 * 60; // 24 hours from now
const amount = new anchor.BN(anchor.web3.LAMPORTS_PER_SOL); // 1 SOL
await program.methods
.initializeSolLock(amount, new anchor.BN(unlockTimestamp))
.accounts({
// ... account setup
})
.rpc();
// Withdraw after unlock time
await program.methods
.withdrawSolLock()
.accounts({
// ... account setup
})
.rpc();- Always verify the unlock timestamp is in the future when creating locks
- Ensure proper account validation in all instructions
- The program uses Program Derived Addresses (PDAs) for secure vault management
- All withdrawals are validated against the vault owner and unlock timestamp
This project is licensed under the ISC License.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run tests and linting
- Submit a pull request
For questions or issues, please open an issue in the GitHub repository.