Documentation
¶
Overview ¶
Package tokenguard provides token screening and safety analysis for Solana tokens.
The screener performs security checks on Solana tokens before trading, including:
- Mint/freeze authority status (rug pull risk)
- Liquidity depth (slippage risk)
- LP lock percentage (rug pull risk)
- Holder concentration (manipulation risk)
Results are cached to avoid redundant API calls.
Package tokenguard provides token screening and safety analysis for Solana tokens.
This library performs security checks on Solana tokens before trading, including:
- Authority validation (mint/freeze authority status)
- Liquidity analysis (minimum LP thresholds)
- Holder concentration analysis (top holder distribution)
- LP lock verification (estimated based on creator holdings)
The library supports three screening levels (Strict, Normal, Relaxed) with configurable thresholds for each check.
Example usage:
guard := tokenguard.New(tokenguard.Config{
BirdeyeAPIKey: "your-api-key",
})
result, err := guard.Screen(ctx, tokenMint, tokenguard.ScreeningLevelNormal)
if err != nil {
return err
}
if !result.Passed {
log.Printf("Token failed screening: %v", result.FailureReasons)
}
Index ¶
- Constants
- func ValidScreeningLevel(level ScreeningLevel) bool
- type Cache
- type Config
- type InMemoryCache
- func (c *InMemoryCache) Clear(_ context.Context)
- func (c *InMemoryCache) Close() error
- func (c *InMemoryCache) Delete(_ context.Context, tokenMint string)
- func (c *InMemoryCache) Get(_ context.Context, tokenMint string) (*TokenScreeningResult, bool)
- func (c *InMemoryCache) Set(_ context.Context, result *TokenScreeningResult) error
- func (c *InMemoryCache) Size() int
- type InMemoryCacheConfig
- type NoOpCache
- type Screener
- type ScreeningDetails
- type ScreeningLevel
- type ScreeningThresholds
- type TokenOverviewProvider
- type TokenScreeningResult
- type TokenSecurityProvider
Constants ¶
const DefaultCacheTTL = 5 * time.Minute
DefaultCacheTTL is the default time-to-live for cached screening results.
const DefaultMaxCacheSize = 10000
DefaultMaxCacheSize is the default maximum number of entries in the cache. With ~1KB per entry, 10,000 entries = ~10MB max memory.
Variables ¶
This section is empty.
Functions ¶
func ValidScreeningLevel ¶
func ValidScreeningLevel(level ScreeningLevel) bool
ValidScreeningLevel checks if a screening level is valid.
Types ¶
type Cache ¶
type Cache interface {
// Get retrieves a cached screening result if available and not expired.
Get(ctx context.Context, tokenMint string) (*TokenScreeningResult, bool)
// Set stores a screening result in the cache.
Set(ctx context.Context, result *TokenScreeningResult) error
}
Cache provides caching for screening results. This interface allows swapping cache implementations.
type Config ¶
type Config struct {
// SecurityProvider is used to fetch token security data (required).
SecurityProvider TokenSecurityProvider
// OverviewProvider is used to fetch token market data (required).
OverviewProvider TokenOverviewProvider
// Cache stores screening results (optional; nil disables caching).
Cache Cache
// Logger for structured logging (required).
Logger *zap.Logger
}
Config holds configuration for creating a new Screener.
type InMemoryCache ¶
type InMemoryCache struct {
// contains filtered or unexported fields
}
InMemoryCache provides a simple in-memory cache for screening results.
This implementation is suitable for single-instance deployments. For distributed deployments, use a custom cache implementation.
Features:
- Thread-safe
- Configurable TTL
- Configurable max size (prevents unbounded memory growth)
- Automatic expiration checks on read
- Periodic cleanup goroutine (optional)
func NewInMemoryCache ¶
func NewInMemoryCache(cfg InMemoryCacheConfig) *InMemoryCache
NewInMemoryCache creates a new in-memory cache.
func (*InMemoryCache) Clear ¶
func (c *InMemoryCache) Clear(_ context.Context)
Clear removes all entries from the cache.
func (*InMemoryCache) Close ¶
func (c *InMemoryCache) Close() error
Close stops the background cleanup goroutine. Must be called if CleanupInterval was set.
func (*InMemoryCache) Delete ¶
func (c *InMemoryCache) Delete(_ context.Context, tokenMint string)
Delete removes an entry from the cache.
func (*InMemoryCache) Get ¶
func (c *InMemoryCache) Get(_ context.Context, tokenMint string) (*TokenScreeningResult, bool)
Get retrieves a cached screening result.
Returns the result and true if found and not expired. Returns nil and false if not found or expired.
func (*InMemoryCache) Set ¶
func (c *InMemoryCache) Set(_ context.Context, result *TokenScreeningResult) error
Set stores a screening result in the cache.
If the cache is at maximum capacity, it will: 1. First evict all expired entries 2. If still at capacity, evict one entry (effectively random due to map iteration)
This prevents unbounded memory growth if cleanup goroutine fails or TTL is extended.
func (*InMemoryCache) Size ¶
func (c *InMemoryCache) Size() int
Size returns the number of entries in the cache (including expired).
type InMemoryCacheConfig ¶
type InMemoryCacheConfig struct {
// TTL is the time-to-live for cached entries.
// Defaults to 5 minutes if zero.
TTL time.Duration
// MaxSize is the maximum number of entries in the cache.
// When the cache is full, expired entries are evicted first,
// then the oldest entries are evicted to make room.
// Defaults to 10,000 if zero.
MaxSize int
// CleanupInterval is how often expired entries are removed.
// Set to 0 to disable background cleanup.
// If enabled, you must call Close() to stop the cleanup goroutine.
CleanupInterval time.Duration
}
InMemoryCacheConfig holds configuration for InMemoryCache.
type NoOpCache ¶
type NoOpCache struct{}
NoOpCache is a cache implementation that doesn't cache anything. Useful for testing or when caching should be disabled.
type Screener ¶
type Screener struct {
// contains filtered or unexported fields
}
Screener performs token security analysis before trades.
It checks:
- Mint/freeze authority status (rug pull risk)
- Liquidity depth (slippage risk)
- LP lock percentage (rug pull risk)
- Holder concentration (manipulation risk)
Results are cached to avoid redundant API calls.
func (*Screener) Screen ¶
func (s *Screener) Screen(ctx context.Context, tokenMint string, level ScreeningLevel) (*TokenScreeningResult, error)
Screen performs security analysis on a token.
It runs multiple checks based on the specified screening level and returns a result indicating whether the token passes screening.
The screening process:
- Check cache for recent results
- Fetch token security data (authorities, holders)
- Fetch token market data (liquidity)
- Run checks against thresholds
- Cache and return result
Example:
result, err := screener.Screen(ctx, "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", tokenguard.ScreeningLevelNormal)
if err != nil {
return err
}
if !result.Passed {
log.Warn("token failed screening", zap.Strings("reasons", result.FailureReasons))
}
type ScreeningDetails ¶
type ScreeningDetails struct {
// Authority checks
HasMintAuthority bool `json:"hasMintAuthority"` // Token has active mint authority
HasFreezeAuthority bool `json:"hasFreezeAuthority"` // Token has active freeze authority
// Liquidity check
LiquidityUSD decimal.Decimal `json:"liquidityUsd"` // Total liquidity in USD
// LP lock check (estimated from creator holdings)
LPLockedPct decimal.Decimal `json:"lpLockedPct"` // Estimated LP locked percentage
// Holder concentration checks
Top10HoldersPct decimal.Decimal `json:"top10HoldersPct"` // % held by top 10 holders
TopHolderPct decimal.Decimal `json:"topHolderPct"` // % held by single top holder
// Token-2022 specific features
IsToken2022 bool `json:"isToken2022"` // Uses Token-2022 program
HasTransferFee bool `json:"hasTransferFee"` // Has transfer fee enabled
NonTransferable bool `json:"nonTransferable"` // Token is non-transferable (soulbound)
MutableMetadata bool `json:"mutableMetadata"` // Metadata can be changed
}
ScreeningDetails contains detailed information about each check performed.
type ScreeningLevel ¶
type ScreeningLevel string
ScreeningLevel defines how strict token screening should be.
const ( // ScreeningLevelStrict requires: // - No mint authority // - No freeze authority // - Min liquidity: $50,000 // - Min LP locked: 80% // - Max top 10 holders: 40% // - Max single holder: 15% ScreeningLevelStrict ScreeningLevel = "strict" // ScreeningLevelNormal requires: // - No mint authority // - No freeze authority // - Min liquidity: $20,000 // - Min LP locked: 50% // - Max top 10 holders: 60% // - Max single holder: 25% ScreeningLevelNormal ScreeningLevel = "normal" // ScreeningLevelRelaxed requires: // - Mint authority allowed // - No freeze authority // - Min liquidity: $5,000 // - Min LP locked: 25% // - Max top 10 holders: 75% // - Max single holder: 35% ScreeningLevelRelaxed ScreeningLevel = "relaxed" )
Screening level constants.
type ScreeningThresholds ¶
type ScreeningThresholds struct {
// RequireNoMintAuth requires that mint authority be revoked/disabled.
RequireNoMintAuth bool
// RequireNoFreezeAuth requires that freeze authority be revoked/disabled.
RequireNoFreezeAuth bool
// MinLiquidityUSD is the minimum required liquidity in USD.
MinLiquidityUSD decimal.Decimal
// MinLPLockedPct is the minimum estimated LP locked percentage.
// This is estimated as 100% - creator percentage.
MinLPLockedPct decimal.Decimal
// MaxTop10HoldersPct is the maximum percentage that can be held by top 10 holders.
MaxTop10HoldersPct decimal.Decimal
// MaxTopHolderPct is the maximum percentage that can be held by a single holder.
MaxTopHolderPct decimal.Decimal
}
ScreeningThresholds defines thresholds for each screening level.
These can be customized per-screening call using ScreenWithThresholds, or use the preset levels (Strict/Normal/Relaxed).
type TokenOverviewProvider ¶
type TokenOverviewProvider interface {
GetTokenOverview(ctx context.Context, address string) (*birdeye.TokenOverview, error)
}
TokenOverviewProvider provides token market data (liquidity, price, volume). This interface allows mocking in tests.
type TokenScreeningResult ¶
type TokenScreeningResult struct {
// TokenMint is the token's mint address that was screened.
TokenMint string `json:"tokenMint"`
// Passed indicates whether the token passed all checks for the given level.
Passed bool `json:"passed"`
// Score is a 0-100 safety score, where higher = safer.
// Starts at 100 and deducts points for each failed check.
Score int `json:"score"`
// Level is the screening level that was applied.
Level ScreeningLevel `json:"level"`
// Details contains detailed information about each check performed.
Details ScreeningDetails `json:"details"`
// FailureReasons lists human-readable reasons why checks failed.
// Empty if Passed is true.
FailureReasons []string `json:"failureReasons,omitempty"`
// ScreenedAt is when the screening was performed.
ScreenedAt time.Time `json:"screenedAt"`
}
TokenScreeningResult contains the outcome of token analysis.
type TokenSecurityProvider ¶
type TokenSecurityProvider interface {
GetTokenSecurity(ctx context.Context, address string) (*birdeye.TokenSecurity, error)
}
TokenSecurityProvider provides token security data (authorities, holder concentration). This interface allows mocking in tests.