@pulsadev/erc20-utils
v0.1.0
Published
Zero-dependency ERC-20 token utilities — read balances, allowances, metadata, and build transfer/approve calldata with raw RPC
Downloads
129
Readme
@pulsadev/erc20-utils
Zero-dependency ERC-20 token utilities for TypeScript. Read balances, allowances, metadata, and build transfer/approve calldata using raw JSON-RPC — no ethers, no viem, no web3.js.
Features
- Zero dependencies — pure TypeScript, ~12KB bundle
- Read token data — balanceOf, allowance, name, symbol, decimals, totalSupply
- Build calldata — transfer, approve, transferFrom, maxApprove, revoke
- Format utilities — formatUnits, parseUnits with arbitrary decimals
- Well-known tokens — USDC, USDT, DAI, WETH, WBTC addresses across 7 chains
- Works everywhere — ESM + CJS, Node.js 18+, Bun, Deno, browsers
Install
npm install @pulsadev/erc20-utilsQuick Start
import { getTokenBalance, getTokenMetadata, buildTransferCalldata } from '@pulsadev/erc20-utils'
const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
const opts = { rpcUrl: 'https://ethereum-rpc.publicnode.com' }
// Read token metadata
const meta = await getTokenMetadata(USDC, opts)
// { address: '0xA0b...', name: 'USD Coin', symbol: 'USDC', decimals: 6 }
// Read balance
const balance = await getTokenBalance(USDC, '0xYourAddress...', opts)
// { balance: 5000000n, decimals: 6, formatted: '5' }
// Build transfer calldata
const tx = buildTransferCalldata({
token: USDC,
to: '0xRecipient...',
amount: 1000000n, // 1 USDC
})
// { to: '0xA0b...', data: '0xa9059cbb...', value: 0n }API
Reading Token Data
// Individual queries
const name = await getName(token, opts) // 'USD Coin'
const symbol = await getSymbol(token, opts) // 'USDC'
const decimals = await getDecimals(token, opts) // 6
const supply = await getTotalSupply(token, opts) // 30000000000000n
// Balance & allowance
const balance = await getBalanceOf(token, owner, opts)
const allowed = await getAllowance(token, owner, spender, opts)
// Rich objects with formatted values
const meta = await getTokenMetadata(token, opts)
const bal = await getTokenBalance(token, owner, opts)
const allow = await getTokenAllowance(token, owner, spender, opts)
// Batch
const balances = await getMultipleBalances([USDC, DAI, WETH], owner, opts)Building Calldata
import {
buildTransferCalldata,
buildApproveCalldata,
buildTransferFromCalldata,
buildMaxApproveCalldata,
buildRevokeCalldata,
MAX_UINT256,
} from '@pulsadev/erc20-utils'
// Transfer tokens
const tx = buildTransferCalldata({ token, to, amount })
// Approve spender
const approve = buildApproveCalldata({ token, spender, amount })
// Max approve (type(uint256).max)
const maxApprove = buildMaxApproveCalldata(token, spender)
// Revoke approval
const revoke = buildRevokeCalldata(token, spender)
// Transfer on behalf (requires prior approval)
const transferFrom = buildTransferFromCalldata({ token, from, to, amount })Format Utilities
import { formatUnits, parseUnits } from '@pulsadev/erc20-utils'
formatUnits(1000000n, 6) // '1'
formatUnits(1500000n, 6) // '1.5'
parseUnits('1.5', 6) // 1500000n
parseUnits('100', 18) // 100000000000000000000nWell-Known Tokens
import { getTokenAddress, getTokenByAddress, WELL_KNOWN_TOKENS } from '@pulsadev/erc20-utils'
getTokenAddress('USDC', 1) // '0xA0b86991...' (Ethereum)
getTokenAddress('USDC', 42161) // '0xaf88d065...' (Arbitrum)
getTokenAddress('USDC', 99999) // null
getTokenByAddress('0xA0b86991...', 1) // { symbol: 'USDC', decimals: 6, ... }Supported chains: Ethereum (1), Optimism (10), Polygon (137), Arbitrum (42161), Base (8453), BSC (56).
Why Not ethers/viem?
| | @pulsadev/erc20-utils | ethers.js | viem | |---|---|---|---| | Bundle size | ~12KB | ~114KB | ~40KB | | Dependencies | 0 | 0 | 3 | | ERC20 focused | Yes | General | General | | Calldata builder | Built-in | Manual ABI | Manual ABI | | Token registry | Built-in | No | No |
If you only need ERC20 interactions, this package gives you everything without pulling in a full Ethereum library.
License
MIT
