@artblocks/abx-cli 0.1.0-alpha.21 → 0.1.0-alpha.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +852 -0
- package/assets/renderer-scaffold/README.md +2 -2
- package/assets/renderer-scaffold/src/MyRenderer.sol +2 -2
- package/assets/renderer-scaffold/src/interfaces/IAbxFieldRenderer.sol +1 -1
- package/assets/renderer-scaffold/src/interfaces/IAbxParams.sol +2 -2
- package/assets/renderer-scaffold/test/MyRenderer.t.sol +1 -1
- package/dist/commands/deploy.d.ts +30 -17
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +234 -97
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/project.d.ts +16 -0
- package/dist/commands/project.d.ts.map +1 -1
- package/dist/commands/project.js +150 -10
- package/dist/commands/project.js.map +1 -1
- package/dist/commands/reads.js +2 -2
- package/dist/commands/reads.js.map +1 -1
- package/dist/commands/scaffold.d.ts +3 -1
- package/dist/commands/scaffold.d.ts.map +1 -1
- package/dist/commands/scaffold.js +64 -20
- package/dist/commands/scaffold.js.map +1 -1
- package/dist/commands/service.js +1 -1
- package/dist/commands/service.js.map +1 -1
- package/dist/commands/submit-app.d.ts +58 -0
- package/dist/commands/submit-app.d.ts.map +1 -0
- package/dist/commands/submit-app.js +512 -0
- package/dist/commands/submit-app.js.map +1 -0
- package/dist/config.d.ts +1 -15
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -1
- package/dist/config.js.map +1 -1
- package/dist/flag-allowlists.d.ts.map +1 -1
- package/dist/flag-allowlists.js +5 -1
- package/dist/flag-allowlists.js.map +1 -1
- package/dist/flags.d.ts +4 -0
- package/dist/flags.d.ts.map +1 -1
- package/dist/flags.js +23 -0
- package/dist/flags.js.map +1 -1
- package/dist/main.js +125 -37
- package/dist/main.js.map +1 -1
- package/dist/mintpage.d.ts.map +1 -1
- package/dist/mintpage.js +29 -4
- package/dist/mintpage.js.map +1 -1
- package/dist/output.d.ts +32 -1
- package/dist/output.d.ts.map +1 -1
- package/dist/output.js +74 -9
- package/dist/output.js.map +1 -1
- package/dist/ownerops.d.ts +101 -13
- package/dist/ownerops.d.ts.map +1 -1
- package/dist/ownerops.js +357 -89
- package/dist/ownerops.js.map +1 -1
- package/dist/preview.d.ts +1 -1
- package/dist/preview.js +1 -1
- package/dist/schema.d.ts +18 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +37 -2
- package/dist/schema.js.map +1 -1
- package/dist/served.js +1 -1
- package/dist/update-check.d.ts.map +1 -1
- package/dist/update-check.js +9 -3
- package/dist/update-check.js.map +1 -1
- package/package.json +6 -6
- package/skill/SKILL.md +62 -32
- package/skill/reference/code-projects.md +78 -24
- package/skill/reference/creator-token.md +16 -3
- package/skill/reference/decisions.md +59 -13
- package/skill/reference/hosting.md +1 -1
- package/skill/reference/operating.md +33 -13
- package/skill/reference/setup.md +1 -1
- package/skill/reference/troubleshooting.md +16 -6
|
@@ -9,6 +9,7 @@ After launch the owner operates the project. Each command builds a tx, signs it
|
|
|
9
9
|
| Command | Does | Decision to surface |
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| `abx mint <addr> [--to 0x.. (default owner)]` | issue a token — the 1/1's token #0, or a Series' next-in-order token | who receives it (owner = pre-mint; a buyer = primary sale) |
|
|
12
|
+
| `abx submit-app <collection> --name … --summary … --description …` | list that collection in the ABX App Store (mint + catalog copy). Optional; not part of deploy. Re-run writes params only if already claimed | confirm store copy (not the collection name); they must own the collection |
|
|
12
13
|
| `abx refresh <addr> [--token 0]` | ask marketplaces to (re)index the token's metadata | none — run it right after a mint or URI change |
|
|
13
14
|
| `abx transfer <addr> --to 0x.. [--token 0]` | settle a sale/gift — move the token to a new holder | who the recipient is (price/terms are off-chain) |
|
|
14
15
|
| `abx set-token-uri <addr> --uri <base>` | re-point the resolver **base** (e.g. move the node); contract derives `{base}/{chainId}/{address}/{tokenId}` | the new base URL |
|
|
@@ -24,15 +25,32 @@ After launch the owner operates the project. Each command builds a tx, signs it
|
|
|
24
25
|
| `abx attach <addr> <key> <ipfs://…\|ar://…\|https://…>` | attach a named file to a token → the `artifacts` manifest (the data plane) | the key (how it appears); locator vs `--file` on-chain |
|
|
25
26
|
| `abx set-field <addr> --field <name> (--text "…" \| --value 0x..) [--representation <r>] [--collection]` | set an on-chain metadata field (token or collection scope) — the low-level primitive | which field, where it lives, on-chain vs off |
|
|
26
27
|
| `abx lock-field <addr> --field <name> [--collection]` | **freeze a field forever** (all its representations) | confirm — irreversible |
|
|
28
|
+
| `abx lock-script <addr>` | **freeze the on-chain program (script chunks) forever** — the lock that freezes a code project's *work* (`setScriptChunk`/`removeLastScriptChunk` revert after) | confirm — irreversible; SeriesCode/EditionCode only |
|
|
29
|
+
| `abx lock-dependencies <addr>` | **freeze the dependency set forever** (library list + registry pointer) | confirm — irreversible |
|
|
30
|
+
| `abx lock-param-hooks <addr>` | **freeze the three param hooks forever** (configure/augment/transfer) — the lock a *buyer* cares about: the transfer hook is a veto over transfers **and** mints, so until this is sent the owner can arm one | confirm — irreversible; SeriesCode/EditionCode only. Freezing an EMPTY set is the proof "no transfer veto can ever be armed"; a hook already set keeps its veto. No carve-out: hooks are owner-only forever and a freeze holds against everyone, including on an **ownerless** project — unlike the 721C validator, don't conflate them ([why](code-projects.md#live-data-the-augment-hook--the-hook-is-the-setting)) |
|
|
31
|
+
| `abx set-seed-source <addr> <0x..\|canonical\|none>` | re-point a **code project's** mint-seed source — the creator's own `IAbxSeedSource` (commit-reveal / VRF), the shared `canonical` one, or `none`. Probed first: it must answer `seed(uint256,address)` with 32 bytes or the command refuses | **future mints only** (assigned seeds are settled) — on a part-sold drop the collection then spans two sources; pause and say so. Code projects only |
|
|
27
32
|
| `abx set-admin <addr> --to 0x..` | hand over contract ownership | confirm the new admin address |
|
|
28
33
|
|
|
29
|
-
**`lock-field` / `lock-uri` are permanent — always confirm with the human first.**
|
|
34
|
+
**`lock-field` / `lock-uri` / `lock-script` / `lock-dependencies` / `lock-param-hooks` are permanent — always confirm with the human first.**
|
|
30
35
|
|
|
31
|
-
**
|
|
36
|
+
**A code project isn't frozen until its PROGRAM is.** `lock-field`/`lock-uri` freeze *metadata*; they do **not** touch the script chunks. For a generative/code drop (`SeriesCode`/`EditionCode`) the work lives in the on-chain program, and the owner can keep rewriting it (`setScriptChunk`/`removeLastScriptChunk`) until you run `abx lock-script <addr>`. The full set is **`lock-script` + `lock-dependencies` + `lock-field`/`lock-uri`** (and `set-schema … lock=now` for any param whose value should freeze too). `abx verify` reports the script/dependency lock state so you can see what's still mutable.
|
|
37
|
+
|
|
38
|
+
**Even with every lock engaged, don't tell a creator the OUTPUT is immutable.** A lock freezes what this contract *stores*, and the metadata locks reach fields and the URI config — not the param store. **An *ungoverned* param has no lock**, and the renderer serves it into `tokenURI` — so an owner can still change the served metadata and the render. (A *schema'd* param is different: it can be welded permanently — see "Welding a PARAM" below — but a welded value can still be *overridden at read time* by an `--augment` hook until `lock-param-hooks` freezes the hook set.) And a `name@version` **`--dep` resolves live from the dependency registry** on every read: `lock-dependencies` pins which library the ref means, not the bytes the registry hands back. `abx verify`'s `chain-complete` is about *where* bytes come from, not whether they change. Say **"the metadata is locked"**; the stronger claim needs on-chain `--dep 0x…` refs plus locked fields. **And a lock a buyer will ask about that isn't in the metadata set at all: `lock-param-hooks`** — a code project's transfer hook is a *veto* (its revert fails a transfer, and a mint), so an unfrozen hook set is a standing power over whether a collector can sell ([hooks](code-projects.md#live-data-the-augment-hook--the-hook-is-the-setting)). Read the other way it's a capability — a piece that adapts to live chain state is a real design, not a defect. Full disclosure list (what an owner can and cannot do, and the read for each) → https://abx.docs.artblocks.io/protocol/owner-powers/
|
|
39
|
+
|
|
40
|
+
**Welding a PARAM is a different verb — and it IS a real weld.** Fields and [PostParams](code-projects.md#postparams) are separate namespaces that can share a name, and `lock-field` freezes the *field*. To make a param permanent, lock its schema: `abx set-schema <addr> --schema <key>:<Type>:<Auth>:lock=now` (or `abx retire-param <addr> <key>`, the one-arg form). Once that deadline is past, three things hold **forever**, all enforced on-chain:
|
|
41
|
+
|
|
42
|
+
- every `configure-param` on the key reverts `ParamLockExpired`;
|
|
43
|
+
- **the SCHEMA freezes too** — `set-schema` on the key also reverts `ParamLockExpired`, so its Type, Auth, bounds and `Select` option table can never be edited. (That matters concretely: without it, a locked `Select` param's options could be swapped afterwards and a collector's "Ember" would re-render as "Frost" with no param write at all.)
|
|
44
|
+
- the owner's raw setter was already closed on any schema'd key (`SchemaGoverned`), so there is no back door.
|
|
45
|
+
|
|
46
|
+
`lock=` is **monotonic**: a later `set-schema` may only move the deadline *earlier*, never later and never back to open (`ParamLockNotExtendable`). So the weld cannot be un-welded, and telling a creator "this is permanent" is accurate. (`lock-field` refuses a declared param key rather than letting you lock the wrong thing.) **Two honest caveats to keep, both worth saying out loud before a creator advertises a frozen value:**
|
|
47
|
+
|
|
48
|
+
- a weld freezes the *stored* value and schema — an `--augment` hook can still override what a reader is served, until `lock-param-hooks` freezes the hook set (and that lock freezes the hook **addresses**, not the code behind them — an upgradeable proxy at a locked address can still change behavior, so permanence needs immutable hook contracts);
|
|
49
|
+
- a weld covers **token-scope** writes; a **contract-scope default** on the same key can still be cleared. `clearContractParam` deliberately sits outside the schema guard — it is the only recovery path from a value poisoned before the schema existed — so an owner may set a collection-wide default, weld the key, sell tokens that inherit it, and then delete the default, changing every token that never wrote its own value. Clearing can only *remove* a fallback (it can't forge a value, bypass an auth rule, or touch a token-scope value already written). **If a collection-wide value must be permanent, write it per token through the governed path** instead of leaving it as an inherited default.
|
|
32
50
|
|
|
33
51
|
### Authorship + rights (credit + license)
|
|
34
52
|
|
|
35
|
-
The reserved **collection** keys are `
|
|
53
|
+
The reserved **collection** keys are `creator`, `display_notes`, `creator_links`, `license` (a rights *identifier* like `CC0-1.0` / `CC-BY-NC-4.0`). `--creator`/`--license`/`--display-notes`/`--creator-links` on any deploy command are **sugar over `set-field`** — they pre-fill the same on-chain inline collection fields at deploy time (parity with `--description`/`--external-url`); change them later with `abx set-field <addr> --collection --field creator --text "Casey Reas"` directly.
|
|
36
54
|
|
|
37
55
|
They project into `contractURI` on both the resolver and the on-chain renderer; unset ⇒ omitted. Works on **any** token type (1/1 · Series · code) — reserved keys in the shared metadata store, not a code-only feature. Being *reserved*, they never become `artifacts` entries the way an arbitrary `attach` key would.
|
|
38
56
|
|
|
@@ -48,7 +66,7 @@ A token anchors **named, typed files**; the served JSON's **`artifacts`** array
|
|
|
48
66
|
- scope: `--token <id>` (default 0) or `--collection`; any lane; `--dry-run` previews the tx.
|
|
49
67
|
- **`artifacts` and `abx_provenance` are COMPUTED** — the resolver/renderer assembles them from your fields. `set-field`/`attach` refuse them: you never set the manifest, you attach the files it lists.
|
|
50
68
|
- **Verify** — a resolver serves the complete listing: `curl <resolver>/t/<chainId>/<addr>/<id>` shows the `artifacts` array, and `/t/<chainId>/<addr>/<id>/data/<key>` fetches (or 302-redirects to) each file. The attached bytes are stored on-chain + keccak-anchored either way.
|
|
51
|
-
- **On-chain vs resolver reach.** The complete listing (arbitrary attached keys) is a **resolver** surface — the EVM can't enumerate an open set of FIELD keys, so the bare on-chain `tokenURI` (on-chain renderer) emits **reserved fields only**. Attaching is durable + anchored regardless, but to *surface* extra files to consumers today, the project is served by a resolver. **PostParams are the exception**: the params store enumerates its own keys on-chain
|
|
69
|
+
- **On-chain vs resolver reach.** The complete listing (arbitrary attached keys) is a **resolver** surface — the EVM can't enumerate an open set of FIELD keys, so the bare on-chain `tokenURI` (on-chain renderer) emits **reserved fields only**. Attaching is durable + anchored regardless, but to *surface* extra files to consumers today, the project is served by a resolver. **PostParams are the exception**: the params store enumerates its own keys on-chain (`paramSchemaKeys` · `contractParamKeys` · `tokenParamKeys`, then `tokenParam`/`contractParam`), so anyone with an RPC reads the complete configuration **directly from the contract** — no resolver, no indexer, and no metadata document in the middle. That store is the canonical surface, which is why params are *not* also projected into `tokenURI`; read them with `abx state` (schemas) and `abx tokens` (values). Say it to a creator as one line — *attachments always need a resolver; params never do.*
|
|
52
70
|
|
|
53
71
|
### Series-only owner ops
|
|
54
72
|
|
|
@@ -63,25 +81,25 @@ For a multi-token Series ([SKILL → Series](../SKILL.md#series-multi-token-drop
|
|
|
63
81
|
| `abx set-primary-payee <addr> --payee 0x..\|none` | declare where primary-sale proceeds go (`none` clears) | the payout destination (a wallet or splitter) |
|
|
64
82
|
| `abx set-max-invocations <addr> --max <N>` | **lower** the supply cap (monotonic) — e.g. close an open edition early at the minted count | confirm — can only decrease, never below what's minted |
|
|
65
83
|
|
|
66
|
-
`set-field` / `lock-field` work per **token** for a Series — pass the token id (`--field image --file … ` targets that token's
|
|
84
|
+
`set-field` / `lock-field` work per **token** for a Series — pass the token id (`--field image --file … ` targets that token's work); tokens share the collection scope with `--collection`.
|
|
67
85
|
|
|
68
86
|
### Edition owner ops
|
|
69
87
|
|
|
70
|
-
For an **ERC-1155 edition** (`OneOfOneEdition` / `EditionImage` / `EditionCode`, reached via `--copies` at deploy — [SKILL → which command](../SKILL.md#which-command--what-are-you-launching)). Everything above still applies per
|
|
88
|
+
For an **ERC-1155 edition** (`OneOfOneEdition` / `EditionImage` / `EditionCode`, reached via `--copies` at deploy — [SKILL → which command](../SKILL.md#which-command--what-are-you-launching)). Everything above still applies per work (transfer, royalty, fields, locking); these are the edition-only twins, keyed by **id** instead of a single owner.
|
|
71
89
|
|
|
72
90
|
| Command | Does | Decision to surface |
|
|
73
91
|
|---|---|---|
|
|
74
|
-
| `abx mint <addr> --token-id <n> --amount <n>` | mint **copies** of one id — `--token-id` defaults to `0` on a 1/1-edition (its only id), **required** on EditionImage/EditionCode (ids are caller-named
|
|
92
|
+
| `abx mint <addr> --token-id <n> --amount <n>` | mint **copies** of one id — `--token-id` defaults to `0` on a 1/1-edition (its only id), **required** on EditionImage/EditionCode (ids are caller-named works; see `abx tokens <addr>`) | which id, how many copies, who receives them |
|
|
75
93
|
| `abx transfer <addr> --amount <n> --from 0x.. --to 0x..` | move copies of an id between holders — `--from` is **required** (an id can have many concurrent holders, so there's no single on-chain "owner" to default from) | which holder is selling, how many copies |
|
|
76
94
|
| `abx set-max-supply <addr> --token-id <n> --cap <n>` | **lower** one id's ERC-1155 supply cap — the per-id twin of `set-max-invocations`; monotonic (never below that id's live supply) | confirm — **one-way**: `--cap open` is refused (once capped, an id can never re-open), so closing an id is final |
|
|
77
|
-
| `abx ping-uri <addr> --token-ids <csv\|range>` |
|
|
95
|
+
| `abx ping-uri <addr> --token-ids <csv\|range>` | **owner-only**: re-emit the per-id refresh events for the given ids, after a contract-wide re-point (`set-token-uri`/`set-renderer`) that only emitted its own config event, not a per-id one. Always emits ERC-4906 `MetadataUpdate(id)`; also emits the native ERC-1155 `URI(uri(id), id)` **unless an on-chain renderer is configured** (that event would carry the whole rendered document, at 8 gas per byte of log data) | sign as the owner — run it when a marketplace/indexer only honors the per-id event and missed the re-point |
|
|
78
96
|
| `abx minter configure <addr> --token-id <n> --price <eth> --allocation <n>` | price **one id** on the edition sibling minter (`AbxFixedPriceMinter1155`) — every id sells on its own terms, not one price for the whole contract | which id, price, allocation |
|
|
79
97
|
| `abx minter buy <addr> --token-id <n> --quantity <n>` | buy `n` copies of that id in one purchase — pays `price × quantity` | how many copies |
|
|
80
98
|
| `abx tokens <addr> --holder 0x..` | **read** (no tx): adds a `held` column — `balanceOf(holder, id)` per id, straight from the contract. The ONLY way to ask what one address holds: `supply/maxSupply` says how many copies exist, never who has them (an id has many concurrent holders and the set isn't enumerable from a head read) | none — this is the "did my transfer actually land?" read |
|
|
81
99
|
|
|
82
|
-
`--token-id` is required on every edition op above that names a specific
|
|
100
|
+
`--token-id` is required on every edition op above that names a specific work, except a 1/1-edition (defaults to `0`, its only id) — and refused on a 721 target either way. Passing `--count` to `mint`, or omitting `--from` on `transfer`, is refused on an edition, pointed at the flag to use instead.
|
|
83
101
|
|
|
84
|
-
**Two numbers, not one — get this straight with the creator BEFORE deploying.** An edition has an **id space** (how many distinct
|
|
102
|
+
**Two numbers, not one — get this straight with the creator BEFORE deploying.** An edition has an **id space** (how many distinct works) and a **per-id copy cap** (`--copies`). They multiply. On `deploy-code --copies 100` the id space comes from `--max`, which **defaults to 16** — so "100 copies" without `--max` means *up to 16 different generative variations × 100 copies each*, i.e. as many as 1600 tokens, not 100. A creator who says "an edition of 100" almost always means **one** work: pass `--max 1 --copies 100`. The dry-run states the real shape (`up to N id(s), M copies each`) — read that line back to them before any spend. Same arithmetic on `deploy-series --copies` (ids come from the folder) and `deploy --copies` (a single id, so `--copies` IS the total).
|
|
85
103
|
|
|
86
104
|
### Selling — the shared fixed-price minter
|
|
87
105
|
|
|
@@ -89,7 +107,7 @@ Instead of writing a sale contract, use the canonical **`AbxFixedPriceMinter`**:
|
|
|
89
107
|
|
|
90
108
|
> **The minter sells a Series, mint-on-purchase — not a 1/1 you already hold.** It mints *unminted* supply to a buyer, so it needs the Series interface (`minter`/`paused`/`primaryPayee`). A plain `abx deploy` **1/1 has none of that** — its only post-mint move is `abx transfer` (settle an off-chain sale). So there are two real paths for selling one piece: **(A)** mint the 1/1 to yourself, sell it off-platform (OpenSea/Blur), then `abx transfer --to <buyer>`; or **(B)** for a native fixed-price *primary* sale, deploy the single piece as a **1-token Series** (`abx deploy-series` on a one-file folder, `--no-mint`) and run the go-live sequence below with `--allocation 1`. Don't try to wire the minter to a plain 1/1 — `set-minter`/`unpause` will revert.
|
|
91
109
|
>
|
|
92
|
-
> **The edition minter is the one exception — it DOES sell a "1/1"-shaped
|
|
110
|
+
> **The edition minter is the one exception — it DOES sell a "1/1"-shaped work directly.** `AbxFixedPriceMinter1155` targets `IAbxEditionMint`, which `OneOfOneEdition` implements (id space fixed to `0`), so a priced open/limited edition of a single work needs no Series wrapper: `abx deploy --copies <n|open> --no-mint` ships the full sale stack on its own — run the same go-live sequence below with `--token-id 0`.
|
|
93
111
|
|
|
94
112
|
| Command | Does | Notes |
|
|
95
113
|
|---|---|---|
|
|
@@ -106,7 +124,9 @@ abx unpause <token> # open the sale (th
|
|
|
106
124
|
```
|
|
107
125
|
Two independent grants — *configured* (on the minter) and *assigned* (on the token) — so "not configured" and "not assigned" are distinct, diagnosable reverts; `abx minter show` flags whichever is missing. **One mint per `purchase()`**; a buyer who wants several sends several txs. Allocation and the token's `maxInvocations` both bind (tighter wins) — keep reserves by allocating less than the supply. Other mechanics (auctions, allowlists) are *different* minters, not knobs here.
|
|
108
126
|
|
|
109
|
-
**
|
|
127
|
+
> **Re-pricing a live sale fails the buys already in flight — by design.** Every purchase carries the terms it was quoted (payment token + a max price) and reverts `SaleTermsChanged` if the sale moved; that's what keeps a re-`configure` from reaching a buyer's ERC-20 allowance. So a mid-mint price change isn't silent: some in-flight buys revert and those buyers just retry (the CLI and the scaffolded mint page re-read the terms every time). Want a clean cutover? `abx pause <token>` → `minter configure …` → `abx unpause <token>`.
|
|
128
|
+
|
|
129
|
+
**On an edition, only the minter calls need `--token-id`** — `minter configure/show/buy --token-id <n>` (a different sale per work, on `AbxFixedPriceMinter1155`); `set-minter`/`set-primary-payee`/`pause`/`unpause` stay exactly as above, contract-wide (one minter, one payee, one pause gate for the whole id space). `minter buy --token-id <n> --quantity <n>` buys that many copies in one purchase, paying `price × quantity`.
|
|
110
130
|
|
|
111
131
|
### A mint website for buyers — `abx mint-page`
|
|
112
132
|
|
|
@@ -118,7 +138,7 @@ Once a sale is live, `abx mint-page <token>` scaffolds a **self-contained Next.j
|
|
|
118
138
|
| Runs | `cd mint-page && npm install && npm run dev` (preview) → **Vercel** (`npm i -g vercel && vercel --prod`), setting the `NEXT_PUBLIC_*` vars in the dashboard |
|
|
119
139
|
|
|
120
140
|
- **Backend-free** — reads sale state + each token's image straight from chain (`tokenURI(id)`); mints via the buyer's injected wallet (viem, no API keys). On-chain collections need nothing else; off-chain ones rely on their `tokenURI` resolving.
|
|
121
|
-
- **Works against an edition too** — pointed at `OneOfOneEdition`/`EditionImage`/`EditionCode`, the page is a **token-id-and-quantity purchase card** instead of a gallery (no minted-tokens list in this v1 page). Refuses only a plain 1/1 (no minter lane) — deploy a one-token Series, or an edition of one
|
|
141
|
+
- **Works against an edition too** — pointed at `OneOfOneEdition`/`EditionImage`/`EditionCode`, the page is a **token-id-and-quantity purchase card** instead of a gallery (no minted-tokens list in this v1 page). Refuses only a plain 1/1 (no minter lane) — deploy a one-token Series, or an edition of one work, instead.
|
|
122
142
|
- **A starting point** — plain React + one CSS file. Offer it as a release next-step, then help build a bespoke page per drop. The README covers multi-wallet (RainbowKit), ERC-20 (add an `approve` step), and the RPC/gallery notes. V1 handles **ETH** sales.
|
|
123
143
|
- **RPC safety** — the embedded read RPC is public/keyless (it ships to the browser). Never bake a secret-keyed endpoint into a `NEXT_PUBLIC_` var.
|
|
124
144
|
|
package/skill/reference/setup.md
CHANGED
|
@@ -34,7 +34,7 @@ When `abx doctor` flags a tight range, or a reconstruction would be large/slow
|
|
|
34
34
|
- **a hosted resolver LOST its index (or its render thumbnails) after a redeploy** → the SQLite projection wasn't on a persistent volume. The scaffold creates `fly volumes create abx_data` **before** the first deploy so the store lives on `/data` (the mount); if you deployed WITHOUT the volume, the store sat on ephemeral disk and a redeploy wiped it. Fix: ensure the volume exists (`fly volumes list`), then re-index (`abx add <addr> --remote --from-block <deployBlock>`). Note published **render locators + traits live on that same volume** (producer-published, not chain-derived), so restoring them after a volume loss needs a runner re-sweep, not just a chain replay — re-run `abx render <addr> --remote <resolver>` (idempotent; it re-publishes from the storage home without re-rendering) or let the effects service sweep.
|
|
35
35
|
- **the project's on-chain `tokenURI` points at a HOSTED resolver but it isn't serving** → **do NOT "fix" it by running `abx serve` locally and handing over a `localhost` link.** The baked URL is the hosted one; a local serve resolves for no one but you. Fix the HOSTED resolver instead: re-run `abx add <addr> --remote` (now forwards the deploy block), check `GET /` on the host, and vet its RPC with `abx doctor`. A local serve is only ever the answer when the baked base is that same local machine.
|
|
36
36
|
- **port hygiene before `serve`** → check the port is free first (`lsof -i:8787`). If an old session holds it, kill that process or serve this project on a distinct `--port <n>` (and point its `--public-base-url`/tokenURI accordingly) — a stale server silently answering on the port is the #1 cause of "works for me, `unknown project` for everyone."
|
|
37
|
-
- **serving code projects is RPC-heavier than static
|
|
37
|
+
- **serving code projects is RPC-heavier than static content** → the live view rebuilds `tokenData` per request, and template-mode script chunks + data-backed (`String`/`Bytes`) params are read **live per view** (scalar PostParams come from the indexed projection, so they don't hit RPC each view). A resolver serving many code projects under marketplace traffic wants a range-generous, reliable RPC — this is a genuine scaling consideration, distinct from the getLogs range cap above.
|
|
38
38
|
- **a remote command returns 401 unauthorized** → the token the CLI resolved is missing/wrong for that target — the error names the var it used (`ABX_REMOTE_<NAME>_TOKEN` for a named remote, else `ABX_REMOTE_SELF_TOKEN`, else `--remote-token`). Check that var, or rotate the key at the provider if it may have leaked. Named remotes deliberately never fall back to `ABX_REMOTE_SELF_TOKEN` (or the resolver's own server-side `ABX_RESOLVER_ADMIN_TOKEN`).
|
|
39
39
|
- **a remote command returns 403 forbidden** → the key is **valid but not authorized** for this contract/chain — provider-side scoping, not a typo. Don't retry-loop and don't swap tokens blindly: check the provider dashboard, and the descriptor's `chains` (`abx remote <name>`).
|
|
40
40
|
- **register refused with `unsupported_chain`** → the service doesn't serve the project's chain — its descriptor `chains` says which it does. Pick a provider that covers the chain, or self-host.
|
|
@@ -16,16 +16,26 @@ Walk the cause down:
|
|
|
16
16
|
- Do **not** reach for `abx index --full` or a redeploy for a render/refresh problem.
|
|
17
17
|
|
|
18
18
|
### I changed the metadata but the marketplace shows the old value
|
|
19
|
-
- **First confirm the change landed:** `abx tokenuri <addr> --token N` (or the resolver's JSON) — if it shows the NEW value
|
|
19
|
+
- **First confirm the change landed:** `abx tokenuri <addr> --token N` (or the resolver's JSON) — if it shows the NEW value, the write worked, and that field's `abx_provenance` entry names the route it took (`source` = `inline`/`reader`/`renderer`/`url`/…, with a `note` like *"stored on chain"*). The gap is then 100% the marketplace's cache. (There is no `onChain` boolean in a provenance entry: the contract can't tell whether a value *resolves* on chain without interpreting it. Whether a value is a self-contained `data:` URI or a pointer is visible in the value itself. On a **resolver**, the extra `status` field is the one that answers "was this checked" — `verified`/`mismatch`/`anchored`/`off-chain`.)
|
|
20
20
|
- **Nudge it:** `abx refresh <addr>` — ABX emits **ERC-4906** on metadata changes so 4906-aware marketplaces self-refresh; `refresh` calls OpenSea directly with `OPENSEA_API_KEY`, else prints the link to click. Marketplace caches still lag on their own schedule — that's their side.
|
|
21
21
|
- **Remote resolver (self-hosted or a managed provider)?** It serves from its own store — a local edit must reach it: `abx add <addr> --remote <name|url>` / `abx index <addr> --remote <name|url>` re-indexes the remote node. Never "resubmit the transaction" or redeploy. If the nudge reported `backfilling`, the service is still catching up — `abx status <addr> --remote <name> --watch` until `live` before blaming the marketplace.
|
|
22
22
|
|
|
23
23
|
### An edition's URI re-point didn't refresh a marketplace/indexer
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
**Both lanes emit ERC-4906** — an edition (`OneOfOneEdition`/`EditionImage`/`EditionCode`) advertises
|
|
25
|
+
`0x49064906` and pings `MetadataUpdate(id)` / `BatchMetadataUpdate(0, max)` just like a 721, so a
|
|
26
|
+
4906-aware consumer does see the change. What an edition *also* has is ERC-1155's native
|
|
27
|
+
`URI(string,uint256)`, and that one is **not** emitted everywhere: a contract-wide re-point
|
|
28
|
+
(`abx set-token-uri` / `abx set-renderer`) has no range form of `URI` to express "every id may have
|
|
29
|
+
changed" (looping the whole id space would be a block-gas trap), and a per-id override write skips it
|
|
30
|
+
when an on-chain renderer is configured (the event would carry the entire rendered document). So a
|
|
31
|
+
marketplace/indexer that honors *only* the native per-id event can miss it. Fix: `abx ping-uri <addr>
|
|
32
|
+
--token-ids <csv|range>` re-emits the per-id refresh events for the ids you name — **owner-only** (it
|
|
33
|
+
used to be permissionless; with an on-chain renderer, letting anyone make an indexer render a whole
|
|
34
|
+
document per id was an asymmetric spam primitive), so sign it as the collection owner. It always emits
|
|
35
|
+
ERC-4906 `MetadataUpdate(id)`; the native `URI(uri(id), id)` follows only when there is **no** on-chain
|
|
36
|
+
renderer configured — with one, that event would carry the entire rendered document.
|
|
37
|
+
(Heads-up: `abx refresh`'s own advisory text still says an edition emits no ERC-4906. That line is
|
|
38
|
+
stale against the contracts; the `ping-uri` advice it gives is still the right next step.)
|
|
29
39
|
|
|
30
40
|
### "It's registered but serves nothing" / the add seemed to hang
|
|
31
41
|
**Ask the service where it got to before doing anything else: `abx status <addr> --remote <name>`.** The five states and what each one means for you are in [hosting.md → Indexing status](hosting.md#indexing-status--backfilling-is-not-a-failure). In short: `queued`/`backfilling` = **wait** (a cold replay on a rate-limited RPC takes minutes; the registration is already durable, so re-adding just makes you wait again); `failed` = read `error.class` (`rpc_rate_limited`/`rpc_unavailable` are the *service's* RPC, not your key — it retries on backoff); `stale` = it's serving, just behind. Never diagnose this by redeploying, rotating the key, or re-pointing the on-chain URI.
|