Skip to main content

Overview

Accounts are fundamental to Solana development. This guide covers creating and managing keypairs, generating Program Derived Addresses (PDAs), and working with account metadata.

Creating and Loading Keypairs

Generating a New Keypair

The Signer interface provides methods to generate new Ed25519 keypairs:
import software.sava.core.accounts.Signer;
import software.sava.core.accounts.PublicKey;

// Generate a new keypair
byte[] keyPairBytes = Signer.generatePrivateKeyPairBytes();
Signer signer = Signer.createFromKeyPair(keyPairBytes);

// Access the public key
PublicKey publicKey = signer.publicKey();
System.out.println("Public Key: " + publicKey.toBase58());

Loading from Private Key

Create a signer from an existing private key:
// From 32-byte private key
byte[] privateKey = // ... your private key bytes
Signer signer = Signer.createFromPrivateKey(privateKey);

// From 64-byte keypair (private + public)
byte[] keyPair = // ... your keypair bytes
Signer signer = Signer.createFromKeyPair(keyPair);

Loading from Base58

Parse public keys from Base58-encoded strings:
import software.sava.core.accounts.PublicKey;

// From Base58 string
String base58Address = "11111111111111111111111111111111";
PublicKey publicKey = PublicKey.fromBase58Encoded(base58Address);

// From Base64
String base64Address = // ... base64 string
PublicKey publicKey = PublicKey.fromBase64Encoded(base64Address);
1
Step 1: Generate Private Key
2
Use Signer.generatePrivateKeyBytes() to create a new 32-byte private key using secure random generation.
3
Step 2: Create Key Pair
4
Call Signer.createFromPrivateKey() to derive the public key and create a signer instance.
5
Step 3: Store Securely
6
Save the keypair bytes securely. Never expose private keys in code or logs.

Generating Program Derived Addresses

PDAs are deterministic addresses derived from seeds and a program ID.

Finding a PDA

import software.sava.core.accounts.PublicKey;
import software.sava.core.accounts.ProgramDerivedAddress;
import java.util.List;

PublicKey programId = PublicKey.fromBase58Encoded("YourProgramId");
PublicKey userAccount = PublicKey.fromBase58Encoded("UserPublicKey");

// Define seeds for PDA derivation
List<byte[]> seeds = List.of(
    "vault".getBytes(),
    userAccount.toByteArray()
);

// Find PDA with bump seed
ProgramDerivedAddress pda = PublicKey.findProgramAddress(seeds, programId);

System.out.println("PDA Address: " + pda.publicKey().toBase58());
System.out.println("Bump: " + pda.nonce());
Source: PublicKey.java:204-216

Creating Program Addresses

For manual PDA creation without bump finding:
// Create program address with specific seeds
PublicKey address = PublicKey.createProgramAddress(seeds, programId);

if (address != null) {
    System.out.println("Valid PDA: " + address.toBase58());
} else {
    System.out.println("Seeds do not create valid PDA");
}
Source: PublicKey.java:198-202

Creating Accounts with Seeds

Generate derived addresses using ASCII seeds:
PublicKey baseAccount = PublicKey.fromBase58Encoded("BaseAddress");
String seed = "my-seed";
PublicKey programId = PublicKey.fromBase58Encoded("ProgramId");

// Create derived address
PublicKey derivedAddress = PublicKey.createWithSeed(
    baseAccount,
    seed,
    programId
);

System.out.println("Derived Address: " + derivedAddress.toBase58());
Source: PublicKey.java:250-265
PDA seeds have a maximum length of 32 bytes, and you can use up to 16 seeds per derivation.

Working with Account Metadata

Account metadata describes how accounts are used in transactions.

Creating Account Metadata

import software.sava.core.accounts.meta.AccountMeta;
import software.sava.core.accounts.PublicKey;

PublicKey account = PublicKey.fromBase58Encoded("AccountAddress");

// Read-only account
AccountMeta readOnly = AccountMeta.createRead(account);

// Writable account
AccountMeta writable = AccountMeta.createWrite(account);

// Read-only signer
AccountMeta signer = AccountMeta.createReadOnlySigner(account);

// Writable signer
AccountMeta writableSigner = AccountMeta.createWritableSigner(account);

// Fee payer (special writable signer)
AccountMeta feePayer = AccountMeta.createFeePayer(account);
Source: AccountMeta.java:23-51

Account Metadata Properties

Query account metadata properties:
AccountMeta meta = AccountMeta.createWritableSigner(account);

// Check properties
boolean isSigner = meta.signer();
boolean isWritable = meta.write();
boolean isFeePayer = meta.feePayer();
boolean isInvoked = meta.invoked();
PublicKey pubkey = meta.publicKey();

Merging Account Metadata

When building transactions, metadata may need to be merged:
AccountMeta meta1 = AccountMeta.createRead(account);
AccountMeta meta2 = AccountMeta.createWrite(account);

// Merge - results in writable account
AccountMeta merged = meta1.merge(meta2);

System.out.println("Writable: " + merged.write()); // true
Source: AccountMeta.java:96

Creating Metadata from Flags

Use boolean flags to create metadata:
boolean writable = true;
boolean signer = false;

AccountMeta meta = AccountMeta.createMeta(account, writable, signer);

// With all flags
boolean invoked = false;
boolean feePayer = false;

AccountMeta fullMeta = AccountMeta.createMeta(
    account,
    invoked,
    feePayer,
    writable,
    signer
);
Source: AccountMeta.java:60-84

Key Validation

Sava performs automatic keypair validation:
// Validation happens automatically during creation
try {
    byte[] privateKey = // ... your key
    Signer signer = Signer.createFromPrivateKey(privateKey);
    // Key is valid
} catch (IllegalStateException e) {
    System.err.println("Invalid keypair: " + e.getMessage());
}
Source: Signer.java:22-31

Best Practices

  • Never hardcode private keys in source code
  • Use environment variables or secure key management systems
  • Clear sensitive data from memory after use
  • Cache PDAs when possible to avoid recomputation
  • Use meaningful, consistent seed structures
  • Document your seed derivation scheme
  • Mark accounts as writable only when necessary
  • Always include required signers
  • Use createFeePayer() for the transaction fee payer

Building Transactions

Learn how to construct transactions with account metadata

Signing and Sending

Sign transactions with your keypairs

Build docs developers (and LLMs) love