Altana Documentation Audit
Altana's docs (docs.altana.network, for @altananetwork/sdk and @altananetwork/mcp) are unusually agent-ready — llms.txt, llms-full.txt, and a downloadable skill.md all exist and are current — but the release history diverges from npm, the flagship GitHub README example commits the exact decimals mistake the docs warn about, one payments page documents an API surface that matches nothing else on the site, and the single most dangerous default (omit calls → unrestricted session) lives in a closing bullet note instead of a warning box.
1. Changelog claims to track npm but omits published versions (significant)
Location: https://docs.altana.network/changelog
Problem: The changelog opens with "These docs describe @altananetwork/sdk 0.7.0 and @altananetwork/mcp 0.7.0, the current releases on npm" and then lists a release history that doesn't reconcile with npm. The npm registry shows SDK versions 0.3.2, 0.3.3, 0.4.0, 0.5.0, 0.5.1, 0.6.0, 0.7.0 and mcp versions 0.2.3, 0.3.0, 0.4.0, 0.4.1, 0.5.0, 0.6.0, 0.7.0. The changelog has no entry for SDK 0.5.1, never mentions mcp 0.4.1 or 0.6.0 (its mapping jumps 0.6.0→mcp 0.5.0, then 0.7.0→mcp 0.7.0), and calls 0.3.3 the "First public release" even though 0.3.2 is publicly installable from npm.
Consequence: The docs themselves say "Both packages are pre-1.0. Minor versions may contain breaking changes. Pin an exact version if you need stability." A developer pinned to 0.5.0 who sees 0.5.1 on npm has no way to learn what changed before upgrading — the document that exists specifically to answer that question skips the version. Agents reconciling installed versions against the changelog hit versions the changelog has never heard of.
The fix: Add entries (even one-line ones) for every version published to npm — SDK 0.5.1, mcp 0.4.1, and mcp 0.6.0 — and either document 0.3.2 or unpublish/deprecate it so "first public release" is true.
2. GitHub README quick start commits the decimals footgun the docs warn about (significant)
Location: https://github.com/altananetwork/altana-sdk (README "Quick start" → "Grant a scoped session", linked from the docs changelog and MCP pages as the canonical repo)
Problem: The grantSession warning box on https://docs.altana.network/sdk/grant-session says: "USDT and USDC use 18 decimals on BNB Chain and 6 on Ethereum. Writing 100_000_000n for '100 USDT' on BNB sets a cap of 0.0000000001 USDT, and the agent's payments revert against a limit that looks generous." The README's quick start creates a BNB client — const client = createClient({ chains: [BNB] }); — and its "Grant a scoped session" example then grants exactly that pattern on it: spend: [{ limit: 100_000_000n, period: "day", token: "0xUSDC..." }], alongside calls: [{ to: "0xUniswapRouter..." }] (an Ethereum-ecosystem router placeholder on the BNB client). Re-verified against the live README during this audit.
Consequence: The repo README is the first thing most developers and coding agents read. Anyone who copies its quick start onto the SDK's own default chain gets a spend cap ten orders of magnitude too small, and per the docs' Errors page the failure surfaces as a bare { status: "FAILED" } with "No reason, no receipt, no transactionHash" — the docs' own failure table even calls this case "Extremely common on BNB Chain."
The fix: Make the README example internally consistent: either use an Ethereum client with the 6-decimal limit, or keep the BNB client and use an 18-decimal limit with a BNB-native router (e.g. PancakeSwap), and repeat the decimals warning next to the snippet.
3. ERC-8183 page documents an API shape that exists nowhere else, with undeclared variables (significant)
Location: https://docs.altana.network/sdk/erc8183
Problem: Every other SDK page uses the client.* method style (client.execute({...}), client.grantSession({...}) with a single options object). This page alone switches to standalone positional functions — hireErc8183Agent(wallet, signer, {...}, { network: BNB }) and settleErc8183Job(wallet, signer, { jobId }, { network: BNB }) — and its final snippet references variables never defined on the page: await settleErc8183Job(wallet, signer, { jobId, action: "dispute" }, opts) (no opts anywhere) and await execute(wallet, signer, buildClaimRefundCall(56, jobId), opts), calling a bare positional execute that is never imported and whose documented form (client.execute) takes one options object, not four positional arguments.
Consequence: A developer can't copy any of the settle/dispute/refund snippets and run them. Worse for coding agents: given two conflicting call conventions for the same SDK, an agent will confidently generate a hybrid that type-errors — precisely what the docs' own Claude Skill page promises to prevent ("correct function signatures, the right API surface, no hallucinated methods").
The fix: Rewrite the page in the same client.* convention as the rest of the SDK reference (or explicitly document that ERC-8183 helpers are standalone exports with their full signatures), define opts in every snippet, and show the real import list for execute/buildClaimRefundCall.
4. Unrestricted-session default is buried in a closing bullet note (significant)
Location: https://docs.altana.network/sdk/grant-session (Notes section)
Problem: The most dangerous default in the product — "permissions.calls omitted = unrestricted. Always set both calls and spend unless you specifically want an open-scope session" — appears only as the last bullet in the page's Notes section. Meanwhile a lower-stakes issue (token decimals) gets a full red :::warning box higher up on the same page. The use-case walkthroughs reviewed for this audit (the private-key hello world, the DEX-trading guide, and the multi-agent portfolio guide) all pass calls without ever mentioning what happens if it is omitted.
Consequence: This is an authorization product whose pitch is "the agent can only call the contracts you allow." A developer (or an agent assembling permissions from partial examples) who passes only spend silently grants an AI agent the right to call any contract up to the cap — the opposite of the documented mental model, with no error and nothing visibly wrong at grant time.
The fix: Promote the omitted-calls behavior to a :::warning box on grantSession, and state it inline in the permission-shape reference where calls is optional.
5. No error contract: docs instruct developers to branch on message strings in a pre-1.0 SDK (significant)
Location: https://docs.altana.network/sdk/errors
Problem: The Errors page states: "There is no error class and no error code: every one of these is a plain Error, so match on the message if you must branch on them." The same docs' changelog page warns "Minor versions may contain breaking changes." Relay-side failures are even less inspectable: "The SDK returns { status: \"FAILED\" } and nothing else. There is no revert string, no error code, and no receipt to inspect. Diagnosis is by elimination" — the documented remedy is to manually search the wallet address on BscScan/Etherscan and read the trace.
Consequence: Every programmatic error-handling path a developer builds is string-matching against prose that carries no stability guarantee, in a package family that explicitly reserves the right to break in minor versions. Autonomous agents — the SDK's stated audience — cannot triage a FAILED result at all without leaving the SDK for a block explorer.
The fix: Introduce stable error codes or error classes and document them as a contract; at minimum, commit in the Errors page to message-string stability across minors, and surface the relay's failure reason (or the userOp hash) in ExecuteResult so FAILED is diagnosable in code.
6. Use-case overview lists Base as an x402 chain while the networks page says the SDK cannot execute there (minor)
Location: https://docs.altana.network/use-cases (overview table) vs https://docs.altana.network/concepts/networks
Problem: The overview table's row for "Agent pays for an API with x402" gives the chain as "BNB / Base". The Networks page says the opposite about Base: "Base is a verification target, not an execution chain. It hosts a KeyStore cache and no relay, so BASE cannot be passed to createClient and you cannot send transactions there through the SDK." The x402 walkthrough itself only ever shows BNB (createClient({ chains: [BNB] })), and fetchWithX402's chainId option defaults to the client's chain.
Consequence: A developer whose paid API settles on Base reads the overview, assumes first-class support, and only discovers on the networks page that BASE is rejected by createClient. It's unclear from the docs whether a Base-settled 402 challenge is payable at all (the EIP-3009 rail names "Base/Ethereum USDC" as compatible), and nothing resolves the tension.
The fix: Either change the overview cell to the chains the walkthrough actually supports, or add a note to the x402 page explaining exactly how (or whether) a Base-settled payment option can be selected and signed when Base cannot be a client chain.
7. Error table references a networks parameter the rest of the reference never uses (minor)
Location: https://docs.altana.network/sdk/errors (Configuration table)
Problem: The configuration-errors table lists createWallet: at least one network is required. with the cause "Empty networks. Also applies to createPasskeyWallet." No other captured page uses a networks parameter: every snippet across the reference configures createClient({ chains: [...] }), and the per-call selector is uniformly chainId (documented in the grantSession, execute, balances, and revokeSession parameter blocks). The networks name appears exactly once — inside this error message.
Consequence: A developer who hits this error searches the docs for networks and finds nothing to fix; an agent may hallucinate a networks option on createWallet because the error table implies one exists.
The fix: Align the error message and its documented cause with the rest of the API — say chains (and point at createClient) — or document wherever networks actually surfaces.
8. Audit report exists only on a third-party page that blocks automated access (minor)
Location: https://docs.altana.network/security/audits
Problem: The page says the CertiK audit's "full report, the finding-by-finding detail and the current status of every item are published on CertiK Skynet" — the sole link for the report. That URL (skynet.certik.com/projects/altana) returned HTTP 403 to a plain programmatic fetch during this audit (possibly bot protection rather than a dead page), and the docs host no copy, summary of findings, or PDF themselves.
Consequence: Anyone doing automated due diligence — including the AI agents these docs explicitly court with llms-full.txt — cannot retrieve the audit findings; if the Skynet listing ever moves, the docs' only evidence for the "audited by CertiK" claim goes with it.
The fix: Host the audit report PDF (or a findings summary table) on docs.altana.network alongside the existing scope description, keeping the Skynet link as the live-status supplement.
What they do well
- Best-in-class agent readiness: llms.txt, a complete 188 KB llms-full.txt, a downloadable skill.md, and MCP install docs for Claude Code, Cursor, and Codex — with page banners pointing LLMs at the machine-readable files.
- Honest failure-mode documentation: the
PENDING-is-ambiguous warning, the stale-L2-cache revocation footgun (ensureKeyCached"will not do this for you"), and thegetKeysvsisValidKeyexpiry trap are all called out explicitly instead of hidden. - Concrete, verifiable reference data: full contract address tables per network (mainnet and testnet) with a pointer to
config.tsin the repo as source of truth, plus explorer links to verified source.
Top 3 recommendations
- Reconcile the changelog with npm — add the missing 0.5.1/0.4.1/0.6.0 entries — and fix the README quick start so the repo's first example doesn't trigger the decimals footgun the docs warn about.
- Rewrite the ERC-8183 page in the same API convention as the rest of the SDK reference, with complete, runnable snippets.
- Promote the "omitted
calls= unrestricted session" note to a warning box and introduce stable error codes so failures are diagnosable in code.