agentsclimarketplace

Evm decimal validation

Skill widnyana/eyay-toolkits/plugins/evm-decimal-validation/skills/evm-decimal-validation

Validate and configure token decimals for EVM-compatible blockchain deployments. Use when working with ERC20 tokens, multi-chain deployments, token amount conversions, or when decimals might vary across chains.From its SKILL.md

Install
npx -y skills add widnyana/eyay-toolkits --skill evm-decimal-validation

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
  • runs commandsInstructs the agent to run 2 commands, including `grep -rn "18)" --include="*.go" | grep -i "decimal\|wei\|amount"` and 1 more.

SKILL.md

4.8 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

EVM Token Decimal Validation

Ensure token decimals are correctly configured for each blockchain deployment to prevent amount calculation errors.

Quick Start

  1. Check current configuration - Review network configs for decimal fields
  2. Validate against contracts - Query on-chain decimals() for each deployment
  3. Update configuration - Add per-chain decimals to network config
  4. Test conversions - Verify FromWei/ToWei work correctly

Token Decimal Standards

Common Decimal Values

DecimalsUse CaseExamples
18Standard ERC20 (most tokens)WETH, DAI, USDC (on some chains)
6StablecoinsUSDC, USDT (on Ethereum)
8Bitcoin-wrappedWBTC
2Fiat-backed (cents)IDRX, some CBDCs
0Raw integersSome wrapped tokens

Chain-Specific Variations

The same token contract deployed on different chains may use different decimals:

Token A on Ethereum:    18 decimals
Token A on Polygon:     0 decimals (different deployment)
Token A on BNB Chain:   0 decimals (different deployment)

Validation Checklist

Step 1: Audit Current Configuration

# Find hardcoded decimals
grep -rn "18)" --include="*.go" | grep -i "decimal\|wei\|amount"

# Check for decimals field in network config
grep -rn "Decimals" blockchain/networks.go

Step 2: Query On-Chain Values

// Get decimals from contract
decimals, err := contract.Decimals(nil)
if err != nil {
    return fmt.Errorf("failed to get decimals: %w", err)
}

Step 3: Update Network Config

type NetworkConfig struct {
    // ... existing fields ...
    Decimals uint8 // Token decimals for this deployment
}

// In SupportedNetworks
BaseMainnet: {
    // ...
    Decimals: 2, // From on-chain query
},

Step 4: Add Helper Function

// GetDecimals returns token decimals for a chain ID.
// Always provide a sensible fallback.
func GetDecimals(chainID uint64) uint8 {
    config, _, exists := GetNetworkConfigByChainID(chainID)
    if !exists {
        return 2 // Fallback to majority value
    }
    return config.Decimals
}

Step 5: Replace Hardcoded Values

// Before
return FromWei(balance, 18), nil

// After
return FromWei(balance, int32(GetDecimals(chainID))), nil

Common Pitfalls

Pitfall 1: Assuming All Chains Use Same Decimals

// WRONG: Hardcoded decimals
amount := FromWei(balance, 18)

// CORRECT: Per-chain decimals
amount := FromWei(balance, int32(GetDecimals(chainID)))

Pitfall 2: Missing Fallback Value

// WRONG: No fallback, potential nil pointer
return config.Decimals, nil

// CORRECT: Sensible fallback
if !exists {
    return 2 // Majority value or most common
}
return config.Decimals

Pitfall 3: Not Validating Config Against Chain

// Add startup validation
func ValidateDecimals() error {
    for name, config := range SupportedNetworks {
        onChainDecimals, err := queryOnChain(config)
        if err != nil {
            continue // Skip unreachable chains
        }
        if config.Decimals != onChainDecimals {
            return fmt.Errorf("%s: config=%d, on-chain=%d",
                name, config.Decimals, onChainDecimals)
        }
    }
    return nil
}

Test Patterns

func TestGetDecimals(t *testing.T) {
    testCases := map[uint64]uint8{
        8453: 2,  // Base
        137:  0,  // Polygon
        56:   0,  // BSC
    }

    for chainID, expected := range testCases {
        got := GetDecimals(chainID)
        if got != expected {
            t.Errorf("Chain %d: expected %d, got %d", chainID, expected, got)
        }
    }
}

func TestGetDecimalsFallback(t *testing.T) {
    got := GetDecimals(999999) // Unknown chain
    if got != 2 {
        t.Errorf("Unknown chain should return fallback, got %d", got)
    }
}

Integration Points

When adding decimal validation, check these areas:

AreaWhat to Check
Balance queriesBalanceOf() uses per-chain decimals
Total supplyTotalSupply() uses per-chain decimals
TransfersParseTokenAmount() receives correct decimals
Bridge operationsBoth source and dest chains considered
Fee calculationsPlatform fees use correct decimals
API responsesHuman-readable amounts properly converted

Token Decimals by Chain

See decimals-by-chain.md for a reference guide of common tokens and their decimals across different EVM chains.

Sources

What ships with it: 1 file

1.7 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.