Generate a contract's Solidity
Generates the Solidity source for one preset and answers with the source, the constructor arguments, and a Foundry test skeleton that deploys it. **This is the studio's compute step and it is metered.** The call is debited at `CREDIT_PRICES.contract` — the pricing model's own "contract generate + compile + test" action — through the one credit ledger, and the debit happens *before* the generator runs, so a caller who cannot afford it gets a 402 and no work started. The price is the preset-agnostic flat rate, not a function of input size: generation is local in-process string assembly, so it costs putty nothing that scales with the contract. **Determinism is part of the contract.** The same `presetId`, `params`, and `features` produce byte-identical `source`, so it can be diffed, committed, and hashed. `fingerprint` is the SHA-256 of it, which is what lets a later deploy tell whether the file is still the one the generator produced; a mismatch means it was hand edited and the contract's label drops to `experimental`. **Version pinning.** `openZeppelinContractsVersion` and `foundryRemappings` come out of the installed Wizard, not out of a constant in putty, so the version in this response, the `Compatible with OpenZeppelin Contracts` line in the source, and the remapping written to `remappings.txt` cannot disagree. **What you must send.** Every value in `params` is a string or a number, never a parsed Solidity value, and an array parameter is JSON array text (`"[\"0xYourWallet\"]"`), which is what a form field and a model both produce naturally. A required parameter that is missing is a 400 naming it — see `error.problems`. **The `features` block only affects the `wizard` presets.** The `ours` presets are putty's own source and their features are fixed; sending the block with an `ours` preset is accepted and ignored rather than refused, so one form can serve every preset.
Generates the Solidity source for one preset and answers with the source, the constructor arguments, and a Foundry test skeleton that deploys it. This is the studio's compute step and it is metered. The call is debited at CREDIT_PRICES.contract — the pricing model's own "contract generate + compile + test" action — through the one credit ledger, and the debit happens before the generator runs, so a caller who cannot afford it gets a 402 and no work started. The price is the preset-agnostic flat rate, not a function of input size: generation is local in-process string assembly, so it costs putty nothing that scales with the contract. Determinism is part of the contract. The same presetId, params, and features produce byte-identical source, so it can be diffed, committed, and hashed. fingerprint is the SHA-256 of it, which is what lets a later deploy tell whether the file is still the one the generator produced; a mismatch means it was hand edited and the contract's label drops to experimental. Version pinning. openZeppelinContractsVersion and foundryRemappings come out of the installed Wizard, not out of a constant in putty, so the version in this response, the Compatible with OpenZeppelin Contracts line in the source, and the remapping written to remappings.txt cannot disagree. What you must send. Every value in params is a string or a number, never a parsed Solidity value, and an array parameter is JSON array text ("[\"0xYourWallet\"]"), which is what a form field and a model both produce naturally. A required parameter that is missing is a 400 naming it — see error.problems. The features block only affects the wizard presets. The ours presets are putty's own source and their features are fixed; sending the block with an ours preset is accepted and ignored rather than refused, so one form can serve every preset.
Authorization
bearerAuth A bearer token. The Account routes accept a Privy access token; the MCP transport accepts an sk- API key issued by POST /account/api-keys.
In: header
Request Body
application/json
The preset to generate and the values for its parameters.
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/contracts/generate" \ -H "Content-Type: application/json" \ -d '{ "presetId": "erc-20-token", "params": { "property1": "string", "property2": "string" } }'{ "presetId": "string", "name": "string", "source": "string", "constructorArguments": [ "string" ], "constructorNote": "string", "test": "string", "audit": "audited", "auditExplanation": "string", "fingerprint": "string", "openZeppelinContractsVersion": "string", "foundryRemappings": [ "string" ], "credits": { "charged": 0, "action": "contract", "balance": { "allowance": 0, "purchased": 0, "total": 0 } }}List the contract presets GET
Every preset the studio can generate, in catalogue order: the standards first, then the studio's own contracts. A preset carries everything a caller needs to build its form: each parameter's name, its Solidity type, whether it is required, its default, and — for the `ours` presets — the OpenZeppelin files the contract is built on. The parameter order is the constructor's argument order. **The audit label travels with its meaning.** Each preset's `audit` is the trust ceiling for its *unmodified* output, and `reviewed` is not a statement that the contract has been audited: it means the parts are OpenZeppelin's and audited, and the choice of which parts, and how they are wired, is not. The `ours` presets — the Merkle claim, the shares split, the escrow, the staking pool — are `experimental`, because nothing of ours is audited. The Wizard has no kind for them, and OZ v5 removed the library utilities that used to cover them. **A `wizard` preset's constructor takes the initial Ownable owner, which the catalogue does not declare as a parameter**, because it is the deploying account and putty cannot know which account that will be. `POST /contracts/generate` says so in its `constructorNote` whenever the returned argument list is empty for that reason. **Free, and no bearer token.** This is a catalogue read: the same data a UI block renders before anyone has signed in.
Scan a token before you buy it GET
The free-layer Scan from §3.7: what a trader is being scammed by, for one token on one chain. It answers, from the chain itself: - **Supply and mint.** `totalSupply()` raw, and whether the owner can mint more. A live mint function held by an EOA is the flag; a pausable one is worse still, and is reported separately. - **LP lock.** Whether the pool's liquidity can be withdrawn, and until when. - **Fee parameters.** The pool's LP fee and, for a putty pool, the putty fee in bps. - **Holder concentration.** The top wallets by recent `Transfer` movement, and whether they hold more than the served concentration threshold. - **The putty Verify label**, attached from `runVerify` rather than reimplemented. **Public, unauthenticated, and free.** No bearer token is required and none is charged; this is the acquisition surface from §3.7, and a security report behind a login is a report almost nobody reads. The same split `POST /verify` makes. **Every field is measured, not-measurable, or failed — and the three are different.** Each measured field is a `{ status, value }` or a `{ status, kind, reason }` union. A read that failed is `unavailable` with `kind: "read_failed"` and the node's own words; a thing this data source cannot answer is `unavailable` with `kind: "not_measurable"` and a reason naming the seam that could. **Neither is ever rendered as `0`, `[]`, or a null with no reason** — a failed holder census must not read as "zero holders", which is the bug class this endpoint exists to stop repeating. So: `holders` is `null` on a single node (counting every holder means walking an indexed log from genesis) while the `topHolders` window beside it is real; the LP lock is `not_measurable` rather than `unlocked` when putty has no index of lockers; and the simulated buy/sell is `not_measurable` because a token address alone cannot price a swap. **Amounts are decimal strings end to end.** A 1e9 supply at 18 decimals is thirty digits and a double cannot hold it, so `totalSupplyRaw`, every `balanceRaw`, and every percentage are strings. Do not parse them into a number to display a total. **`clearedForMainnet` is always `false`** and is declared as the literal `false` in the schema so the document states what the code enforces: no putty report, of any label, is an external audit. A `verified custom` label means every check ran and passed on the evidence putty had — read `verifyLabelExplanation` for the sentence that must be shown beside it.