Skip to content

avdcr/will-wallet

Repository files navigation

Will Wallet - Solana On-Chain Estate Planning

A Solana smart contract that enables the distribution of a vault of digital assets to designated beneficiaries after a configurable period of vault inactivity.

Overview

Will Wallet implements a solution for "crypto wallet inheritance":

  • Checks vault inactivity using blockchain slot numbers
  • Allows distribution of SOL and SPL tokens to beneficiaries after inactivity periods
  • Prevents unauthorized access through cryptographic ownership verification
  • Supports up to 8 beneficiaries with customizable percentage distributions
  • Provides maker control with ability to withdraw, update beneficiaries, and trigger immediate distributions

Core Concepts

Vault

A Program Derived Address (PDA) that stores:

  • Maker's public key (vault owner)
  • List of beneficiaries and their percentage allocations
  • Inactivity period (measured in blockchain slots)
  • Last activity slot for timing calculations
  • SOL and SPL token balances

Activity Tracking

Uses Solana's consensus-validated slot numbers to estimate inactivity time. Any vault operation (deposits, withdrawals, keep_alive calls) updates the last activity slot.

Distribution Logic

  • Last beneficiary automatically receives remainder percentage to ensure 100% distribution
  • Distributions only occur after inactivity_period_slots have passed since last activity
  • Rent-exempt balance protection prevents vault drainage

Available Methods

create_vault(beneficiaries, inactivity_period_slots)

Purpose: Initialize a new vault with beneficiaries and inactivity settings Parameters:

  • beneficiaries: Vec<Beneficiary> - List of up to 8 beneficiaries with addresses and percentages
  • inactivity_period_slots: u64 - Number of slots of inactivity before distribution is allowed

Beneficiary Structure:

struct Beneficiary {
    address: Pubkey,    // Beneficiary's wallet address
    percentage: u8,     // Percentage allocation (0-100, last beneficiary gets remainder)
}

deposit_sol(amount)

Purpose: Add SOL to the vault and update activity timestamp Parameters:

  • amount: u64 - Amount in lamports to deposit Access: Maker only

deposit_token(amount)

Purpose: Add SPL tokens to the vault and update activity timestamp Parameters:

  • amount: u64 - Amount of tokens to deposit (in token's native units) Access: Maker only Requires: maker_token_account, mint, associated_token_program, and system_program accounts Security: Vault token account is automatically derived and created if needed using PDA authority

withdraw_sol(amount)

Purpose: Withdraw SOL from vault and update activity timestamp Parameters:

  • amount: u64 - Amount in lamports to withdraw Access: Maker only

withdraw_token(amount)

Purpose: Withdraw SPL tokens from vault and update activity timestamp Parameters:

  • amount: u64 - Amount of tokens to withdraw Access: Maker only Requires: maker_token_account, mint, and associated_token_program accounts Security: Vault token account is derived from vault PDA and mint, preventing user manipulation

keep_alive()

Purpose: Update last activity slot without moving funds Parameters: None Access: Maker only

update_beneficiary_address(index, new_address)

Purpose: Change a beneficiary's address (maker-controlled) Parameters:

  • index: usize - Index of beneficiary to update (0-based)
  • new_address: Pubkey - New wallet address for the beneficiary Access: Maker only

change_beneficiary_address(new_address)

Purpose: Allow beneficiary to update their own address Parameters:

  • new_address: Pubkey - New wallet address Access: Current beneficiary only

trigger_distribution()

Purpose: Immediately distribute all vault funds to beneficiaries Parameters: None Access: Maker only Requires: List of beneficiary accounts in remaining_accounts

claim_distribution()

Purpose: Distribute funds after inactivity period has elapsed Parameters: None Access: Anyone (typically called by beneficiaries) Requires:

  • Inactivity period must have elapsed
  • List of beneficiary accounts in remaining_accounts

close_vault()

Purpose: Close vault and return remaining SOL to maker Parameters: None Access: Maker only

Happy Path Command Line Example

Here's a complete example of setting up and using a will wallet from the command line:

Development setup

# Install Solana CLI tools
sh -c "$(curl -sSfL https://release.solana.com/v1.17.0/install)"

# Install Anchor
npm install -g @coral-xyz/anchor-cli

# Clone and setup project
git clone <repository-url>
cd will-wallet
yarn install

# Generate a test keypair (for development only)
solana-keygen new --no-bip39-passphrase --silent --outfile ~/.config/solana/id.json

1. Deploy the Contract

# Start local validator
solana-test-validator

# In another terminal, build and deploy
anchor build
anchor deploy

# Note the Program ID from output (should match Anchor.toml)

2. Create a Will Vault

# Create vault with 2 beneficiaries
# Beneficiary 1: 60%, Beneficiary 2: gets remainder (40%)
# Inactivity period: 1,000,000 slots (~11.5 days at 2.5 slots/second)

anchor run create-vault \
  --provider.cluster localnet \
  --beneficiaries '[
    {"address": "BENEFICIARY1_PUBKEY_HERE", "percentage": 60},
    {"address": "BENEFICIARY2_PUBKEY_HERE", "percentage": 0}
  ]' \
  --inactivity-period 1000000

3. Fund the Vault

# Deposit 5 SOL to the vault
anchor run deposit-sol --amount 5000000000  # 5 SOL in lamports

# Deposit SPL tokens (requires mint address)
anchor run deposit-token --amount 1000000000 --mint YOUR_TOKEN_MINT_ADDRESS

4. Normal Activity (Keeping the Will Active)

# Option 1: Make deposits/withdrawals (updates activity automatically)
anchor run deposit-sol --amount 1000000000  # 1 SOL

# Option 2: Send keep-alive signal without moving funds
anchor run keep-alive

# Option 3: Withdraw some funds
anchor run withdraw-sol --amount 500000000  # 0.5 SOL

5. Update Beneficiaries

# Maker updates beneficiary address
anchor run update-beneficiary \
  --index 0 \
  --new-address "NEW_BENEFICIARY_PUBKEY"

# Beneficiary updates their own address
anchor run change-beneficiary-address \
  --new-address "NEW_ADDRESS" \
  --signer "CURRENT_BENEFICIARY_KEYPAIR"

6. Distribution Scenarios

Immediate Distribution (Maker-Triggered)

# Maker decides to distribute immediately
anchor run trigger-distribution \
  --beneficiaries '["BENEFICIARY1_PUBKEY", "BENEFICIARY2_PUBKEY"]'

Automatic Distribution (After Inactivity)

# After 1,000,000 slots of inactivity, anyone can trigger distribution
anchor run claim-distribution \
  --beneficiaries '["BENEFICIARY1_PUBKEY", "BENEFICIARY2_PUBKEY"]'

7. Vault Management

# Check vault status
anchor run get-vault-info

# Close vault and recover remaining SOL (maker only)
anchor run close-vault

Development Setup

Installation

git clone <repository-url>
cd will-wallet
yarn install

Building and Testing

# Build the smart contract
anchor build

# Run tests
anchor test

# Run linting
yarn run lint
yarn run lint:fix

Configuration

The project is configured for multiple environments in Anchor.toml:

  • localnet: Development and testing
  • devnet: Staging environment
  • mainnet: Production deployment

Program ID: 4LjAaMirdWtJz4QVy6kphwAAtVj3fGVQZw9qdMPova3L

Security Features

Slot-Based Timing

Uses consensus-validated blockchain slots instead of manipulatable timestamps for inactivity detection.

PDA Ownership

Vaults are Program Derived Addresses ensuring only the program can modify vault state and only authorized users can call functions.

Percentage Validation

Ensures total percentages don't exceed 100% and automatically handles remainder distribution.

Rent Protection

Maintains minimum rent-exempt balance to prevent vault account closure.

Secure Token Account Management

  • Automatic Derivation: Vault token accounts are derived deterministically from vault PDA + mint
  • PDA Ownership: Token accounts are owned by the vault PDA, preventing user manipulation
  • Auto-Creation: Token accounts are created automatically when needed using init_if_needed
  • No User Input: Users cannot specify arbitrary token accounts, eliminating attack vectors

Access Controls

  • Maker-only functions: deposits, withdrawals, beneficiary updates, immediate distributions
  • Beneficiary functions: self-address updates
  • Public functions: claim distribution (after inactivity period)

Error Handling

The contract includes comprehensive error codes:

  • TooManyBeneficiaries: Exceeds 8 beneficiary limit
  • NoBeneficiaries: Empty beneficiary list
  • InvalidPercentageDistribution: Total percentages >= 100%
  • UnauthorizedMaker: Non-maker attempting maker-only operation
  • BeneficiaryNotFound: Invalid beneficiary index/address
  • InsufficientFunds: Withdrawal exceeds available balance
  • VaultStillActive: Attempting distribution before inactivity period
  • InvalidBeneficiaryIndex: Beneficiary index out of bounds

License

[Add your license information here]

Contributing

[Add contributing guidelines here]

About

A contract to implement "crypto wallet inheritance"

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors