Portfolio — vitalik.eth on mainnet
Four ERC-20s × three reads each (symbol, decimals,
balanceOf) for vitalik.eth on Ethereum mainnet, batched
into a single eth_call via Multicall3. Twelve reads, one
roundtrip.
Holdervitalik.eth
The code
import "./demo.css"
import { eip155_1 } from "@ethernauta/chain/eip155-1"
import { AddressSchema, Uint256Schema } from "@ethernauta/core"
import {
balanceOf,
decimals,
symbol,
} from "@ethernauta/erc/20"
import {
contract,
create_multicall,
encode_chain_id,
http,
} from "@ethernauta/transport"
import { hex_to_number } from "@ethernauta/utils"
import { useCallback, useEffect, useState } from "react"
import {
bigint,
type InferOutput,
number,
object,
parse,
string,
tuple,
} from "valibot"
import { Button } from "../../components/button"
const MAINNET_CHAIN_ID = encode_chain_id({
namespace: "eip155",
reference: eip155_1.chainId,
})
// vitalik.eth — chosen because every reader recognises the
// balances, and the address has been around long enough that
// the major ERC-20s have non-zero holdings there.
const OWNER = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
const TOKENS = [
{
symbol: "USDC",
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
},
{
symbol: "DAI",
address: "0x6B175474E89094C44Da98b954EedeAC495271d0F",
},
{
symbol: "WETH",
address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
},
{
symbol: "UNI",
address: "0x1f9840a85d5aF5bf1D1762F925BdAdDC4201F984",
},
] as const
const multicall = create_multicall([
{
chainId: MAINNET_CHAIN_ID,
transports: [
http("https://ethereum-rpc.publicnode.com"),
],
},
])
const HoldingSchema = object({
symbol: string(),
decimals: number(),
balance: bigint(),
})
type Holding = InferOutput<typeof HoldingSchema>
// Per-token slice: [symbol(), decimals(), balanceOf({account})]
const TokenCallResultsSchema = tuple([
string(),
Uint256Schema,
Uint256Schema,
])
export function PortfolioDemo() {
const [holdings, set_holdings] = useState<
Holding[] | null
>(null)
const [loading, set_loading] = useState(false)
const [error, set_error] = useState<string | null>(null)
const [elapsed_ms, set_elapsed_ms] = useState<
number | null
>(null)
const run = useCallback(async () => {
set_loading(true)
set_error(null)
try {
const owner = parse(AddressSchema, OWNER)
const calls = TOKENS.flatMap((t) => {
const ctx = contract({
chain_id: MAINNET_CHAIN_ID,
to: parse(AddressSchema, t.address),
})
return [
symbol()(ctx),
decimals()(ctx),
balanceOf({ account: owner })(ctx),
]
})
const start = performance.now()
const results = await multicall(calls)
set_elapsed_ms(Math.round(performance.now() - start))
const next: Holding[] = TOKENS.map((_, i) => {
const [sym, dec_hex, bal_hex] = parse(
TokenCallResultsSchema,
results.slice(i * 3, i * 3 + 3),
)
return parse(HoldingSchema, {
symbol: sym,
decimals: hex_to_number(dec_hex),
balance: BigInt(bal_hex),
})
})
set_holdings(next)
} catch (e) {
set_error(
e instanceof Error ? e.message : "Unknown error",
)
} finally {
set_loading(false)
}
}, [])
useEffect(() => {
run()
}, [run])
return (
<div className="portfolio-root">
<div className="portfolio-card">
<div className="portfolio-header">
<span>Holder</span>
<span className="portfolio-header-value">
vitalik.eth
</span>
</div>
{loading && (
<p className="portfolio-loading">Loading…</p>
)}
{error && (
<p className="portfolio-error">{error}</p>
)}
{holdings?.map((h) => (
<div key={h.symbol} className="portfolio-row">
<span className="portfolio-row-label">
{h.symbol}
</span>
<span className="portfolio-row-value">
{format(h.balance, h.decimals)}
</span>
</div>
))}
{elapsed_ms !== null && (
<div className="portfolio-footer">
<span className="portfolio-row-label">
Roundtrip
</span>
<span className="portfolio-row-value">
{elapsed_ms} ms · {TOKENS.length * 3} reads ·
1 RPC call
</span>
</div>
)}
</div>
<Button onClick={run} disabled={loading}>
{loading ? "Running…" : "Re-run multicall"}
</Button>
</div>
)
}
function format(raw: bigint, decimals: number): string {
const base = 10n ** BigInt(decimals)
const whole = raw / base
const fraction = raw % base
const fraction_str = fraction
.toString()
.padStart(decimals, "0")
.slice(0, 4)
return `${whole.toLocaleString()}.${fraction_str}`
}