{"openapi":"3.1.0","info":{"title":"HALOWERK kettenwerk","version":"1.0.0","description":"HALOWERK kettenwerk — bezahlte Endpunkte nach x402. Preise in USDC auf Base Mainnet.","contact":{"url":"https://kette.halowerk.com/"}},"servers":[{"url":"https://kette.halowerk.com"}],"paths":{"/token/resolve":{"post":{"operationId":"token_resolve","summary":"Resolves a token symbol, contract address or price-directory id into every matching contract across Ethereum, Base, Arbitrum, Optimism, Polygon and BNB Smart Chain, marking which one is the issuer-operated version and which are bridged or look-alike contracts.","description":"A symbol is not an identity. Dozens of contracts carry the symbol USDC and most of them are not the one anyone means. This endpoint returns all of them rather than silently picking one: every match carries its chain, contract, on-chain symbol, name and decimals read directly from the contract, whether its source is verified, its market cap rank when it is inside the top 250, and a canonical flag whose criterion is stated in the answer — a contract is canonical when the price directory lists it under that asset for that chain. Bridged and wrapped images are flagged with the evidence taken from the contract's own name or symbol, never inferred. When more than one match exists, ambiguous is true and a recommendation names one contract with its reason; that recommendation is about identity, not about whether to buy anything. Symbol matches with no on-chain code, and contracts the price directory does not know, are still listed, because hiding them is exactly how an agent ends up on a look-alike. Accepts \"USDC\", \"0x…\" or \"coingecko:usd-coin\".","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"additionalProperties":false,"properties":{"query":{"type":"string","minLength":1,"maxLength":100,"description":"Token symbol (\"USDC\"), contract address (\"0x…\") or price-directory id (\"coingecko:usd-coin\")."},"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Restrict the answer to one chain. Omit to search all six."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/contract/verification":{"post":{"operationId":"contract_verification","summary":"Tells whether a contract's source is publicly verified, with compiler version, optimizer settings, license, deployer, creation block — and for a proxy, whether the implementation behind it is verified, which is the question that actually matters.","description":"Checks one address on Ethereum, Base, Arbitrum, Optimism, Polygon or BNB Smart Chain against the open verification registry and against the chain itself. For a proxy the answer is deliberately split in two: whether the proxy is verified says almost nothing, whether the implementation it currently points to is verified is the real question, and both are reported separately with the implementation address read from the EIP-1967 storage slot, the EIP-1167 clone pattern or an implementation() call — with the evidence named in each case. Not verified means the source is not published here; it is not a statement about safety, and this endpoint deliberately makes none. similar_contracts_count would need a bytecode index this hub does not run, so it stays null and the runtime bytecode hash is returned instead, which is what such a lookup would need. Security judgements are made by /token/authorities, /contract/upgrade-risk and /token/report, not here.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","address"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the contract lives on."},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Contract address."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/token/authorities":{"post":{"operationId":"token_authorities","summary":"Finds who can still change a token: owner, whether ownership was really renounced, mint, pause, freeze, blacklist, upgrade and fee authorities — each backed by the function name, its selector and a simulated call that shows whether access is actually restricted.","description":"Reads the contract itself rather than a project's claims. Ownership renouncement is checked, not believed: the zero address in owner() is evidence, a sentence in a whitepaper is not. Dangerous functions are found by their four-byte selectors in the runtime bytecode, and every finding names the function and the selector — a selector that is merely absent from the dispatch table is not reported. Whether a function is actually restricted is then tested by simulating the call from a neutral address that owns nothing: a call that goes through from there is a strong finding and is reported as such, a call that reverts with an access message is evidence of a guard, and anything else stays \"unklar\" instead of being interpreted. Nothing is ever signed or sent — every probe is a read-only simulation. A multisig owner is not the same as a single address, so the threshold and signer count are read from the owner contract and stated. Risk is a classification with all thresholds disclosed in the answer, not a score from a black box, and it is not investment or security advice.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","token"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the token lives on."},"token":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Token contract address."},"probe_calls":{"type":"boolean","default":true,"description":"Simulate each dangerous function from a neutral address to test whether access is restricted. Read-only, nothing is sent."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/contract/upgrade-risk":{"post":{"operationId":"proxy_upgrade_risk","summary":"For an upgradeable contract: who is allowed to swap the code behind the address, whether a timelock stands in front of it and how long its delay is, plus the full upgrade history with transaction references.","description":"Upgradeability alone is not a finding — every serious protocol is upgradeable. The finding is who holds the key and how much warning holders get. This endpoint reads the proxy pattern from the EIP-1967 slots, the clone bytecode or an implementation() call, resolves the admin, checks whether that admin is a multisig by asking it for its threshold and signer count, and checks whether it is a timelock by asking for getMinDelay() or delay() — a timelock with a delay of zero is not a timelock and is reported as such, with the delay always given in seconds. The upgrade history comes from the contract's own Upgraded events with block, timestamp, previous and new implementation and the transaction hash, so a buyer can go and look. Public nodes limit log ranges, so the window actually searched is stated and an incomplete history is marked incomplete rather than presented as complete. The storage gap check reads the published source; without published source it stays null, which means unknown, not absent. Risk is a classification with every threshold disclosed, not advice.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","address"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the contract lives on."},"address":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Contract or proxy address."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/tx/decode":{"post":{"operationId":"tx_decode","summary":"Decodes EVM call data into a readable method name, typed parameters, approvals and transfers, plus a one-sentence summary of what the transaction does — from a transaction hash, a raw signed transaction or a plain {to, data, value}.","description":"Turns opaque call data into something an agent can reason about before signing. The method signature is resolved from the verified source of the contract first, then from this hub's own list of common signatures, then from the open selector directory — and the answer always names which of the three was used, because a four-byte selector is short enough to collide and colliding entries are listed. An unknown selector stays unknown: parameters are returned raw and nothing is guessed. Approvals and transfers are pulled out separately and unlimited approvals are flagged in warnings. For a mined transaction hash the receipt logs are decoded as well, which gives the transfers and approvals that actually happened rather than only those visible in the call data. Batching wrappers (multicall, aggregate3, Universal Router execute) are unpacked one level. This endpoint decodes only — it never executes, never simulates and never sends. What the transaction would do to your balances is answered by /tx/simulate.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the call belongs to."},"tx_hash":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$","description":"Hash of an existing transaction. Its receipt logs are decoded too when it is mined."},"raw":{"type":"string","pattern":"^0x[0-9a-fA-F]{20,}$","description":"Raw signed transaction (any EIP-2718 type). It is only parsed, never broadcast."},"to":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Target address, when passing call data directly."},"data":{"type":"string","pattern":"^0x[0-9a-fA-F]*$","description":"Call data, when passing it directly."},"value":{"type":"string","description":"Value in wei as a decimal or 0x string. Optional, defaults to 0."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/tx/simulate":{"post":{"operationId":"tx_simulate","summary":"Simulates one EVM transaction against a forked chain state and returns exactly what it would do: success or revert reason, gas used, every balance change measured before and after, approvals granted or revoked, the call tree and warnings — without ever signing or broadcasting anything.","description":"Answers the question that stands before every signature: what really happens to my assets and my rights. The call is executed against the state of a named block on a simulation interface, never on the chain — this hub holds no private key and broadcasts nothing. Balance changes are not inferred from events but measured: the same simulation reads every touched balance immediately before and immediately after the call, native currency included, so an outflow that emits no event is still visible. Approvals granted and revoked are extracted separately and unlimited ones are flagged. Where a public node offers a call tracer, the full internal call tree with depth and the number of storage slots written are included; where it does not, both fields are null and listed in unavailable_fields rather than approximated — currently Arbitrum and BNB Smart Chain have no free tracer. State overrides are supported for what-if questions. A revert is a valid, billable answer with its reason; a simulation that could not be run at all is not billed. The result holds for the stated block only — state can change before execution.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","from","to"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain to simulate on."},"from":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Sender address. No signature is needed and none is created."},"to":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Target address."},"data":{"type":"string","pattern":"^0x[0-9a-fA-F]*$","default":"0x","description":"Call data."},"value":{"type":"string","default":"0","description":"Value in wei, decimal or 0x."},"gas":{"type":"integer","minimum":21000,"maximum":30000000,"description":"Optional gas limit for the simulation."},"block":{"type":"string","default":"latest","description":"\"latest\" or a block number as decimal string."},"state_overrides":{"type":"object","description":"Optional state overrides per address, in the eth_simulateV1 format (balance, nonce, code, state, stateDiff)."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/token/report":{"post":{"operationId":"token_risk_report","summary":"One combined report on an ERC-20 token: identity and look-alikes, source verification, who can still mint, pause, blacklist or upgrade it, and the upgrade history — every finding tagged with the endpoint it came from, priced below the sum of the individual calls.","description":"Runs the identity resolver, the verification check, the authority scanner and the upgrade risk check against one token and merges them into a single answer. Nothing new is measured here: every statement carries the endpoint number it came from, so any finding can be re-bought individually and checked. A section that fails does not sink the report — it is set to null, listed in checks_failed with its reason, and the score is computed only over the checks that ran, with coverage stated. Sections this hub does not offer yet (taxes and restrictions, holder concentration, liquidity ownership, honeypot simulation, unlock schedule) are named explicitly in sections_not_covered rather than silently omitted, because a report that hides what it did not look at is worse than no report. The score is arithmetic with every deduction listed by name and amount and every threshold disclosed; it is a summary of measurements, not a verdict on a project. This is not investment advice and not a security audit — a contract can behave differently after this check, and a clean report is not a guarantee.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","token"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the token lives on."},"token":{"type":"string","pattern":"^0x[0-9a-fA-F]{40}$","description":"Token contract address."},"depth":{"type":"string","enum":["schnell","voll"],"default":"voll","description":"\"schnell\" skips the upgrade history, which needs a log scan; \"voll\" runs everything available."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/tx/status":{"post":{"operationId":"tx_status","summary":"Status of one EVM transaction: confirmed, failed, pending, replaced or unknown, with confirmations, the finality rule of that chain, the fee actually paid and the revert reason when it failed.","description":"Reads one transaction hash on Ethereum, Base, Arbitrum, Optimism, Polygon or BNB Smart Chain and answers the question an agent actually has: did it go through, is it final yet, and what did it cost. Finality is defined differently per chain, so the rule used and the required block count are part of the answer instead of a single hard-coded number. A hash that no node knows is reported as \"unbekannt\", never as \"fehlgeschlagen\" — the two are not the same. A pending transaction whose nonce has already been consumed elsewhere is reported as \"ersetzt\", and the replacing transaction is searched for in the last 15 blocks; the search window is stated, so an empty result is not sold as proof of absence. Does not broadcast, sign or accelerate anything, and cannot tell you when a transaction entered the mempool — no node reports that.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain","tx_hash"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain the transaction lives on."},"tx_hash":{"type":"string","pattern":"^0x[0-9a-fA-F]{64}$","description":"Transaction hash, 0x plus 64 hex characters."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["pending","bestaetigt","fehlgeschlagen","ersetzt","unbekannt"]},"block_number":{"type":["integer","null"]},"confirmations":{"type":["integer","null"]},"finality":{"type":["string","null"]},"finality_blocks_remaining":{"type":["integer","null"]},"finality_rule":{"type":"string"},"gas_used":{"type":["integer","null"]},"effective_gas_price":{"type":["string","null"]},"fee_paid":{"type":["string","null"]},"revert_reason":{"type":["string","null"]},"replaced_by":{"type":["string","null"]},"in_mempool_seconds":{"type":["integer","null"]},"nonce_status":{"type":["string","null"]},"unavailable_fields":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/gas":{"post":{"operationId":"gas_estimate","summary":"Current gas cost on one EVM chain: base fee, priority fee for slow, normal and fast, the suggested max fee, the expected wait in seconds measured from real block times, and the total cost in USD for a typical transaction.","description":"Reads the fee history of the last 20 blocks on Ethereum, Base, Arbitrum, Optimism, Polygon or BNB Smart Chain and returns what a transaction costs right now. Priority fees come from the 10th, 50th and 90th percentile of the tips actually paid in those blocks — the percentile used is named, not hidden. On rollups the L1 data fee is quoted separately from the L2 execution fee, because it is often the larger part and an estimate that merges them is simply wrong; the L1 part is computed from the chain's own gas price oracle for a synthetic payload of a stated byte size. Waiting times are derived from the measured average block time over the last blocks, not guessed, and the number of blocks assumed per speed level is disclosed. USD cost needs a price for the native currency from two independent sources; if neither answers, the USD fields stay null instead of being estimated. Arbitrum has no OP-Stack gas price oracle, so its L1 data fee is reported as unavailable rather than approximated. This is a measurement, not a recommendation.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["chain"],"additionalProperties":false,"properties":{"chain":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"],"description":"Chain to read fees from."},"speed":{"type":"string","enum":["langsam","normal","schnell","alle"],"default":"alle","description":"Which speed level to highlight. All three are always returned."},"tx_type":{"type":"string","enum":["native_transfer","erc20_transfer","erc20_approve","swap","nft_mint","contract_deploy"],"default":"erc20_transfer","description":"Transaction profile used for the total cost estimate. Its assumed gas limit and byte size are stated in the answer."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}},"/chain/health":{"post":{"operationId":"chain_health","summary":"Health of one or more EVM chains measured across several independent public RPC endpoints at once: block height per endpoint, agreement, latency, block age, a real block-hash comparison at fixed depth and a gas spike flag.","description":"Queries every public RPC endpoint this hub knows for a chain in parallel — at least three, usually five — and reports what each one says instead of trusting one. Disagreement is the valuable finding: a single endpoint that lags or serves a different fork is exactly the failure mode this endpoint is built to expose, so agreement is reported per endpoint and the tolerance in blocks is derived from that chain's block time and stated. Beyond height it compares the actual block hash six blocks deep across endpoints; two different hashes at the same height mean the endpoints are on different chains. Endpoint names are given, never URLs, credentials or internal addresses. An endpoint this hub has rate-limited itself is marked self_limited with reachable null, because our own throttle says nothing about the endpoint. Supported chains: Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Smart Chain. This is a status measurement, not advice on which endpoint to use.","tags":["kettenwerk"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"chains":{"type":"array","items":{"type":"string","enum":["ethereum","base","arbitrum","optimism","polygon","bsc"]},"minItems":1,"maxItems":6,"default":["base"],"description":"Chains to check. Defaults to base."}}}}}},"responses":{"200":{"description":"Ergebnis","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Eingabe ungültig, charged=false"},"402":{"description":"Zahlung erforderlich. Die Antwort trägt accepts, description und inputSchema.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentRequired"}}}},"429":{"description":"Zu viele unbezahlte Anfragen, charged=false"},"502":{"description":"Gegenstelle nicht erreichbar, charged=false"},"504":{"description":"Zeitbudget überschritten, charged=false"}}}}},"components":{"schemas":{"PaymentRequired":{"type":"object","properties":{"x402Version":{"type":"integer"},"error":{"type":"string"},"description":{"type":"string"},"inputSchema":{"type":"object"},"accepts":{"type":"array","items":{"type":"object"}}}}},"securitySchemes":{"x402":{"type":"apiKey","in":"header","name":"PAYMENT-SIGNATURE","description":"x402 Zahlungsnachweis"}}}}