Skip to main content

TokenAccount Record

software.sava.core.accounts.token.TokenAccount Represents an SPL Token account containing token balance and metadata.

Constants

int BYTES = 165;
BYTES
int
Standard size of a token account (165 bytes)

Field Offsets

int MINT_OFFSET = 0;
int OWNER_OFFSET = 32;
int AMOUNT_OFFSET = 64;
int DELEGATE_OPTION_OFFSET = 72;
int DELEGATE_OFFSET = 76;
int STATE_OFFSET = 108;
int IS_NATIVE_OPTION_OFFSET = 109;
int IS_NATIVE_OFFSET = 113;
int DELEGATED_AMOUNT_OFFSET = 121;
int CLOSE_AUTHORITY_OPTION_OFFSET = 129;
int CLOSE_AUTHORITY_OFFSET = 133;

Record Components

record TokenAccount(
    PublicKey address,
    PublicKey mint,
    PublicKey owner,
    long amount,
    int delegateOption,
    PublicKey delegate,
    AccountState state,
    int isNativeOption,
    long isNative,
    long delegatedAmount,
    int closeAuthorityOption,
    PublicKey closeAuthority
)
address
PublicKey
Token account address
mint
PublicKey
Mint address for this token type
owner
PublicKey
Owner of the token account
amount
long
Token balance (raw amount, not accounting for decimals)
delegateOption
int
0 = no delegate, 1 = has delegate
delegate
PublicKey
Delegate authority (null if delegateOption == 0)
state
AccountState
Account state (Uninitialized, Initialized, Frozen)
isNativeOption
int
0 = not native, 1 = native SOL
isNative
long
Rent-exempt reserve for native accounts
delegatedAmount
long
Amount delegated to delegate
closeAuthorityOption
int
0 = no close authority, 1 = has close authority
closeAuthority
PublicKey
Close authority (null if closeAuthorityOption == 0)

Factory Methods

static TokenAccount read(PublicKey publicKey, byte[] data)
static TokenAccount read(PublicKey publicKey, byte[] data, int offset)
publicKey
PublicKey
required
Token account address
data
byte[]
required
Account data (165 bytes)
return
TokenAccount
Parsed token account

RPC Filters

static Filter createMintFilter(PublicKey mint)
return
Filter
RPC filter for accounts with specified mint
static Filter createOwnerFilter(PublicKey owner)
return
Filter
RPC filter for accounts with specified owner
static Filter createDelegateFilter(PublicKey delegate)
static Filter createCloseAuthorityFilter(PublicKey closeAuthority)

Example Usage

import software.sava.core.accounts.token.TokenAccount;
import software.sava.core.accounts.PublicKey;

// Parse token account from data
var tokenAccount = TokenAccount.read(accountAddress, accountData);

// Access fields
var mint = tokenAccount.mint();
var owner = tokenAccount.owner();
var balance = tokenAccount.amount();

System.out.println("Token: " + mint.toBase58());
System.out.println("Owner: " + owner.toBase58());
System.out.println("Balance: " + balance);

// Check if frozen
if (tokenAccount.state() == AccountState.Frozen) {
    System.out.println("Account is frozen");
}

// Check for delegate
if (tokenAccount.delegateOption() == 1) {
    var delegate = tokenAccount.delegate();
    var delegatedAmount = tokenAccount.delegatedAmount();
    System.out.println("Delegated " + delegatedAmount + " to " + delegate.toBase58());
}

// Create RPC filter to find all token accounts for a mint
var filter = TokenAccount.createMintFilter(mintAddress);

Mint Record

software.sava.core.accounts.token.Mint Represents an SPL Token mint account.

Constants

int BYTES = 82;

Record Components

record Mint(
    PublicKey address,
    PublicKey mintAuthority,
    long supply,
    int decimals,
    boolean initialized,
    PublicKey freezeAuthority
)
address
PublicKey
Mint account address
mintAuthority
PublicKey
Authority that can mint new tokens (null if no authority)
supply
long
Total supply of tokens (raw amount)
decimals
int
Number of decimals (0-9)
initialized
boolean
Whether mint is initialized
freezeAuthority
PublicKey
Authority that can freeze accounts (null if no authority)

Factory Method

static Mint read(PublicKey address, byte[] data)
return
Mint
Parsed mint account, or null if data is empty

Example Usage

import software.sava.core.accounts.token.Mint;

// Parse mint account
var mint = Mint.read(mintAddress, mintData);

// Access fields
var decimals = mint.decimals();
var supply = mint.supply();
var mintAuthority = mint.mintAuthority();

System.out.println("Decimals: " + decimals);
System.out.println("Supply: " + supply);
System.out.println("UI Supply: " + (supply / Math.pow(10, decimals)));

// Check authorities
if (mint.mintAuthority() != null) {
    System.out.println("Mint authority: " + mint.mintAuthority().toBase58());
} else {
    System.out.println("Minting disabled (no authority)");
}

if (mint.freezeAuthority() != null) {
    System.out.println("Can freeze accounts");
}

Token2022 Record

software.sava.core.accounts.token.Token2022 Represents a Token-2022 mint with extensions.

Record Components

record Token2022(
    Mint mint,
    AccountType accountType,
    Map<ExtensionType, TokenExtension> extensions
)
mint
Mint
Base mint information
accountType
AccountType
Account type (Uninitialized, Mint, Account)
extensions
Map<ExtensionType, TokenExtension>
Map of extension type to extension data

Factory Method

static Token2022 read(PublicKey address, byte[] data)
return
Token2022
Parsed Token-2022 mint with extensions

Extension Types

enum ExtensionType {
    Uninitialized,
    TransferFeeConfig,
    TransferFeeAmount,
    MintCloseAuthority,
    ConfidentialTransferMint,
    ConfidentialTransferAccount,
    DefaultAccountState,
    ImmutableOwner,
    MemoTransfer,
    NonTransferable,
    InterestBearingConfig,
    CpiGuard,
    PermanentDelegate,
    NonTransferableAccount,
    TransferHook,
    TransferHookAccount,
    ConfidentialTransferFeeConfig,
    ConfidentialTransferFeeAmount,
    MetadataPointer,
    TokenMetadata,
    GroupPointer,
    TokenGroup,
    GroupMemberPointer,
    TokenGroupMember,
    ConfidentialMintBurn,
    ScaledUiAmount,
    Pausable,
    PausableAccount
}

Example Usage

import software.sava.core.accounts.token.Token2022;
import software.sava.core.accounts.token.extensions.*;

// Parse Token-2022 mint
var token2022 = Token2022.read(mintAddress, mintData);

// Access base mint info
var mint = token2022.mint();
System.out.println("Supply: " + mint.supply());
System.out.println("Decimals: " + mint.decimals());

// Check extensions
var extensions = token2022.extensions();

if (extensions.containsKey(ExtensionType.TransferFeeConfig)) {
    var feeConfig = (TransferFeeConfig) extensions.get(ExtensionType.TransferFeeConfig);
    System.out.println("Has transfer fee");
}

if (extensions.containsKey(ExtensionType.MetadataPointer)) {
    var metadata = (MetadataPointer) extensions.get(ExtensionType.MetadataPointer);
    System.out.println("Metadata pointer: " + metadata.metadataAddress().toBase58());
}

if (extensions.containsKey(ExtensionType.PermanentDelegate)) {
    var permDelegate = (PermanentDelegate) extensions.get(ExtensionType.PermanentDelegate);
    System.out.println("Permanent delegate: " + permDelegate.delegate().toBase58());
}

Token2022Account Record

software.sava.core.accounts.token.Token2022Account Represents a Token-2022 token account with extensions.

Example Usage

import software.sava.core.accounts.token.Token2022Account;

// Parse Token-2022 account
var token2022Account = Token2022Account.read(accountAddress, accountData);

// Access token account info
var tokenAccount = token2022Account.tokenAccount();
var owner = tokenAccount.owner();
var balance = tokenAccount.amount();

// Check for account extensions
var extensions = token2022Account.extensions();

if (extensions.containsKey(ExtensionType.ImmutableOwner)) {
    System.out.println("Owner cannot be changed");
}

if (extensions.containsKey(ExtensionType.CpiGuard)) {
    System.out.println("CPI guard enabled");
}

AccountState Enum

software.sava.core.accounts.token.AccountState
enum AccountState {
    Uninitialized,
    Initialized,
    Frozen
}

Common Token Operations

Calculate UI Amount

public static double toUiAmount(long rawAmount, int decimals) {
    return rawAmount / Math.pow(10, decimals);
}

public static long fromUiAmount(double uiAmount, int decimals) {
    return (long) (uiAmount * Math.pow(10, decimals));
}

// Example
var mint = Mint.read(mintAddress, mintData);
var tokenAccount = TokenAccount.read(accountAddress, accountData);

double uiBalance = toUiAmount(tokenAccount.amount(), mint.decimals());
System.out.println("Balance: " + uiBalance);

Find Associated Token Account

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

public static PublicKey findAssociatedTokenAddress(
    PublicKey wallet,
    PublicKey mint
) {
    var accounts = SolanaAccounts.MAIN_NET;
    var seeds = List.of(
        wallet.toByteArray(),
        accounts.tokenProgram().toByteArray(),
        mint.toByteArray()
    );
    var pda = PublicKey.findProgramAddress(
        seeds,
        accounts.associatedTokenAccountProgram()
    );
    return pda.publicKey();
}

// Usage
var ataAddress = findAssociatedTokenAddress(walletAddress, mintAddress);
System.out.println("ATA: " + ataAddress.toBase58());

Build docs developers (and LLMs) love