@artblocks/abx-cli 0.1.0-alpha.0
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/LICENSE +21 -0
- package/assets/renderer-scaffold/README.md +59 -0
- package/assets/renderer-scaffold/foundry.toml +15 -0
- package/assets/renderer-scaffold/remappings.txt +3 -0
- package/assets/renderer-scaffold/script/Deploy.s.sol +23 -0
- package/assets/renderer-scaffold/src/MyRenderer.sol +123 -0
- package/assets/renderer-scaffold/src/MyTraits.sol +75 -0
- package/assets/renderer-scaffold/src/interfaces/IAbxFieldRenderer.sol +32 -0
- package/assets/renderer-scaffold/src/interfaces/IAbxParams.sol +26 -0
- package/assets/renderer-scaffold/test/MyRenderer.t.sol +110 -0
- package/dist/config.d.ts +69 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +184 -0
- package/dist/config.js.map +1 -0
- package/dist/deps.d.ts +46 -0
- package/dist/deps.d.ts.map +1 -0
- package/dist/deps.js +90 -0
- package/dist/deps.js.map +1 -0
- package/dist/flags.d.ts +25 -0
- package/dist/flags.d.ts.map +1 -0
- package/dist/flags.js +34 -0
- package/dist/flags.js.map +1 -0
- package/dist/inspect.d.ts +48 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +184 -0
- package/dist/inspect.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +5102 -0
- package/dist/main.js.map +1 -0
- package/dist/migrate.d.ts +65 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +180 -0
- package/dist/migrate.js.map +1 -0
- package/dist/mintpage.d.ts +46 -0
- package/dist/mintpage.d.ts.map +1 -0
- package/dist/mintpage.js +461 -0
- package/dist/mintpage.js.map +1 -0
- package/dist/onchain-uri.d.ts +97 -0
- package/dist/onchain-uri.d.ts.map +1 -0
- package/dist/onchain-uri.js +243 -0
- package/dist/onchain-uri.js.map +1 -0
- package/dist/ownerops.d.ts +195 -0
- package/dist/ownerops.d.ts.map +1 -0
- package/dist/ownerops.js +1270 -0
- package/dist/ownerops.js.map +1 -0
- package/dist/provision.d.ts +86 -0
- package/dist/provision.d.ts.map +1 -0
- package/dist/provision.js +372 -0
- package/dist/provision.js.map +1 -0
- package/dist/remote.d.ts +58 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +54 -0
- package/dist/remote.js.map +1 -0
- package/dist/schema.d.ts +15 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +125 -0
- package/dist/schema.js.map +1 -0
- package/dist/series-traits.d.ts +30 -0
- package/dist/series-traits.d.ts.map +1 -0
- package/dist/series-traits.js +103 -0
- package/dist/series-traits.js.map +1 -0
- package/dist/signer.d.ts +80 -0
- package/dist/signer.d.ts.map +1 -0
- package/dist/signer.js +520 -0
- package/dist/signer.js.map +1 -0
- package/dist/upload.d.ts +28 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +41 -0
- package/dist/upload.js.map +1 -0
- package/package.json +55 -0
- package/skill/SKILL.md +304 -0
- package/skill/reference/code-projects.md +211 -0
- package/skill/reference/hosting.md +138 -0
- package/skill/reference/operating.md +116 -0
- package/skill/reference/setup.md +36 -0
- package/skill/reference/troubleshooting.md +28 -0
package/dist/migrate.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migrate a contract's OFF-CHAIN operator state from one resolver to another — the
|
|
3
|
+
* toolkit's portability guarantee, made operational.
|
|
4
|
+
*
|
|
5
|
+
* Everything on-chain a new resolver gets for free: it replays the event spine from any
|
|
6
|
+
* RPC (that's what the admin control plane's `POST /admin/projects` already does). The only
|
|
7
|
+
* thing it can't reconstruct from chain is the operator's off-chain state — the four fields
|
|
8
|
+
* on the registration row: `description`, `externalUrl`, off-chain `attributes`, and the
|
|
9
|
+
* `keccak → gateway-URL` content locators.
|
|
10
|
+
*
|
|
11
|
+
* The key property: each resolver's served JSON is **self-describing** via `abx_provenance`,
|
|
12
|
+
* which makes it self-MIGRATING. By reading the SOURCE resolver's public token/contract API
|
|
13
|
+
* (plus the chain, for the locator KEYS — the on-chain hashes, which aren't in any served
|
|
14
|
+
* JSON), we reconstruct exactly that off-chain state and bridge it to the destination through
|
|
15
|
+
* the same control plane. The two resolvers never talk to each other; the operator's CLI
|
|
16
|
+
* orchestrates from public endpoints alone — no shared database, no private channel.
|
|
17
|
+
*
|
|
18
|
+
* Two cases this can't paper over, both surfaced honestly:
|
|
19
|
+
* - **Stitched attributes** — an off-chain trait shadowed by an on-chain one of the same
|
|
20
|
+
* `trait_type` was never *served*, so it can't be recovered. We migrate the off-chain
|
|
21
|
+
* remainder (served traits whose `trait_type` has no on-chain entry), which is byte-exact
|
|
22
|
+
* for everything that was ever visible.
|
|
23
|
+
* - **Node-custody images** — an image committed by hash but never pinned to a durable
|
|
24
|
+
* backend is served from the source node's own `/image` route. There's no portable URL to
|
|
25
|
+
* copy; the bytes live only on the old host. We list these so the operator re-pins them
|
|
26
|
+
* (fetch → verify against the on-chain hash → re-upload) BEFORE tearing the old host down.
|
|
27
|
+
*/
|
|
28
|
+
import { fieldOf, inlineText, normalizeAttributes, METADATA_REPRESENTATION as R } from '@artblocks/abx-sdk';
|
|
29
|
+
import { hashContent } from '@artblocks/abx-storage';
|
|
30
|
+
const trim = (base) => base.replace(/\/+$/, '');
|
|
31
|
+
export const tokenApiUrl = (base, chainId, addr, id) => `${trim(base)}/t/${chainId}/${addr.toLowerCase()}/${id}`;
|
|
32
|
+
export const contractApiUrl = (base, chainId, addr) => `${trim(base)}/c/${chainId}/${addr.toLowerCase()}`;
|
|
33
|
+
async function getJson(url) {
|
|
34
|
+
let resp;
|
|
35
|
+
try {
|
|
36
|
+
resp = await fetch(url);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
throw new Error(`couldn't reach the source resolver at ${url}: ${err.message}`);
|
|
40
|
+
}
|
|
41
|
+
if (resp.status === 404)
|
|
42
|
+
return null; // unknown project / unminted token — not fatal per-token
|
|
43
|
+
if (!resp.ok)
|
|
44
|
+
throw new Error(`source resolver ${url} → ${resp.status} ${resp.statusText}`);
|
|
45
|
+
return (await resp.json());
|
|
46
|
+
}
|
|
47
|
+
const provOf = (json, field) => json?.abx_provenance?.find((p) => p.field === field);
|
|
48
|
+
/** Off-chain attribute trait_types present on-chain (case-insensitive) — these are NOT migrated as
|
|
49
|
+
* off-chain (the destination re-derives them from chain and they win the stitch). */
|
|
50
|
+
function onChainTraitTypes(fields) {
|
|
51
|
+
const entry = fieldOf(fields, 'attributes');
|
|
52
|
+
if (!entry || entry.representation !== R.inline)
|
|
53
|
+
return new Set();
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(inlineText(entry));
|
|
56
|
+
if (!Array.isArray(parsed))
|
|
57
|
+
return new Set();
|
|
58
|
+
return new Set(parsed.map((a) => String(a.trait_type).toLowerCase()));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return new Set();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Build the migration plan by reading the SOURCE resolver's public API, using the locally
|
|
66
|
+
* reconstructed on-chain state (`local`) for the hash KEYS the served JSON doesn't expose.
|
|
67
|
+
*/
|
|
68
|
+
export async function buildMigrationPlan(sourceBase, chainId, local) {
|
|
69
|
+
const addr = local.address;
|
|
70
|
+
const plan = { contentLocators: {}, nodeCustody: [], tokensRead: 0 };
|
|
71
|
+
// ── operator-level fields (one registration row applies across the collection) ──
|
|
72
|
+
// Prefer the contract API; fall back to token #0. Take a value only when its provenance
|
|
73
|
+
// says it's off-chain (a plain operator value) — on-chain values are re-derived by replay.
|
|
74
|
+
const contractJson = await getJson(contractApiUrl(sourceBase, chainId, addr));
|
|
75
|
+
const firstToken = local.tokens.find((t) => t.minted) ?? local.tokens[0];
|
|
76
|
+
const tokenZeroJson = firstToken
|
|
77
|
+
? await getJson(tokenApiUrl(sourceBase, chainId, addr, firstToken.tokenId))
|
|
78
|
+
: null;
|
|
79
|
+
const offChainText = (json, field, value) => (value != null && provOf(json, field)?.status === 'off-chain' ? value : undefined);
|
|
80
|
+
plan.description =
|
|
81
|
+
offChainText(tokenZeroJson, 'description', tokenZeroJson?.description) ??
|
|
82
|
+
offChainText(contractJson, 'description', contractJson?.description);
|
|
83
|
+
plan.externalUrl =
|
|
84
|
+
offChainText(tokenZeroJson, 'external_url', tokenZeroJson?.external_url) ??
|
|
85
|
+
offChainText(contractJson, 'external_link', contractJson?.external_link);
|
|
86
|
+
// attributes: the off-chain remainder = served traits whose trait_type has NO on-chain entry.
|
|
87
|
+
if (tokenZeroJson?.attributes?.length && provOf(tokenZeroJson, 'attributes')?.status !== 'on-chain') {
|
|
88
|
+
const onChain = onChainTraitTypes(firstToken?.fields ?? []);
|
|
89
|
+
const offChain = tokenZeroJson.attributes.filter((a) => !onChain.has(String(a.trait_type).toLowerCase()));
|
|
90
|
+
if (offChain.length)
|
|
91
|
+
plan.attributes = normalizeAttributes(offChain);
|
|
92
|
+
}
|
|
93
|
+
// ── per-token content locators (image bytes that live off-chain by hash) ──
|
|
94
|
+
for (const token of local.tokens) {
|
|
95
|
+
const image = fieldOf(token.fields, 'image');
|
|
96
|
+
if (!image || (image.representation !== R.keccak256 && image.representation !== R.sha256)) {
|
|
97
|
+
continue; // on-chain content or an on-chain locator — the destination derives it from chain
|
|
98
|
+
}
|
|
99
|
+
const json = await getJson(tokenApiUrl(sourceBase, chainId, addr, token.tokenId));
|
|
100
|
+
if (!json)
|
|
101
|
+
continue; // unminted / not served
|
|
102
|
+
plan.tokensRead++;
|
|
103
|
+
const prov = provOf(json, 'image');
|
|
104
|
+
const hash = image.value.toLowerCase();
|
|
105
|
+
// A durable locator: the resolver served a portable URL (ipfs/arweave/url source). Node-custody:
|
|
106
|
+
// the source served the bytes from its own host (source === the hash kind), so there's nothing to copy.
|
|
107
|
+
if (json.image && prov && prov.onChain === false && (prov.source === 'ipfs' || prov.source === 'arweave' || prov.source === 'url')) {
|
|
108
|
+
plan.contentLocators[hash] = json.image;
|
|
109
|
+
}
|
|
110
|
+
else if (json.image) {
|
|
111
|
+
plan.nodeCustody.push({ tokenId: token.tokenId, hash, imageUrl: json.image });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return plan;
|
|
115
|
+
}
|
|
116
|
+
export async function repinNodeCustody(images, backend) {
|
|
117
|
+
const result = { repinned: {}, repinnedTokens: [], mismatched: [], unreachable: [], needsDurableBackend: [] };
|
|
118
|
+
if (!images.length)
|
|
119
|
+
return result;
|
|
120
|
+
// A backend is "durable" for migration iff it can hand back a node-independent locator.
|
|
121
|
+
if (!backend.locator) {
|
|
122
|
+
result.needsDurableBackend = [...images];
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
for (const img of images) {
|
|
126
|
+
let bytes;
|
|
127
|
+
let contentType;
|
|
128
|
+
try {
|
|
129
|
+
const resp = await fetch(img.imageUrl);
|
|
130
|
+
if (!resp.ok) {
|
|
131
|
+
result.unreachable.push(img);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
bytes = new Uint8Array(await resp.arrayBuffer());
|
|
135
|
+
contentType = resp.headers.get('content-type') ?? 'application/octet-stream';
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
result.unreachable.push(img);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
// Trustless: re-hash the fetched bytes and compare to the ON-CHAIN commitment.
|
|
142
|
+
if (hashContent(bytes).toLowerCase() !== img.hash.toLowerCase()) {
|
|
143
|
+
result.mismatched.push(img);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
await backend.put(img.hash, { bytes, contentType });
|
|
147
|
+
const loc = await backend.locator(img.hash);
|
|
148
|
+
if (loc) {
|
|
149
|
+
result.repinned[img.hash.toLowerCase()] = loc;
|
|
150
|
+
result.repinnedTokens.push(img.tokenId);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Stored, but the backend still can't produce a portable locator — treat as not durable.
|
|
154
|
+
result.needsDurableBackend.push(img);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
const sameAttrs = (a = [], b = []) => {
|
|
160
|
+
const key = (xs) => xs
|
|
161
|
+
.map((x) => `${String(x.trait_type).toLowerCase()}=${String(x.value)}`)
|
|
162
|
+
.sort()
|
|
163
|
+
.join('|');
|
|
164
|
+
return key(a) === key(b);
|
|
165
|
+
};
|
|
166
|
+
export async function verifyParity(sourceBase, destBase, chainId, addr, tokenId) {
|
|
167
|
+
const [src, dst] = await Promise.all([
|
|
168
|
+
getJson(tokenApiUrl(sourceBase, chainId, addr, tokenId)),
|
|
169
|
+
getJson(tokenApiUrl(destBase, chainId, addr, tokenId)),
|
|
170
|
+
]);
|
|
171
|
+
return {
|
|
172
|
+
tokenId,
|
|
173
|
+
imageMatch: !!src && !!dst && src.image === dst.image,
|
|
174
|
+
descriptionMatch: (src?.description ?? null) === (dst?.description ?? null),
|
|
175
|
+
attributesMatch: sameAttrs(src?.attributes, dst?.attributes),
|
|
176
|
+
sourceImage: src?.image,
|
|
177
|
+
destImage: dst?.image,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mint-page scaffolding — a **self-contained** Next.js starter a creator stands up to sell a drop,
|
|
3
|
+
* compatible with the shared {AbxFixedPriceMinter}. The sibling of `deploy-resolver`: a buildable
|
|
4
|
+
* artifact the creator OWNS and customizes (with the agent's help), not a service we run.
|
|
5
|
+
*
|
|
6
|
+
* SELF-CONTAINED + BACKEND-FREE by design:
|
|
7
|
+
* - Reads live sale state (price · sold/allocation · paused · supply) straight from chain, and each
|
|
8
|
+
* token's image/name from `tokenURI(id)` — no server, no database. Fully-on-chain collections need
|
|
9
|
+
* nothing else; off-chain ones rely on their `tokenURI` resolving (same as any marketplace).
|
|
10
|
+
* - Wallet connect + mint use viem + the injected browser wallet (`window.ethereum`) — NO API keys,
|
|
11
|
+
* no WalletConnect projectId. The README shows how to swap in RainbowKit for multi-wallet.
|
|
12
|
+
* - Reads use a PUBLIC RPC (never the creator's keyed endpoint — that would leak a secret into a
|
|
13
|
+
* `NEXT_PUBLIC_` var); the mint tx uses the wallet's own RPC. Config rides `NEXT_PUBLIC_*` env vars,
|
|
14
|
+
* prefilled by the CLI into `.env.local`.
|
|
15
|
+
*
|
|
16
|
+
* V1 scope (deliberately minimal — customize from here): ETH sales, one mint per click, a paginated
|
|
17
|
+
* gallery of minted tokens. ERC-20 sales (need an `approve` step) are flagged as a customization.
|
|
18
|
+
*
|
|
19
|
+
* Pure module: returns the artifact files + the exact next-step commands. The CLI writes the files and
|
|
20
|
+
* prints the steps; `vercel` / `next dev` run in the creator's own account/machine — they own that step.
|
|
21
|
+
*/
|
|
22
|
+
export interface MintPageOptions {
|
|
23
|
+
/** The ABX token (collection) contract to sell. */
|
|
24
|
+
token: string;
|
|
25
|
+
/** The shared fixed-price minter for the chain. */
|
|
26
|
+
minter: string;
|
|
27
|
+
chainId: number;
|
|
28
|
+
chainName: string;
|
|
29
|
+
/** A PUBLIC read RPC (no API key — it is embedded in a NEXT_PUBLIC_ var / a public site). */
|
|
30
|
+
rpcUrl: string;
|
|
31
|
+
/** Display name for the collection (defaults from the token's on-chain name). */
|
|
32
|
+
collectionName: string;
|
|
33
|
+
/** Block explorer base (e.g. https://sepolia.etherscan.io), for a "view contract" link. */
|
|
34
|
+
explorer?: string;
|
|
35
|
+
}
|
|
36
|
+
export interface MintPageArtifact {
|
|
37
|
+
files: Array<{
|
|
38
|
+
path: string;
|
|
39
|
+
content: string;
|
|
40
|
+
}>;
|
|
41
|
+
steps: string[];
|
|
42
|
+
}
|
|
43
|
+
/** Public, keyless RPCs safe to embed in a public site. Extend as chains are added. */
|
|
44
|
+
export declare const PUBLIC_RPC: Record<number, string>;
|
|
45
|
+
export declare function mintPageArtifact(o: MintPageOptions): MintPageArtifact;
|
|
46
|
+
//# sourceMappingURL=mintpage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mintpage.d.ts","sourceRoot":"","sources":["../src/mintpage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,cAAc,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,uFAAuF;AACvF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAG7C,CAAC;AAubF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,GAAG,gBAAgB,CA0BrE"}
|