EVM Token Canonicalizer - deterministic, schema-validated normalization of messy EVM token data (OKX.AI A2MCP service)
Project description
evm-canon — deterministic EVM data utilities (OKX.AI A2MCP service)
Turns messy EVM token / on-chain value data into strict, schema-validated JSON. Sold to other agents as a pay-per-call A2MCP service on OKX.AI.
Three services behind one x402-gated endpoint (evm_canon/server.py):
| Route | What | Price |
|---|---|---|
POST /canonicalize |
token/value canonicalization (below) | 0.002 |
POST /decode |
calldata → typed function args + deterministic risk flags (evm_canon/decoder.py, pinned sigdb@2026-07-10) |
0.003 |
POST /resolve |
ENS forward/reverse with forward-verification (evm_canon/ens.py, RPC failover) |
0.001 |
The promise (this is the marketplace listing, verbatim): schema-validated, deterministic core, honest nulls.
- Every response is either a schema-valid
{result, report}or a typed error — never a best-effort blob. - Same input + same pinned
registry_version→ byte-identical output. - Any underivable field is
nulland listed inreport.fields_null. - No IEEE-754 floats anywhere near amounts or billing (enforced by
tests/test_precision.py::test_no_float_in_amount_source_paths).
Why Python
The brief allowed TypeScript or Python. Python wins here on three counts:
decimal.Decimal+ native bigints.Decimal.scalebshifts exponents without dividing, so raw↔human conversion is exact by construction — there is no precision context to misconfigure and no float to sneak in. In TS the equivalent needs a third-party big-decimal library and discipline aroundJSON.parse(which silently floats large numbers).eth_utilsprovides audited keccak-based EIP-55 checksumming without pulling in a full web3 client.- Boring and auditable. The whole deterministic core is stdlib + two small libs; the dependency surface an OKX.AI caller has to trust is tiny.
The one thing viem/ethers would buy us — on-chain decimals() — is a single
eth_call with selector 0x313ce567, done here with urllib (opt-in only,
via hints.prefer: "onchain" + an EVM_CANON_RPC_<chainId> env var).
Install & run
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
# canonicalize one payload (stdin or -i file)
echo '{"raw":{"symbol":"USDC","chain":"arbitrum","amount":"1500000"}}' \
| evm-canon canonicalize --pretty
evm-canon schema # default output JSON Schema
evm-canon version # package + pinned registry version
pytest # full suite incl. idempotency + precision gates
Exit codes: 0 schema-valid result, 1 typed error, 2 malformed invocation.
Non-pretty output is canonical JSON (sorted keys, fixed separators) so callers
can assert byte-identity.
Library
from evm_canon import canonicalize
out = canonicalize({
"raw": {"token": "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
"chain": "arb", "amount": "1500000", "time": 1752062400},
"target_schema": None, # optional caller schema
"hints": {"chain": "arbitrum", "prefer": "registry"},
})
# -> {"result": {...}, "report": {...}} or {"error": {"code": ...}}
An LLM may be injected only for the ambiguous-ticker branch
(canonicalize(payload, llm=picker)); its pick is re-validated against the
registry candidate set and discarded if it names anything outside it
(evm_canon/llm.py). By default no LLM is wired and ambiguity returns a typed
TICKER_AMBIGUOUS error carrying the full candidate set.
Contracts
Input: {"raw": {...dirty fields...}, "target_schema": {...optional...}, "hints": {"chain": ..., "prefer": "registry|onchain"}}.
Output: see evm_canon/data/default_schema.json. Typed error codes:
INVALID_ADDRESS, UNKNOWN_CHAIN, TICKER_UNRESOLVED, TICKER_AMBIGUOUS,
DECIMALS_UNKNOWN, BAD_TIMESTAMP, SCHEMA_VALIDATION_FAILED — returned as
{"error": {"code", "field", "detail", "candidates"?}}, never thrown at the caller.
Documented deterministic choices (assumptions stated once, here)
- A bare JSON integer amount is treated as raw (smallest units); a decimal
string is human. A human amount with more fractional digits than the
token's
decimalsis not representable → honest null, noted in the report. amount_humanis the exact value with trailing zeros trimmed (1500000@ 6 decimals →"1.5"), which keeps output canonical.- Timestamp magnitude rule:
0 < v < 1e11→ unix seconds;1e12 ≤ v < 1e14→ unix millis (flagged inferred); in between / beyond → ambiguous → null. Naive ISO strings are assumed UTC and flagged inferred. Relative timestamps ("2 hours ago") depend on now and are rejected asBAD_TIMESTAMP— determinism beats convenience. chainIdis the source of truth when both a chainId and a chain alias are present.hints.chainis only consulted whenrawcarries no chain.- When a provided address is a canonical registry contract, registry metadata
overrides a contradicting raw symbol (noted in
report.notes). When the address is unknown but the symbol is canonical for that chain →scam_suspected: trueand the caller's address is preserved, never "fixed". - Confidence is a deterministic formula, not a vibe: base by provenance (registry 0.99 / onchain 0.95 / heuristic 0.70), −0.02 per null field, −0.30 if scam suspected, clamped to [0.05, 0.99].
Registry: refresh + re-pin procedure
The snapshot evm_canon/data/registry-tokenlists@2026-07-01.json (Uniswap-style
token list + ethereum-lists/chains, curated to 8 chains) is pinned by
PINNED_VERSION in evm_canon/registry.py and surfaced in every report.
To bump — a deliberate release action, never automatic:
python scripts/refresh_registry.py --date 2026-08-01
# 1. hand-review the diff vs the previous snapshot (decimals changes and
# added/removed tokens are reputation-relevant)
# 2. bump PINNED_VERSION in evm_canon/registry.py
# 3. bump metadata.registry_version in SKILL.md
# 4. pytest && release a new package version
Go-live on OKX.AI (A2MCP)
scripts/go_live.sh scripts the scriptable parts; the wallet OTP and listing
publication are interactive by design (keys stay in the TEE).
npx skills add okx/onchainos-skills- Create the Agentic Wallet: tell your agent "Log in to Agentic Wallet with email" → enter email + OTP. Private keys live in the TEE, never in the model.
npx skills add https://github.com/okx/onchainos-skills --skill okx-ai-guide- Register the on-chain identity with role
asp(ERC-8004 on X Layer); set avatar + service metadata. - Integrate the OKX Payment SDK — required before A2MCP goes live. The
seam is
evm_canon/payment.py(A2MCPBilling.charge); theTODO(go-live)block marks exactly where live credentials + wallet attach. Pricing is int micro-units of USDG/USDT (default 2000 µ = 0.002 per record). - Publish the listing with the promise: schema-validated, deterministic core, honest nulls. Fund the wallet for gas (X Layer is gas-free).
Layout
SKILL.md Onchain OS skill file (contracts + pipeline)
evm_canon/
detect.py stage 1: classify dirty fields (pure)
resolve.py stage 2: address/chain/decimals/amount/timestamp (exact math)
registry.py pinned snapshot loader + lookups
llm.py the ONLY LLM seam (ambiguous ticker, re-validated)
pipeline.py orchestrator + report/confidence
validate.py stage 3: JSON Schema gate + canonical serializer
payment.py A2MCP billing stub (int micro-units, TODO(go-live))
cli.py evm-canon CLI
data/ pinned registry snapshot + default schema
scripts/refresh_registry.py refresh + re-pin procedure
scripts/go_live.sh scripted go-live steps
tests/ 79 tests: per-stage units, scam-double,
cross-/same-chain ambiguity, idempotency,
uint256 precision, no-float source grep
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file evm_canon-0.2.0.tar.gz.
File metadata
- Download URL: evm_canon-0.2.0.tar.gz
- Upload date:
- Size: 38.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cbe95168309931a9d20faa7f821429fe8a2f74061235b582a347475c1ef4a562
|
|
| MD5 |
a494d066ad9c1cd2bf7987acff28b6c7
|
|
| BLAKE2b-256 |
99b706e83bbc49333356869d50843bbd425252d9aeee0bfba2b17361e81fdf46
|
File details
Details for the file evm_canon-0.2.0-py3-none-any.whl.
File metadata
- Download URL: evm_canon-0.2.0-py3-none-any.whl
- Upload date:
- Size: 31.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d1af3529a88b2066a6d4f149793400caeb47830ebb83c6307b91503aaea6cb4
|
|
| MD5 |
c36d3ac34a91b19032b9550441e84929
|
|
| BLAKE2b-256 |
ce8bf090c2e9df4c690931ca7a008ba1d3e6ab3da9c647d8f43a6d767dd1bae0
|