π₯ Honorable Mention - Superteam Earn - Recognized for innovative time-locked wallet solution on Solana blockchain.
A comprehensive Solana library for creating time-locked wallets that allows users to lock SOL or SPL tokens with a predefined unlock timestamp. Perfect for vesting schedules, savings plans, or any time-based asset management.
- π Time-Locked Wallets: Lock SOL or SPL tokens until a specific timestamp
- β° Flexible Timing: Support for any future timestamp (minutes to years)
- π‘οΈ Security: Built with reentrancy protection and comprehensive error handling
- π Solana Native: Full integration with Solana's architecture using Anchor framework
- π¦ Developer Friendly: TypeScript SDK with full type safety
- βοΈ React Ready: Pre-built hooks and components for frontend integration
- π§ͺ Well Tested: Comprehensive test suite for both devnet and localnet
time-locked-wallet-solana-lib/
βββ programs/
β βββ time-locked-wallet/ # Rust/Anchor Solana program
β βββ src/
β β βββ lib.rs # Main program entry point
β β βββ state.rs # Account structures
β β βββ instructions/ # Program instructions
β β βββ errors.rs # Custom error definitions
β β βββ events.rs # Event definitions
β βββ Cargo.toml
βββ packages/
β βββ core/ # TypeScript SDK
β βββ src/
β β βββ client.ts # Main client for production
β β βββ client-demo.ts # Demo client for testing
β β βββ types.ts # TypeScript definitions
β β βββ builders.ts # Transaction builders
β β βββ utils/ # Utility functions
β βββ package.json
βββ target/
β βββ idl/ # Generated IDL files
β βββ types/ # Generated TypeScript types
βββ tests/ # Test suites
βββ localnet-test.ts # Local development tests
βββ devnet-test.ts # Devnet integration tests
- Node.js: Version 16+ required
- Rust: Latest stable version
- Solana CLI: Version 1.14+
- Anchor CLI: Version 0.28+
- Git: For cloning the repository
# Clone the repository
git clone https://github.com/your-org/time-locked-wallet-solana-lib.git
cd time-locked-wallet-solana-lib
# Install dependencies
npm install
# Build the Anchor program
anchor build
# Run tests (requires Solana test validator)
anchor testThe Time-Locked Wallet uses Program Derived Addresses (PDAs) to create secure, deterministic wallet addresses that can only be unlocked after a specified timestamp. Here's the flow:
- Initialize: Create a time-locked wallet with an unlock timestamp
- Deposit: Lock SOL or SPL tokens into the wallet
- Wait: Funds remain locked until the unlock timestamp
- Withdraw: Once unlocked, only the owner can withdraw funds
The on-chain Rust program handles:
- Wallet initialization with unlock timestamps
- Secure fund deposits (SOL and SPL tokens)
- Time-based withdrawal validation
- PDA-based security model
The client library provides:
- Easy-to-use JavaScript/TypeScript API
- Transaction building and signing
- Account data fetching and parsing
- Error handling and validation
Auto-generated TypeScript definitions from the Anchor IDL for type safety.
import { TimeLockClient, AssetType } from '@time-locked-wallet/core';
import { Connection, PublicKey } from '@solana/web3.js';
// Initialize client
const connection = new Connection('https://api.devnet.solana.com');
const client = new TimeLockClient(connection, wallet);
// Create a time-locked wallet (unlock in 1 hour)
const unlockTimestamp = Math.floor(Date.now() / 1000) + 3600;
const result = await client.createSolTimeLock({
owner: wallet.publicKey,
unlockTimestamp,
assetType: AssetType.Sol,
amount: 1000000000 // 1 SOL in lamports
});
console.log('Time-lock created:', result.timeLockAccount.toString());
console.log('Transaction signature:', result.signature);// Deposit more SOL to existing time-lock
await client.depositSol({
timeLockAccount: result.timeLockAccount,
amount: 500000000 // 0.5 SOL in lamports
});// Check if funds can be withdrawn
const canWithdraw = await client.canWithdraw(result.timeLockAccount);
const remainingTime = await client.getRemainingLockTime(result.timeLockAccount);
console.log('Can withdraw:', canWithdraw);
console.log('Time remaining:', remainingTime, 'seconds');// Withdraw funds (only works after unlock time)
if (canWithdraw) {
const signature = await client.withdrawSol({
timeLockAccount: result.timeLockAccount,
owner: wallet.publicKey
});
console.log('Withdrawal successful:', signature);
}// Create token time-lock
const tokenResult = await client.createTokenTimeLock({
owner: wallet.publicKey,
unlockTimestamp: Math.floor(Date.now() / 1000) + 86400, // 24 hours
assetType: AssetType.Token
});
// Deposit tokens
await client.depositToken({
timeLockAccount: tokenResult.timeLockAccount,
amount: 1000000, // Token amount (adjust for decimals)
tokenFromAta: userTokenAccount,
tokenVault: vaultAccount,
tokenProgramId: TOKEN_PROGRAM_ID
});The program is deployed with the following ID:
899SKikn1WiRBSurKhMZyNCNvYmWXVE6hZFYbFim293g
// Devnet
const connection = new Connection('https://api.devnet.solana.com');
// Mainnet Beta
const connection = new Connection('https://api.mainnet-beta.solana.com');
// Localnet (for development)
const connection = new Connection('http://localhost:8899');The project includes a comprehensive testing suite for both development and production environments.
# Local development testing
npm run test:localnet
# Production-like testing
npm run test:devnet
# Both environments
npm run test:all
# Show all available test commands
npm run test:help- π Complete Guide:
tests/README.md- Full testing documentation - π Quick Start:
tests/QUICK_START.md- TL;DR version - π Devnet Setup:
tests/DEVNET_SETUP.md- Wallet funding guide
β
Initialize SOL time-locked wallets
β
Deposit SOL to time-locked accounts
β
Reject early withdrawal (time-lock mechanism)
β
Allow withdrawal after unlock time
Performance: 4/4 tests passing in ~11s (localnet) / ~25s (devnet)
# Start local Solana test validator
solana-test-validator
# In another terminal, run tests
anchor test --skip-deploy# Configure Solana CLI for devnet
solana config set --url https://api.devnet.solana.com
# Run devnet integration tests
npm run test:devnet- Operations are protected against reentrancy attacks
- Uses a processing flag to prevent concurrent operations
- All wallets use Program Derived Addresses
- Deterministic addresses based on owner + timestamp
- No private key management required
- Unlock timestamps must be in the future
- Clock-based validation using Solana's on-chain clock
- Protection against time manipulation
- Comprehensive error types and messages
- Input validation on all parameters
- Clear error reporting for debugging
createSolTimeLock(params)- Create new SOL time-lockdepositSol(params)- Deposit SOL to existing time-lockwithdrawSol(params)- Withdraw SOL (if unlocked)
createTokenTimeLock(params)- Create new token time-lockdepositToken(params)- Deposit tokens to existing time-lockwithdrawToken(params)- Withdraw tokens (if unlocked)
getTimeLockData(account)- Get time-lock account datacanWithdraw(account)- Check if withdrawal is availablegetRemainingLockTime(account)- Get seconds until unlock
findTimeLockPDA(owner, timestamp)- Calculate PDA addressvalidatePublicKey(key)- Validate public key formatvalidateTimestamp(timestamp)- Validate timestamp formatvalidateAmount(amount)- Validate amount format
interface CreateTimeLockParams {
owner: PublicKey;
unlockTimestamp: number;
assetType: AssetType;
amount?: number;
}
interface DepositParams {
timeLockAccount: PublicKey;
amount: number;
depositor?: PublicKey;
}
interface WithdrawParams {
timeLockAccount: PublicKey;
owner: PublicKey;
}
enum AssetType {
Sol = "sol",
Token = "token"
}1. InstructionDidNotDeserialize Error
Error Code: 102
- Cause: Mismatch between instruction parameters
- Solution: Ensure you're using the latest version and correct parameter types
2. Custom Program Error: 0x1771
Custom program error: 0x1771 (TimeLockNotExpired)
- Cause: Attempting to withdraw before unlock time
- Solution: Wait until unlock timestamp or check
canWithdraw()
3. Account Not Found
Error: Account not found
- Cause: Time-lock account doesn't exist or incorrect PDA calculation
- Solution: Verify account was created and use correct owner/timestamp
- Check the Tests: Look at
tests/directory for working examples - Enable Debug Logs: Use
ANCHOR_LOG=debugfor detailed logging - Verify Network: Ensure you're connecting to the correct network
- Check Balance: Ensure sufficient SOL for transaction fees
# Clone and setup
git clone <repository-url>
cd time-locked-wallet-solana-lib
npm install
# Build program
anchor build
# Generate types
anchor run test
# Run development server (if using examples)
cd examples/react-vite
npm run dev- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Anchor Framework
- Inspired by the Solana ecosystem
- Thanks to the Solana community for feedback and contributions
