Altana's docs (docs.altana.network) are agent-first and unusually complete for a young SDK — llms.txt/llms-full.txt, an MCP server, a downloadable Claude skill, contract addresses in tables — but the surface contradicts itself in exactly the places that matter for a security product: revocation semantics, what writes to the Keystore, how many MCP tools exist, and a "source of truth" repo that 404s.
1. Revocation semantics contradict each other across pages (critical)
Location: /sdk/revoke-session vs /sdk/sync-to-l2
Problem:/sdk/revoke-session states: "Effect is global and immediate. No off-chain coordination required." and "After the userOp confirms, the session is dead everywhere simultaneously." But /sdk/sync-to-l2 says the opposite for the cross-chain path: "Revocations on L1 do not propagate automatically; until someone submits a post-revocation proof, the L2 cache still reports the key as valid. Call syncKeyToL2 right after revokeSession to push the revocation through." The same sync-to-l2 page also opens with the unqualified claim "A session you granted via grantSession is registered in the Keystore on L1 (Ethereum)" — even though the SDK default is BNB Smart Chain, which /concepts/keystore describes as a "Standalone Keystore."
Consequence: This is the single most safety-critical behavior in the product — cutting off a misbehaving agent. A developer who reads only the revokeSession page (or an AI agent that retrieved just that chunk) will revoke a key and reasonably believe the agent is dead "everywhere simultaneously," while any counterparty verifying against the Base cache still sees isValidKey == true until a proof lands. That window is exactly when a compromised session key does damage. Meanwhile a developer on the default BNB chain is told, unqualified, that their session lives on Ethereum.
The fix: Add the L2-cache caveat directly to /sdk/revoke-session ("Immediate on the chain where the key is registered; L2 caches report the old state until a post-revocation proof is submitted — see syncKeyToL2"), scope the "dead everywhere simultaneously" claim to the registering chain, and qualify the sync-to-l2 opener ("a session granted on Ethereum…").
2. SDK reference table says createWallet writes to the Keystore; three other pages say it doesn't (significant)
Location: /sdk (Wallets table) vs /sdk/create-wallet and /concepts/keystore
Problem: The /sdk overview table describes createWallet as "Create a wallet from a private key signer and register it in the Keystore." The page directly contradicts this: "The wallet is counterfactual… it isn't a smart account onchain until the first execute. That first execute is what registers the admin key in Keystore." The Keystore concept page's write table agrees: " | No | Wallet is counterfactual until first ."
Consequence: Registration timing is load-bearing here. Per /sdk/create-wallet, developers must "Fund result.address with native tokens before calling execute — the wallet is counterfactual and has no balance until you send some," and per /sdk/grant-session, Keystore registration is what makes authority "provable to anyone" via readers like verify_authorization. A developer or coding agent trusting the reference table will assume the wallet is discoverable in the Keystore right after createWallet and build verification or onboarding flows against onchain state that doesn't exist yet.
The fix: Change the /sdk table row to "Create a counterfactual smart-account wallet for a signer; the admin key is registered in Keystore on the first execute."
3. MCP docs disagree on how many tools exist — 11 vs 17 — and the "every tool has a slash command" claim is false (significant)
Location: /mcp vs /mcp/tools; also /use-cases (overview table)
Problem:/mcp says the server provides "11 tools covering wallet creation, balance, verification, session lifecycle, and transactions" and "12 prompts exposed as slash commands." /mcp/tools says "The Altana MCP server exposes 17 tools" and enumerates 17 (including x402_request, erc8183_create_job, erc8183_job_status, erc8183_settle, search_skills, get_skill). The same page then claims "Every tool has a matching prompt, exposed as a slash command" above a table listing only 12 commands — none of the x402, ERC-8183, or skills tools appear. The use-cases overview table separately references an x402-request MCP command that exists nowhere in the slash-command table.
Consequence: Humans shrug at a stale count; AI hosts and agents don't. An agent planning against /mcp will conclude payment and skills tooling doesn't exist; one told "every tool has a slash command" will try /altana-agentic-wallet:x402-request and fail. For an MCP server whose primary consumers are literally AI hosts, the tool inventory is the contract.
The fix: Update /mcp to "17 tools," regenerate the counts from the server manifest, and either add the five missing slash commands to the table or delete the "every tool has a matching prompt" sentence.
4. The docs' declared "source of truth" — the SDK GitHub repo — returns 404 (significant)
Problem:/mcp/skill links "The full skill content is at packages/wallet/SKILL.md in the SDK repo" → github.com/altananetwork/sdk/blob/main/packages/wallet/SKILL.md, which returns HTTP 404, as does github.com/altananetwork/sdk itself (verified with and without a browser user agent). /concepts/networks tells readers "Addresses are the source of truth in the Keystore repo's deployment manifests (deployments/*.json) and the SDK's packages/wallet/src/config.ts" — neither repo is publicly reachable, and no Keystore repo link is given anywhere. The npm package @altananetwork/sdk also declares repository: github.com/altananetwork/sdk.git.
Consequence: For a product whose pitch is "verifiable by anyone," the canonical place developers are told to verify contract addresses and read the skill source is a dead end. Anyone auditing the deployed addresses against the "deployment manifests" can't; anyone following the SKILL.md link gets a 404 from a docs page.
The fix: Either make the SDK repo public, or repoint these references at accessible artifacts (the published npm tarball, docs.altana.network/skill.md, and the explorer-verified sources already linked from /security/audits).
5. grantSession example comments "100 USDC (6 decimals)" on a BNB client — the docs' own Skills page drills "18 decimals on BNB Chain" (significant)
Location: /sdk/grant-session vs /skills
Problem: The flagship /sdk/grant-session example runs on createClient({ chains: [BNB] }) and sets limit: 100_000_000n, // 100 USDC (6 decimals). Altana's own /skills page names this exact trap as the canonical agent mistake: "USDT on BNB Chain has 18 decimals, not 6 like Ethereum. $20 is 20n * 10n**18n" — a fact the page says "an agent cannot infer" — and its own BNB session example uses limit: 50n * 10n ** 18n // 50 USDT. Note: 18 decimals on BNB Chain. The reference page and the skills page model opposite decimal conventions for a stablecoin spend cap on the same chain.
Consequence: A developer or agent who copies the grantSession example onto BNB with a real BNB-chain stablecoin risks setting a spend cap orders of magnitude smaller than intended — agent payments revert and they debug a "broken" session. The docs elsewhere invest an entire section in warning about precisely this decimals trap, then plant it in the primary reference example.
The fix: Make the reference example chain-consistent: use an 18-decimal amount with a BNB-chain token comment (as the /skills example does), or switch the example to Ethereum where a 6-decimals USDC comment is conventionally correct.
6. No error reference anywhere — failure is a three-value enum (significant)
Problem: The entire documented failure surface of the SDK is status: "CONFIRMED" | "FAILED" | "PENDING" on ExecuteResult, plus scattered prose ("reverts at validation", "Empty calls is rejected"). There is no error-code reference, no relay error documentation, no troubleshooting page; llms.txt lists no errors/troubleshooting page and /changelog returns 404.
Consequence: The product's core promise is that out-of-policy calls "revert at the onchain validator." A developer whose execute returns FAILED cannot distinguish a policy violation (over cap, wrong contract, expired session) from a byte-exactness mismatch ("Sloppy JSON round-trips… break the match"), an unfunded counterfactual wallet, or a relay problem — the most common first-week failures the docs themselves describe, none of which are mapped to an observable error.
The fix: Add an error reference: what FAILED looks like per failure class (policy revert vs validation mismatch vs insufficient funds vs relay rejection), what the thrown SDK errors are, and how to introspect a reverted userOp.
7. The byte-exact session hash includes a role field the Session type doesn't have (minor)
Location: /concepts/sessions, /sdk/execute
Problem: /sdk/execute and /concepts/sessions both warn "The onchain validator matches permissions + expiry + role + publicKey exactly to the hash committed at grant," but the documented Session type is { walletAddress, signer, publicKey, permissions, expiry } — no role. role appears nowhere else in the docs.
Consequence: Developers are told to persist the session "byte-exact" or execution reverts, then shown a type that omits one of the four hashed fields. Anyone serializing the documented shape has no way to know whether they're preserving role or what it even is.
The fix: Either add role to the Session type documentation (with its values) or remove it from the byte-exact warning if it's internal to the signer.
8. Getting-started flow depends on an underscore-private property, signer._privateKey (minor)
Problem: /getting-started/create-agentic-wallet instructs users to persist their only admin credential via console.log("Save this key:", signer._privateKey), with a callout: "Copy the value printed for signer._privateKey. The SDK does not store it anywhere."
Consequence: The onboarding path's key-backup step hangs off an underscore-prefixed property — conventionally private API with no stability guarantee. If a future SDK version renames it, every tutorial-follower's backup instruction silently logs undefined for the credential that controls their funds.
The fix: Export a public accessor (e.g. signer.privateKey or exportPrivateKey(signer)) and document that; reserve underscore fields for internals.
9. No changelog or version compatibility notes for a pre-1.0 SDK (minor)
Location: site-wide; /changelog (404)
Problem:@altananetwork/sdk and @altananetwork/mcp are at 0.7.0 (npm), i.e. pre-1.0 with no semver stability promise, yet the docs have no changelog (/changelog 404s, llms.txt lists none), no version banner, and no migration notes. The docs also pin behavior claims to "the current SDK" ("The current SDK supports wallet execution on BNB and Ethereum… additional L2 execution support will be added as it ships") with no dated record of what changed when.
Consequence: Developers (and the AI agents the docs explicitly court via llms-full.txt) cannot tell whether a page describes 0.7.0 or an older release, and breaking changes in a 0.x line will land unannounced.
The fix: Publish a changelog page keyed to npm versions and note the documented SDK version somewhere machine-readable.
What they do well
First-class agent readability: /llms.txt and /llms-full.txt exist and are complete, and every page banner points LLMs at them.
Deployed contract addresses are in checksummed tables with explorer links, and the CertiK audit page names its exact scope files.
Honest, load-bearing caveats most docs omit: the x402 CORS browser limitation, the getKeys-vs-expiry footgun, and the explicit "no sub-delegation" note.
Top 3 recommendations
Reconcile the revocation story: scope "global and immediate" to the registering chain and surface the L2-cache staleness caveat on the revokeSession page itself.
Regenerate the MCP tool counts and slash-command table from the server manifest, and fix the /sdk table's claim that createWallet writes to the Keystore.
Make the referenced GitHub "source of truth" reachable (or repoint to public artifacts), and fix the 6-vs-18 decimals comment in the grantSession example.
Fixed
0
Skip
5
Fail
0
Summary
Verified 14 runnable snippets from the Altana docs (docs.altana.network) in a clean Node.js v24 sandbox: 9 PASS, 5 SKIP, 0 FAIL. Everything executable without a funded onchain wallet worked exactly as written — installs, wallet generation (counterfactual, offline), the public-RPC read client, the balances read, the skill.md download, and both MCP config formats. Notably, the getting-started flow's signer._privateKey property exists and prints a key in SDK 0.7.0, and client.balances on an undeployed counterfactual wallet returns 0n with no funds, matching the "No funds required" claim. Skips were snippets requiring a funded wallet/relay fees (no credentials provided), the claude CLI (unavailable in sandbox), or fragments with undefined variables the page does not supply.
Required credentials
PRIVATE_KEY — a throwaway secp256k1 key generated locally (as the docs themselves suggest) sufficed for counterfactual wallet creation; no requester credentials were provided.
A funded BNB wallet would be required to execute grantSession, execute, and ERC-8183 flows; not available.