[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6JCYRH025KJM2MFZFRTCE61":3,"skill-same:01M6JCYRH025KJM2MFZFRTCE61":67},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":45,"commitSha":46,"skillDirectory":47,"forksCount":48,"repositoryHtmlUrl":49,"repositoryHomepageUrl":50,"ownerHtmlUrl":51,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":52,"install":53,"resources":66},"01M6JCYRH025KJM2MFZFRTCE61","evm-token-decimals",null,"Prevent silent decimal mismatch bugs across EVM chains. Covers runtime decimal lookup, chain-aware caching, bridged-token precision drift, and safe normalization for bots, dashboards, and DeFi tools.","S3YED\u002Fappie-kit","S3YED","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F62743867?v=4","01M6JBKBRRVP6KMS0VWZ27T3R6","01M6JBKBX0KG30284PW1DBYJT1",14,"MIT","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fecc\u002Fevm-token-decimals\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"token","evm token decimals","evm","drift","bugs","for","port","chain","runtime","adaptation","across","caching","safe","bots","direct","dashboards","normalization","Tools","lookup","defi","2026-11-10 10:12:30",false,"---\nname: evm-token-decimals\ndescription: Prevent silent decimal mismatch bugs across EVM chains. Covers runtime decimal lookup, chain-aware caching, bridged-token precision drift, and safe normalization for bots, dashboards, and DeFi tools.\norigin: ECC direct-port adaptation\nversion: \"1.0.0\"\n---\n\n# EVM Token Decimals\n\nSilent decimal mismatches are one of the easiest ways to ship balances or USD values that are off by orders of magnitude without throwing an error.\n\n## When to Use\n\n- Reading ERC-20 balances in Python, TypeScript, or Solidity\n- Calculating fiat values from on-chain balances\n- Comparing token amounts across multiple EVM chains\n- Handling bridged assets\n- Building portfolio trackers, bots, or aggregators\n\n## How It Works\n\nNever assume stablecoins use the same decimals everywhere. Query `decimals()` at runtime, cache by `(chain_id, token_address)`, and use decimal-safe math for value calculations.\n\n## Examples\n\n### Query decimals at runtime\n\n```python\nfrom decimal import Decimal\nfrom web3 import Web3\n\nERC20_ABI = [\n    {\"name\": \"decimals\", \"type\": \"function\", \"inputs\": [],\n     \"outputs\": [{\"type\": \"uint8\"}], \"stateMutability\": \"view\"},\n    {\"name\": \"balanceOf\", \"type\": \"function\",\n     \"inputs\": [{\"name\": \"account\", \"type\": \"address\"}],\n     \"outputs\": [{\"type\": \"uint256\"}], \"stateMutability\": \"view\"},\n]\n\ndef get_token_balance(w3: Web3, token_address: str, wallet: str) -> Decimal:\n    contract = w3.eth.contract(\n        address=Web3.to_checksum_address(token_address),\n        abi=ERC20_ABI,\n    )\n    decimals = contract.functions.decimals().call()\n    raw = contract.functions.balanceOf(Web3.to_checksum_address(wallet)).call()\n    return Decimal(raw) \u002F Decimal(10 ** decimals)\n```\n\nDo not hardcode `1_000_000` because a symbol usually has 6 decimals somewhere else.\n\n### Cache by chain and token\n\n```python\nfrom functools import lru_cache\n\n@lru_cache(maxsize=512)\ndef get_decimals(chain_id: int, token_address: str) -> int:\n    w3 = get_web3_for_chain(chain_id)\n    contract = w3.eth.contract(\n        address=Web3.to_checksum_address(token_address),\n        abi=ERC20_ABI,\n    )\n    return contract.functions.decimals().call()\n```\n\n### Handle odd tokens defensively\n\n```python\ntry:\n    decimals = contract.functions.decimals().call()\nexcept Exception:\n    logging.warning(\n        \"decimals() reverted on %s (chain %s), defaulting to 18\",\n        token_address,\n        chain_id,\n    )\n    decimals = 18\n```\n\nLog the fallback and keep it visible. Old or non-standard tokens still exist.\n\n### Normalize to 18-decimal WAD in Solidity\n\n```solidity\ninterface IERC20Metadata {\n    function decimals() external view returns (uint8);\n}\n\nfunction normalizeToWad(address token, uint256 amount) internal view returns (uint256) {\n    uint8 d = IERC20Metadata(token).decimals();\n    if (d == 18) return amount;\n    if (d \u003C 18) return amount * 10 ** (18 - d);\n    return amount \u002F 10 ** (d - 18);\n}\n```\n\n### TypeScript with ethers\n\n```typescript\nimport { Contract, formatUnits } from 'ethers';\n\nconst ERC20_ABI = [\n  'function decimals() view returns (uint8)',\n  'function balanceOf(address) view returns (uint256)',\n];\n\nasync function getBalance(provider: any, tokenAddress: string, wallet: string): Promise\u003Cstring> {\n  const token = new Contract(tokenAddress, ERC20_ABI, provider);\n  const [decimals, raw] = await Promise.all([\n    token.decimals(),\n    token.balanceOf(wallet),\n  ]);\n  return formatUnits(raw, decimals);\n}\n```\n\n### Quick on-chain check\n\n```bash\ncast call \u003Ctoken_address> \"decimals()(uint8)\" --rpc-url \u003Crpc>\n```\n\n## Rules\n\n- Always query `decimals()` at runtime\n- Cache by chain plus token address, not symbol\n- Use `Decimal`, `BigInt`, or equivalent exact math, not float\n- Re-query decimals after bridging or wrapper changes\n- Normalize internal accounting consistently before comparison or pricing\n","# EVM Token Decimals\n\nSilent decimal mismatches are one of the easiest ways to ship balances or USD values that are off by orders of magnitude without throwing an error.\n\n## When to Use\n\n- Reading ERC-20 balances in Python, TypeScript, or Solidity\n- Calculating fiat values from on-chain balances\n- Comparing token amounts across multiple EVM chains\n- Handling bridged assets\n- Building portfolio trackers, bots, or aggregators\n\n## How It Works\n\nNever assume stablecoins use the same decimals everywhere. Query `decimals()` at runtime, cache by `(chain_id, token_address)`, and use decimal-safe math for value calculations.\n\n## Examples\n\n### Query decimals at runtime\n\n```python\nfrom decimal import Decimal\nfrom web3 import Web3\n\nERC20_ABI = [\n    {\"name\": \"decimals\", \"type\": \"function\", \"inputs\": [],\n     \"outputs\": [{\"type\": \"uint8\"}], \"stateMutability\": \"view\"},\n    {\"name\": \"balanceOf\", \"type\": \"function\",\n     \"inputs\": [{\"name\": \"account\", \"type\": \"address\"}],\n     \"outputs\": [{\"type\": \"uint256\"}], \"stateMutability\": \"view\"},\n]\n\ndef get_token_balance(w3: Web3, token_address: str, wallet: str) -> Decimal:\n    contract = w3.eth.contract(\n        address=Web3.to_checksum_address(token_address),\n        abi=ERC20_ABI,\n    )\n    decimals = contract.functions.decimals().call()\n    raw = contract.functions.balanceOf(Web3.to_checksum_address(wallet)).call()\n    return Decimal(raw) \u002F Decimal(10 ** decimals)\n```\n\nDo not hardcode `1_000_000` because a symbol usually has 6 decimals somewhere else.\n\n### Cache by chain and token\n\n```python\nfrom functools import lru_cache\n\n@lru_cache(maxsize=512)\ndef get_decimals(chain_id: int, token_address: str) -> int:\n    w3 = get_web3_for_chain(chain_id)\n    contract = w3.eth.contract(\n        address=Web3.to_checksum_address(token_address),\n        abi=ERC20_ABI,\n    )\n    return contract.functions.decimals().call()\n```\n\n### Handle odd tokens defensively\n\n```python\ntry:\n    decimals = contract.functions.decimals().call()\nexcept Exception:\n    logging.warning(\n        \"decimals() reverted on %s (chain %s), defaulting to 18\",\n        token_address,\n        chain_id,\n    )\n    decimals = 18\n```\n\nLog the fallback and keep it visible. Old or non-standard tokens still exist.\n\n### Normalize to 18-decimal WAD in Solidity\n\n```solidity\ninterface IERC20Metadata {\n    function decimals() external view returns (uint8);\n}\n\nfunction normalizeToWad(address token, uint256 amount) internal view returns (uint256) {\n    uint8 d = IERC20Metadata(token).decimals();\n    if (d == 18) return amount;\n    if (d \u003C 18) return amount * 10 ** (18 - d);\n    return amount \u002F 10 ** (d - 18);\n}\n```\n\n### TypeScript with ethers\n\n```typescript\nimport { Contract, formatUnits } from 'ethers';\n\nconst ERC20_ABI = [\n  'function decimals() view returns (uint8)',\n  'function balanceOf(address) view returns (uint256)',\n];\n\nasync function getBalance(provider: any, tokenAddress: string, wallet: string): Promise\u003Cstring> {\n  const token = new Contract(tokenAddress, ERC20_ABI, provider);\n  const [decimals, raw] = await Promise.all([\n    token.decimals(),\n    token.balanceOf(wallet),\n  ]);\n  return formatUnits(raw, decimals);\n}\n```\n\n### Quick on-chain check\n\n```bash\ncast call \u003Ctoken_address> \"decimals()(uint8)\" --rpc-url \u003Crpc>\n```\n\n## Rules\n\n- Always query `decimals()` at runtime\n- Cache by chain plus token address, not symbol\n- Use `Decimal`, `BigInt`, or equivalent exact math, not float\n- Re-query decimals after bridging or wrapper changes\n- Normalize internal accounting consistently before comparison or pricing\n",{"name":5,"origin":43,"version":44,"description":7},"ECC direct-port adaptation","1.0.0","master","8ec37df6d71fb664ea19d32c079e7d3ff931a8e0","skills\u002Fecc\u002Fevm-token-decimals",3,"https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit","https:\u002F\u002Fweblyfe.ai","https:\u002F\u002Fgithub.com\u002FS3YED","2026-08-27 01:54:02",{"source":8,"skillName":5,"commands":54,"prompt":64,"zipAvailable":65},[55,58,61],{"tool":56,"command":57},"npx","npx skills add S3YED\u002Fappie-kit --skill evm-token-decimals",{"tool":59,"command":60},"bunx","bunx skills add S3YED\u002Fappie-kit --skill evm-token-decimals",{"tool":62,"command":63},"pnpm","pnpm dlx skills add S3YED\u002Fappie-kit --skill evm-token-decimals","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fecc\u002Fevm-token-decimals\u002FSKILL.md",true,[],[68,103,138,164,194,218],{"skillNo":69,"name":70,"nameZh":6,"description":71,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":72,"categories":73,"keywords":85,"publishedAt":38},"01M6JFD4M6N4DSGC7TXEJ5R3J2","ai-music","AI music generation and audio tools: HeartMuLa lyrics-to-music generation, songwriting craft (+ Suno prompts), and audio spectrogram\u002Ffeature visualization.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fwethlete\u002Fai-music\u002FSKILL.md",[74,79,82],{"categoryNo":75,"categoryName":76,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000013","分析与可视化","SCENARIO","使用场景",{"categoryNo":80,"categoryName":81,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":83,"categoryName":84,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000023","Skill与智能体开发",[86,87,88,89,35,90,91,92,93,94,95,96,97,98,99,100,101,102],"music","ai music","humanizer","visualization","Audio","hermes","hermes agent","songwriting","suno","lyrics","prompts","heartmula","craft","generation","feature","ai music generation","music generation",{"skillNo":104,"name":105,"nameZh":6,"description":106,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":117,"publishedAt":38},"01M6JFCZE4XNFQFMNZDHKHT5V5","agentic-webdesign-design-system-ingestion","Use v0 Design Systems 2.0, Bolt Design System Agents, or Lovable to generate production UI from a client's real design system components — not generic Tailwind. Use when building a client website where brand consistency matters.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fweb-design\u002Fagentic-webdesign-design-system-ingestion\u002FSKILL.md",[109,112],{"categoryNo":110,"categoryName":111,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":113,"categoryName":114,"taxonomyType":115,"taxonomyTypeDesc":116},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137],"design","agentic","design system","system","ingestion","webdesign","agentic webdesign design system ingestion","components","generate","design systems","website","ui","Tailwind","bolt","lovable","v0","design-system","wed","design system components","appie",{"skillNo":139,"name":140,"nameZh":6,"description":141,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":142,"categories":143,"keywords":146,"publishedAt":38},"01M6JFCVPX3913CFAS6QQJ33ZB","agentic-webdesign-agent-elements","Use 21st.dev Agent Elements — 25 shadcn\u002Fui components purpose-built for AI agent UIs. Tool cards (Bash, Edit, Search, Plan, Subagent, MCP), chat, input, streaming. Open source, shadcn-registry install, no runtime lock-in.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fweb-design\u002Fagentic-webdesign-agent-elements\u002FSKILL.md",[144,145],{"categoryNo":83,"categoryName":84,"taxonomyType":77,"taxonomyTypeDesc":78},{"categoryNo":113,"categoryName":114,"taxonomyType":115,"taxonomyTypeDesc":116},[119,147,123,148,149,150,125,151,152,153,154,155,156,157,158,159,160,161,162,163],"elements","agentic webdesign agent elements","MCP","ai agent","registry","search","streaming","open source","open","Bash","plan","subagent","edit","install","input","lock","source",{"skillNo":165,"name":166,"nameZh":6,"description":167,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":168,"categories":169,"keywords":174,"publishedAt":38},"01M6JFCQC7H65M9QJ6TRE71BS1","vercel-deployment","Deploy static sites and frontends to Vercel — handles both CLI and REST API paths, including the CLI token sanitization workaround.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Fvercel-deployment\u002FSKILL.md",[170,173],{"categoryNo":171,"categoryName":172,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000011","运维与部署",{"categoryNo":83,"categoryName":84,"taxonomyType":77,"taxonomyTypeDesc":78},[175,176,177,178,179,180,181,182,183,184,185,186,187,18,188,189,190,191,192,193],"deployment","vercel deployment","vercel","macos","cli","linux","windows","deploy","vercel deploy","REST","api","site","deploy to vercel","rest api","host","sites","paths","sanitization","static site",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":198,"categories":199,"keywords":201,"publishedAt":38},"01M6JFCM4SMTXBM5A01BK2YQG1","software-quality-workflows","Umbrella workflow for TDD, debugging, code simplification, spikes, pre-commit review, and debugger-assisted investigation.","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Fsoftware-quality-workflows\u002FSKILL.md",[200],{"categoryNo":83,"categoryName":84,"taxonomyType":77,"taxonomyTypeDesc":78},[202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,23],"workflows","quality","software","software quality workflows","review","tdd","workflow","commit","debugging","code","debugger","pre-commit","investigation","code simplification","user","simplification",{"skillNo":219,"name":220,"nameZh":6,"description":221,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":222,"categories":223,"keywords":231,"publishedAt":38},"01M6JFCGD0M6CEATY01W7YN6DB","react-component-refactoring","Safely refactor large React components into smaller, maintainable pieces using proven patterns","https:\u002F\u002Fgithub.com\u002FS3YED\u002Fappie-kit\u002Fblob\u002Fmaster\u002Fskills\u002Fsoftware-development\u002Freact-component-refactoring\u002FSKILL.md",[224,227,230],{"categoryNo":225,"categoryName":226,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000007","代码审查",{"categoryNo":228,"categoryName":229,"taxonomyType":77,"taxonomyTypeDesc":78},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":83,"categoryName":84,"taxonomyType":77,"taxonomyTypeDesc":78},[232,233,234,235,236,237,238,239,178,30,240,125,241,181,242,211,243,244,245,246],"react","component","refactoring","component refactoring","react component","react component refactoring","frontend","writing","typescript","react components","modular","refactor","simplify","patterns","test-driven-development"]