@artblocks/abx-sdk 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.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/dist/abi/generated.d.ts +6185 -0
  3. package/dist/abi/generated.d.ts.map +1 -0
  4. package/dist/abi/generated.js +28 -0
  5. package/dist/abi/generated.js.map +1 -0
  6. package/dist/abi/index.d.ts +3227 -0
  7. package/dist/abi/index.d.ts.map +1 -0
  8. package/dist/abi/index.js +38 -0
  9. package/dist/abi/index.js.map +1 -0
  10. package/dist/chains.d.ts +27 -0
  11. package/dist/chains.d.ts.map +1 -0
  12. package/dist/chains.js +71 -0
  13. package/dist/chains.js.map +1 -0
  14. package/dist/chunks.d.ts +168 -0
  15. package/dist/chunks.d.ts.map +1 -0
  16. package/dist/chunks.js +232 -0
  17. package/dist/chunks.js.map +1 -0
  18. package/dist/clients.d.ts +42 -0
  19. package/dist/clients.d.ts.map +1 -0
  20. package/dist/clients.js +90 -0
  21. package/dist/clients.js.map +1 -0
  22. package/dist/create2.d.ts +42 -0
  23. package/dist/create2.d.ts.map +1 -0
  24. package/dist/create2.js +47 -0
  25. package/dist/create2.js.map +1 -0
  26. package/dist/deploy.d.ts +192 -0
  27. package/dist/deploy.d.ts.map +1 -0
  28. package/dist/deploy.js +231 -0
  29. package/dist/deploy.js.map +1 -0
  30. package/dist/deployments.d.ts +60 -0
  31. package/dist/deployments.d.ts.map +1 -0
  32. package/dist/deployments.js +81 -0
  33. package/dist/deployments.js.map +1 -0
  34. package/dist/deps.d.ts +109 -0
  35. package/dist/deps.d.ts.map +1 -0
  36. package/dist/deps.js +103 -0
  37. package/dist/deps.js.map +1 -0
  38. package/dist/env.d.ts +2 -0
  39. package/dist/env.d.ts.map +1 -0
  40. package/dist/env.js +45 -0
  41. package/dist/env.js.map +1 -0
  42. package/dist/fastlz.d.ts +20 -0
  43. package/dist/fastlz.d.ts.map +1 -0
  44. package/dist/fastlz.js +123 -0
  45. package/dist/fastlz.js.map +1 -0
  46. package/dist/generator.d.ts +129 -0
  47. package/dist/generator.d.ts.map +1 -0
  48. package/dist/generator.js +81 -0
  49. package/dist/generator.js.map +1 -0
  50. package/dist/index.d.ts +31 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +20 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/ops.d.ts +379 -0
  55. package/dist/ops.d.ts.map +1 -0
  56. package/dist/ops.js +811 -0
  57. package/dist/ops.js.map +1 -0
  58. package/dist/probe.d.ts +30 -0
  59. package/dist/probe.d.ts.map +1 -0
  60. package/dist/probe.js +74 -0
  61. package/dist/probe.js.map +1 -0
  62. package/dist/reconstruct.d.ts +97 -0
  63. package/dist/reconstruct.d.ts.map +1 -0
  64. package/dist/reconstruct.js +597 -0
  65. package/dist/reconstruct.js.map +1 -0
  66. package/dist/spine.d.ts +110 -0
  67. package/dist/spine.d.ts.map +1 -0
  68. package/dist/spine.js +0 -0
  69. package/dist/spine.js.map +1 -0
  70. package/dist/token.d.ts +33 -0
  71. package/dist/token.d.ts.map +1 -0
  72. package/dist/token.js +66 -0
  73. package/dist/token.js.map +1 -0
  74. package/dist/tokendata.d.ts +50 -0
  75. package/dist/tokendata.d.ts.map +1 -0
  76. package/dist/tokendata.js +178 -0
  77. package/dist/tokendata.js.map +1 -0
  78. package/dist/traits.d.ts +38 -0
  79. package/dist/traits.d.ts.map +1 -0
  80. package/dist/traits.js +92 -0
  81. package/dist/traits.js.map +1 -0
  82. package/dist/types.d.ts +145 -0
  83. package/dist/types.d.ts.map +1 -0
  84. package/dist/types.js +2 -0
  85. package/dist/types.js.map +1 -0
  86. package/package.json +53 -0
@@ -0,0 +1,110 @@
1
+ import { type Hex } from 'viem';
2
+ /**
3
+ * The native-dialect vocabulary of the event spine, expressed once so every
4
+ * consumer (indexer, token API, UX) speaks it identically.
5
+ *
6
+ * Extensions are identified on-chain by `keccak256(name)` and announced via
7
+ * `AbxExtensionVersionSet(id, version)`. We keep the *names* here and derive the
8
+ * ids, so adding a future extension is one line — never a magic constant.
9
+ */
10
+ export declare const EXTENSION_NAMES: {
11
+ readonly royalty: "abx.extension.royalty";
12
+ readonly onChainMetadata: "abx.extension.onchain-metadata";
13
+ readonly maxInvocations: "abx.extension.max-invocations";
14
+ readonly externalMinter: "abx.extension.external-minter";
15
+ readonly primaryPayee: "abx.extension.primary-payee";
16
+ readonly paused: "abx.extension.paused";
17
+ readonly params: "abx.extension.params";
18
+ readonly configurableParams: "abx.extension.configurable-params";
19
+ readonly onChainScript: "abx.extension.onchain-script";
20
+ readonly dependencies: "abx.extension.dependencies";
21
+ readonly seedSource: "abx.extension.seed-source";
22
+ };
23
+ export type ExtensionKey = keyof typeof EXTENSION_NAMES;
24
+ export declare const EXTENSION_ID: Record<ExtensionKey, Hex>;
25
+ /** Friendly extension name for an on-chain id (falls back to the raw id). */
26
+ export declare function extensionName(id: Hex): string;
27
+ /**
28
+ * On-chain metadata `field` and `representation` tags are `bytes32` holding a short
29
+ * ASCII string, right-padded with zeros (a Solidity `bytes32` string literal). These
30
+ * encode/decode the readable tag both axes share (e.g. "image", "inline", "keccak256").
31
+ */
32
+ export declare function decodeTag(bytes32: Hex): string;
33
+ /** Encode a short metadata tag (a `field` or `representation`, e.g. "image") as a `bytes32`. */
34
+ export declare function encodeTag(tag: string): Hex;
35
+ /** Canonical on-chain metadata field tags (mirror `MetadataFields.sol`; a field key = its JSON key). */
36
+ export declare const METADATA_FIELD: {
37
+ readonly name: "name";
38
+ readonly description: "description";
39
+ readonly image: "image";
40
+ readonly animationUrl: "animation_url";
41
+ readonly externalUrl: "external_url";
42
+ readonly attributes: "attributes";
43
+ readonly backgroundColor: "background_color";
44
+ readonly youtubeUrl: "youtube_url";
45
+ readonly bannerImage: "banner_image";
46
+ readonly featuredImage: "featured_image";
47
+ readonly externalLink: "external_link";
48
+ readonly collaborators: "collaborators";
49
+ readonly artist: "artist";
50
+ readonly displayNotes: "display_notes";
51
+ readonly artistLinks: "artist_links";
52
+ readonly license: "license";
53
+ };
54
+ /**
55
+ * Canonical representation tags — the *how* of an on-chain metadata field. These are
56
+ * protocol convention (the contract stores `bytes32` opaquely; it never branches on them).
57
+ * A field carries exactly one. `reader` delegates on-chain decoding to a separate
58
+ * `IAbxOnChainReader` contract (value = `(reader, pointer)`); `gzip` variants are
59
+ * inflated off-chain by the indexer.
60
+ */
61
+ export declare const METADATA_REPRESENTATION: {
62
+ readonly inline: "inline";
63
+ readonly reader: "reader";
64
+ readonly renderer: "renderer";
65
+ readonly readerGzip: "reader-gzip";
66
+ readonly keccak256: "keccak256";
67
+ readonly sha256: "sha256";
68
+ readonly arweave: "arweave";
69
+ readonly ipfs: "ipfs";
70
+ readonly url: "url";
71
+ readonly urlTemplate: "url-template";
72
+ readonly inlineGzip: "inline-gzip";
73
+ };
74
+ /**
75
+ * The Configurable Params type + auth vocabularies — index-aligned with the
76
+ * Solidity enums (`IAbxConfigurableParams.ParamType` / `.AuthOption`), so a
77
+ * uint8 from an event decodes to its canonical name by index.
78
+ */
79
+ export declare const PARAM_TYPES: readonly ["Bool", "Select", "Uint256Range", "Int256Range", "DecimalRange", "HexColor", "Timestamp", "String", "Bytes"];
80
+ export type ParamTypeName = (typeof PARAM_TYPES)[number];
81
+ export declare const AUTH_OPTIONS: readonly ["Artist", "TokenOwner", "Address", "ArtistOrTokenOwner", "ArtistOrAddress", "TokenOwnerOrAddress", "ArtistOrTokenOwnerOrAddress"];
82
+ export type AuthOptionName = (typeof AUTH_OPTIONS)[number];
83
+ /** The canonical delegate.xyz v2 registry — the TokenOwner-auth-leg default (same address every chain). */
84
+ export declare const DELEGATE_REGISTRY_DEFAULT: Hex;
85
+ /**
86
+ * The canonical scalar decode — the JS twin of `TokenDataLib.decodeScalar`: one
87
+ * stored `bytes32` → the canonical string `tokenData` carries. `String`/`Bytes`
88
+ * are data-backed (UTF-8 passthrough / base64 at read) and never pass through here.
89
+ */
90
+ export declare function decodeScalarParam(paramType: ParamTypeName, value: Hex | bigint): string;
91
+ /** `DecimalRange`: stored uint ÷ 1e10, trailing zeros trimmed, no point when whole. */
92
+ export declare function decodeDecimalParam(v: bigint): string;
93
+ /**
94
+ * The reverse canonical decode: a human input string → the stored `bytes32`, per the
95
+ * schema's type — what a configure UI (or `abx configure-param`) writes with. Returns
96
+ * the canonical display form alongside (round-tripped through {@link decodeScalarParam}).
97
+ */
98
+ export declare function encodeScalarParam(paramType: ParamTypeName, input: string, selectOptions?: string[]): {
99
+ value: Hex;
100
+ display: string;
101
+ };
102
+ /**
103
+ * Human-facing descriptions of each spine signal — used by the dashboard to
104
+ * narrate "what the chain told us." Keyed by event name.
105
+ */
106
+ export declare const SPINE_EVENT_DOC: Record<string, {
107
+ register: 1 | 2;
108
+ what: string;
109
+ }>;
110
+ //# sourceMappingURL=spine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../src/spine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,GAAG,EAAC,MAAM,MAAM,CAAC;AAEtE;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;CAelB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,eAAe,CAAC;AAExD,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,GAAG,CAErB,CAAC;AAM/B,6EAA6E;AAC7E,wBAAgB,aAAa,CAAC,EAAE,EAAE,GAAG,GAAG,MAAM,CAE7C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAM9C;AAED,gGAAgG;AAChG,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAE1C;AAED,wGAAwG;AACxG,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;CAoBjB,CAAC;AAEX;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;CAY1B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,WAAW,wHAUd,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,YAAY,6IAQf,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,2GAA2G;AAC3G,eAAO,MAAM,yBAAyB,EAAE,GAAkD,CAAC;AAK3F;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,MAAM,CAevF;AAED,uFAAuF;AACvF,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAIpD;AAGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,MAAM,EACb,aAAa,GAAE,MAAM,EAAO,GAC3B;IAAC,KAAK,EAAE,GAAG,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAC,CAoD/B;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE;IAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAyC3E,CAAC"}
package/dist/spine.js ADDED
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spine.js","sourceRoot":"","sources":["../src/spine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type Address, type Hex } from 'viem';
2
+ import type { MetadataField, ProjectState, TokenState } from './types.js';
3
+ /** The token in a reconstructed project, or null. */
4
+ export declare function findToken(state: ProjectState, tokenId: string | number): TokenState | null;
5
+ /** A field's single active on-chain entry (`{field, representation, value}`), or null if unset. */
6
+ export declare function fieldOf(fields: MetadataField[], fieldName: string): MetadataField | null;
7
+ export declare function isOnChain(representation: string): boolean;
8
+ /** Decode an `inline` field value as UTF-8 text. */
9
+ export declare function inlineText(field: MetadataField): string;
10
+ /** Decode an `inline` field value as raw bytes. */
11
+ export declare function inlineBytes(field: MetadataField): Uint8Array;
12
+ /** Verify bytes against a field carried as a `keccak256`/`sha256` hash; null if not a hash representation. */
13
+ export declare function verifyAgainstHash(bytes: Uint8Array | string, field: MetadataField): boolean | null;
14
+ /**
15
+ * Decode a `reader` field value → `(reader, pointer)` addresses. Content is then
16
+ * obtained on-chain by `IAbxOnChainReader(reader).read(pointer)` (an `eth_call`). The
17
+ * reader encapsulates storage + on-chain decoding; this just unpacks the two addresses.
18
+ */
19
+ export declare function decodeReader(value: Hex): {
20
+ reader: Address;
21
+ pointer: Address;
22
+ };
23
+ /** Encode a `reader` field value from `(reader, pointer)` — the write-side counterpart. */
24
+ export declare function encodeReader(reader: Address, pointer: Address): Hex;
25
+ /**
26
+ * Encode a `renderer` field value — `abi.encode(address fieldRenderer)` (the representations
27
+ * table, specs/protocol/onchain-metadata.md). Content is COMPUTED at read: the metadata
28
+ * renderer (and the off-chain resolver) staticcall `render(token, tokenId, field)` on it.
29
+ */
30
+ export declare function encodeFieldRenderer(fieldRenderer: Address): Hex;
31
+ /** Decode a `renderer` field value back to the field-renderer address (the read-side twin). */
32
+ export declare function decodeFieldRenderer(value: Hex): Address;
33
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,GAAG,EACT,MAAM,MAAM,CAAC;AAEd,OAAO,KAAK,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AAExE,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAG1F;AAED,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAExF;AAED,wBAAgB,SAAS,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAEzD;AAID,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAMvD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,UAAU,CAE5D;AAED,8GAA8G;AAC9G,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,GAAG,IAAI,CAKlG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAC,CAG5E;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,CAInE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,OAAO,GAAG,GAAG,CAE/D;AAED,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAGvD"}
package/dist/token.js ADDED
@@ -0,0 +1,66 @@
1
+ import { keccak256, sha256, hexToString, hexToBytes, decodeAbiParameters, } from 'viem';
2
+ import { METADATA_REPRESENTATION as R } from './spine.js';
3
+ /** The token in a reconstructed project, or null. */
4
+ export function findToken(state, tokenId) {
5
+ const id = String(tokenId);
6
+ return state.tokens.find((t) => t.tokenId === id) ?? null;
7
+ }
8
+ /** A field's single active on-chain entry (`{field, representation, value}`), or null if unset. */
9
+ export function fieldOf(fields, fieldName) {
10
+ return fields.find((f) => f.field === fieldName) ?? null;
11
+ }
12
+ export function isOnChain(representation) {
13
+ return representation === R.inline || representation === R.reader;
14
+ }
15
+ // ── value decoding by representation ─────────────────────────────────────────
16
+ /** Decode an `inline` field value as UTF-8 text. */
17
+ export function inlineText(field) {
18
+ try {
19
+ return hexToString(field.value);
20
+ }
21
+ catch {
22
+ return '';
23
+ }
24
+ }
25
+ /** Decode an `inline` field value as raw bytes. */
26
+ export function inlineBytes(field) {
27
+ return hexToBytes(field.value);
28
+ }
29
+ /** Verify bytes against a field carried as a `keccak256`/`sha256` hash; null if not a hash representation. */
30
+ export function verifyAgainstHash(bytes, field) {
31
+ const input = typeof bytes === 'string' ? new TextEncoder().encode(bytes) : bytes;
32
+ if (field.representation === R.keccak256)
33
+ return keccak256(input) === field.value;
34
+ if (field.representation === R.sha256)
35
+ return sha256(input) === field.value;
36
+ return null;
37
+ }
38
+ /**
39
+ * Decode a `reader` field value → `(reader, pointer)` addresses. Content is then
40
+ * obtained on-chain by `IAbxOnChainReader(reader).read(pointer)` (an `eth_call`). The
41
+ * reader encapsulates storage + on-chain decoding; this just unpacks the two addresses.
42
+ */
43
+ export function decodeReader(value) {
44
+ const [reader, pointer] = decodeAbiParameters([{ type: 'address' }, { type: 'address' }], value);
45
+ return { reader, pointer };
46
+ }
47
+ /** Encode a `reader` field value from `(reader, pointer)` — the write-side counterpart. */
48
+ export function encodeReader(reader, pointer) {
49
+ // abi.encode(address, address)
50
+ const strip = (a) => a.slice(2).toLowerCase().padStart(64, '0');
51
+ return (`0x${strip(reader)}${strip(pointer)}`);
52
+ }
53
+ /**
54
+ * Encode a `renderer` field value — `abi.encode(address fieldRenderer)` (the representations
55
+ * table, specs/protocol/onchain-metadata.md). Content is COMPUTED at read: the metadata
56
+ * renderer (and the off-chain resolver) staticcall `render(token, tokenId, field)` on it.
57
+ */
58
+ export function encodeFieldRenderer(fieldRenderer) {
59
+ return (`0x${fieldRenderer.slice(2).toLowerCase().padStart(64, '0')}`);
60
+ }
61
+ /** Decode a `renderer` field value back to the field-renderer address (the read-side twin). */
62
+ export function decodeFieldRenderer(value) {
63
+ const [renderer] = decodeAbiParameters([{ type: 'address' }], value);
64
+ return renderer;
65
+ }
66
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { type Hex, type PublicClient } from 'viem';
2
+ import type { MetadataField, ProjectState, TokenState } from './types.js';
3
+ export interface TokenDataResult {
4
+ /** The flat object (values are canonical strings; `chainId` is a number). */
5
+ data: Record<string, string | number>;
6
+ /** The canonical serialization: keys sorted lexicographically, no insignificant whitespace. */
7
+ json: string;
8
+ }
9
+ /** The `code` collection field (directory mode), if any — locators only per the registry. */
10
+ export declare function codeField(state: ProjectState): MetadataField | null;
11
+ /** Whether this project has executable content (a `code` field, or on-chain script chunks). */
12
+ export declare function isCodeProject(state: ProjectState): boolean;
13
+ /** A well-known contract param's canonical string (e.g. `display.animation`), or null. */
14
+ export declare function contractParamString(state: ProjectState, key: string): string | null;
15
+ /**
16
+ * Assemble canonical tokenData. `client` null ⇒ best-effort (no blobs, no augment hook).
17
+ *
18
+ * `opts.augment` picks between the two canonical forms:
19
+ * - **full** (default, `augment: true`) — settled params + the augment hook's LIVE entries.
20
+ * What the live view injects: current by construction, stale the moment after.
21
+ * - **settled** (`augment: false`) — event-derived state only (explicit params ∪ seed ∪
22
+ * data-backed blobs; all deterministic chain reads). This is what effect outputs are
23
+ * ADDRESSED by: a still is a snapshot of settled state, so a volatile augment hook
24
+ * (block timestamp, an oracle) animates the live view without re-addressing the render
25
+ * every block — the cache stays hot, and re-render triggers are settled-state changes only.
26
+ */
27
+ export declare function buildTokenData(client: PublicClient | null, state: ProjectState, token: TokenState, opts?: {
28
+ augment?: boolean;
29
+ }): Promise<TokenDataResult>;
30
+ /** The canonical serialization: lexicographically sorted keys, compact JSON, UTF-8. */
31
+ export declare function canonicalTokenDataJson(data: Record<string, string | number>): string;
32
+ /**
33
+ * The effect run identity (`specs/protocol/effects.md`):
34
+ * `keccak256(contentDigest ‖ canonical tokenData ‖ environmentId)`. Deterministic across
35
+ * producers and consumers — the resolver computes the CURRENT hash and looks up exactly
36
+ * that artifact, so a param change re-addresses output and stale renders are never served.
37
+ */
38
+ export declare function inputsHash(contentDigest: Hex | null, canonicalJson: string, environmentId?: string): Hex;
39
+ /** The project's content digest: on-chain script digest (head-read), else keccak of the
40
+ * `code` field's locator value (content-addressed forms carry their own integrity). */
41
+ export declare function contentDigestOf(state: ProjectState): Hex | null;
42
+ /**
43
+ * The canonical artifact address for an effect output, mapped onto the hash-keyed
44
+ * byte-custody interface: `keccak256` of the path
45
+ * `{chainId}/{address}/{tokenId}/{effectKey}/{inputsHash}/{outputKey}` — so every
46
+ * conforming producer (the `abx render` CLI, a hosted node) and consumer (this
47
+ * resolver) agree on where a run's artifacts live, over any storage backend.
48
+ */
49
+ export declare function renderArtifactKey(chainId: number, address: string, tokenId: string, hash: Hex, outputKey?: string, effectKey?: string): Hex;
50
+ //# sourceMappingURL=tokendata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokendata.d.ts","sourceRoot":"","sources":["../src/tokendata.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,GAAG,EACR,KAAK,YAAY,EAClB,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAC,aAAa,EAA2B,YAAY,EAAE,UAAU,EAAC,MAAM,YAAY,CAAC;AAuBjG,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;IACtC,+FAA+F;IAC/F,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6FAA6F;AAC7F,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,GAAG,IAAI,CAEnE;AAED,+FAA+F;AAC/F,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAE1D;AAED,0FAA0F;AAC1F,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAInF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,YAAY,GAAG,IAAI,EAC3B,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAM,GAC7B,OAAO,CAAC,eAAe,CAAC,CAyC1B;AAED,uFAAuF;AACvF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAIpF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACxB,aAAa,EAAE,GAAG,GAAG,IAAI,EACzB,aAAa,EAAE,MAAM,EACrB,aAAa,SAAY,GACxB,GAAG,CAQL;AAED;wFACwF;AACxF,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,GAAG,GAAG,IAAI,CAI/D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,GAAG,EACT,SAAS,GAAE,MAAgB,EAC3B,SAAS,SAAW,GACnB,GAAG,CAIL"}
@@ -0,0 +1,178 @@
1
+ import { concat, hexToBytes, keccak256, parseAbi, stringToBytes, } from 'viem';
2
+ import { seriesCodeAbi } from './abi/index.js';
3
+ import { decodeScalarParam } from './spine.js';
4
+ /**
5
+ * The canonical `tokenData` assembly — the off-chain serializer the spec names as
6
+ * authoritative (`specs/protocol/code-projects.md`). One flat object: the reserved
7
+ * coordinates + every param (contract ∪ token scope, token wins) + the augment hook's
8
+ * entries (augment wins per key), every value its canonical string (`chainId` alone is
9
+ * a number). The serialization is canonical because it is *hashed*: an effect's
10
+ * `inputsHash` commits to it, so this exact byte shape is what makes render outputs
11
+ * addressable and self-invalidating.
12
+ *
13
+ * Decode rules: a schema'd param decodes per its type (`Select` → the option string,
14
+ * `DecimalRange` ÷ 1e10, …); a schema-less literal stays the raw `bytes32` hex (a
15
+ * schema is what buys a human decode — `seed` is the canonical example); a data-backed
16
+ * value reads its blob (`String` → UTF-8, `Bytes`/schema-less → base64).
17
+ */
18
+ const RESERVED = new Set(['chainId', 'contractAddress', 'tokenId', 'seed']);
19
+ const augmentHookAbi = parseAbi([
20
+ 'function augmentTokenParams(address token, uint256 tokenId) view returns ((bytes32 key, string value)[])',
21
+ ]);
22
+ /** The `code` collection field (directory mode), if any — locators only per the registry. */
23
+ export function codeField(state) {
24
+ return state.collectionFields.find((f) => f.field === 'code') ?? null;
25
+ }
26
+ /** Whether this project has executable content (a `code` field, or on-chain script chunks). */
27
+ export function isCodeProject(state) {
28
+ return codeField(state) !== null || ((state.script?.chunkCount ?? 0) > 0);
29
+ }
30
+ /** A well-known contract param's canonical string (e.g. `display.animation`), or null. */
31
+ export function contractParamString(state, key) {
32
+ const p = state.contractParams?.find((x) => x.key === key);
33
+ if (!p || p.valueIsHash)
34
+ return null;
35
+ return decodeTagLoose(p.value);
36
+ }
37
+ /**
38
+ * Assemble canonical tokenData. `client` null ⇒ best-effort (no blobs, no augment hook).
39
+ *
40
+ * `opts.augment` picks between the two canonical forms:
41
+ * - **full** (default, `augment: true`) — settled params + the augment hook's LIVE entries.
42
+ * What the live view injects: current by construction, stale the moment after.
43
+ * - **settled** (`augment: false`) — event-derived state only (explicit params ∪ seed ∪
44
+ * data-backed blobs; all deterministic chain reads). This is what effect outputs are
45
+ * ADDRESSED by: a still is a snapshot of settled state, so a volatile augment hook
46
+ * (block timestamp, an oracle) animates the live view without re-addressing the render
47
+ * every block — the cache stays hot, and re-render triggers are settled-state changes only.
48
+ */
49
+ export async function buildTokenData(client, state, token, opts = {}) {
50
+ const schemas = new Map((state.paramSchemas ?? []).map((s) => [s.key, s]));
51
+ const data = {
52
+ chainId: state.chainId,
53
+ contractAddress: state.address.toLowerCase(),
54
+ tokenId: token.tokenId,
55
+ };
56
+ // contract ∪ token scope, token wins — decoded per schema (or the schema-less rule)
57
+ const merged = new Map();
58
+ for (const p of state.contractParams ?? [])
59
+ merged.set(p.key, { p, tokenScope: false });
60
+ for (const p of token.params ?? [])
61
+ merged.set(p.key, { p, tokenScope: true });
62
+ for (const [key, { p, tokenScope }] of merged) {
63
+ if (RESERVED.has(key) && key !== 'seed')
64
+ continue; // coordinates win
65
+ data[key] = await decodeParam(client, state.address, token.tokenId, p, tokenScope, schemas.get(key));
66
+ }
67
+ // augment hook — last, wins per key (except the reserved coordinates). Skipped for the
68
+ // SETTLED form (opts.augment false): live data belongs in the live view, never in the
69
+ // address of a render artifact.
70
+ const hook = state.paramHooks?.augmentHook ?? null;
71
+ if (client && hook && (opts.augment ?? true)) {
72
+ try {
73
+ const entries = (await client.readContract({
74
+ address: hook,
75
+ abi: augmentHookAbi,
76
+ functionName: 'augmentTokenParams',
77
+ args: [state.address, BigInt(token.tokenId)],
78
+ }));
79
+ for (const e of entries) {
80
+ const key = decodeBytes32Key(e.key);
81
+ if (RESERVED.has(key))
82
+ continue;
83
+ data[key] = e.value;
84
+ }
85
+ }
86
+ catch {
87
+ // best-effort by design: a broken augment hook must never take tokenData down
88
+ }
89
+ }
90
+ return { data, json: canonicalTokenDataJson(data) };
91
+ }
92
+ /** The canonical serialization: lexicographically sorted keys, compact JSON, UTF-8. */
93
+ export function canonicalTokenDataJson(data) {
94
+ const sorted = {};
95
+ for (const key of Object.keys(data).sort())
96
+ sorted[key] = data[key];
97
+ return JSON.stringify(sorted);
98
+ }
99
+ /**
100
+ * The effect run identity (`specs/protocol/effects.md`):
101
+ * `keccak256(contentDigest ‖ canonical tokenData ‖ environmentId)`. Deterministic across
102
+ * producers and consumers — the resolver computes the CURRENT hash and looks up exactly
103
+ * that artifact, so a param change re-addresses output and stale renders are never served.
104
+ */
105
+ export function inputsHash(contentDigest, canonicalJson, environmentId = 'web:any') {
106
+ return keccak256(concat([
107
+ contentDigest ? hexToBytes(contentDigest) : new Uint8Array([0]),
108
+ stringToBytes(canonicalJson),
109
+ stringToBytes(environmentId),
110
+ ]));
111
+ }
112
+ /** The project's content digest: on-chain script digest (head-read), else keccak of the
113
+ * `code` field's locator value (content-addressed forms carry their own integrity). */
114
+ export function contentDigestOf(state) {
115
+ if (state.script?.digest)
116
+ return state.script.digest;
117
+ const code = codeField(state);
118
+ return code ? keccak256(code.value) : null;
119
+ }
120
+ /**
121
+ * The canonical artifact address for an effect output, mapped onto the hash-keyed
122
+ * byte-custody interface: `keccak256` of the path
123
+ * `{chainId}/{address}/{tokenId}/{effectKey}/{inputsHash}/{outputKey}` — so every
124
+ * conforming producer (the `abx render` CLI, a hosted node) and consumer (this
125
+ * resolver) agree on where a run's artifacts live, over any storage backend.
126
+ */
127
+ export function renderArtifactKey(chainId, address, tokenId, hash, outputKey = 'image', effectKey = 'render') {
128
+ return keccak256(stringToBytes(`${chainId}/${address.toLowerCase()}/${tokenId}/${effectKey}/${hash}/${outputKey}`));
129
+ }
130
+ // ── internals ──────────────────────────────────────────────────────────────────
131
+ async function decodeParam(client, token, tokenId, p, tokenScope, schema) {
132
+ if (!p.valueIsHash) {
133
+ if (!schema)
134
+ return p.key === 'seed' ? p.value : decodeTagLoose(p.value);
135
+ if (schema.paramType === 'Select') {
136
+ const idx = Number(BigInt(p.value));
137
+ return schema.selectOptions[idx] ?? String(idx);
138
+ }
139
+ return decodeScalarParam(schema.paramType, p.value);
140
+ }
141
+ // data-backed: read the blob (token scope falls back to contract scope by construction)
142
+ if (!client)
143
+ return p.value; // best-effort floor: the hash itself
144
+ try {
145
+ const blob = (await client.readContract({
146
+ address: token,
147
+ abi: seriesCodeAbi,
148
+ functionName: tokenScope ? 'tokenParamData' : 'contractParamData',
149
+ args: tokenScope ? [BigInt(tokenId), keyToBytes32(p.key)] : [keyToBytes32(p.key)],
150
+ }));
151
+ const bytes = hexToBytes(blob);
152
+ if (schema?.paramType === 'String')
153
+ return new TextDecoder().decode(bytes);
154
+ return Buffer.from(bytes).toString('base64'); // Bytes + schema-less: base64 at read
155
+ }
156
+ catch {
157
+ return p.value;
158
+ }
159
+ }
160
+ /** A readable-ASCII `bytes32` literal as its string (e.g. a `display.animation` value). */
161
+ function decodeTagLoose(value) {
162
+ const bytes = hexToBytes(value);
163
+ let end = bytes.length;
164
+ while (end > 0 && bytes[end - 1] === 0)
165
+ end--;
166
+ const trimmed = bytes.slice(0, end);
167
+ const isAscii = trimmed.length > 0 && trimmed.every((b) => b >= 0x20 && b < 0x7f);
168
+ return isAscii ? new TextDecoder().decode(trimmed) : value;
169
+ }
170
+ function decodeBytes32Key(key) {
171
+ return decodeTagLoose(key);
172
+ }
173
+ function keyToBytes32(key) {
174
+ const bytes = new Uint8Array(32);
175
+ bytes.set(stringToBytes(key).slice(0, 32));
176
+ return `0x${Buffer.from(bytes).toString('hex')}`;
177
+ }
178
+ //# sourceMappingURL=tokendata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokendata.js","sourceRoot":"","sources":["../src/tokendata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * OpenSea-style token traits (`attributes`). The protocol stores them as one
3
+ * metadata field (`attributes`) carrying **inline JSON** when on-chain; off-chain,
4
+ * an operator keeps the same array in their resolver's registration. Either way the
5
+ * shape is the marketplace standard — `{trait_type, value, display_type?}` — and
6
+ * NOT a dumping ground for protocol facts (version, canonical, royalty); those are
7
+ * `abx_provenance` / ERC-2981 concerns, never traits. This module is the one place
8
+ * the toolkit parses, validates, and merges them, so the CLI (write side) and the
9
+ * resolver (read side) agree on exactly one normal form.
10
+ */
11
+ export interface OpenSeaAttribute {
12
+ trait_type: string;
13
+ value: string | number;
14
+ /** OpenSea display hint, e.g. `number`, `boost_percentage`, `date`. Omitted for plain string traits. */
15
+ display_type?: string;
16
+ }
17
+ /**
18
+ * Normalize arbitrary input into a validated OpenSea attribute array. Accepts either
19
+ * the canonical array form (`[{trait_type, value, display_type?}]`) or a convenience
20
+ * object map (`{Background: "Blue", Edition: 3}`). Drops entries with an empty
21
+ * `trait_type`. Throws only on a value that's structurally not traits at all.
22
+ */
23
+ export declare function normalizeAttributes(input: unknown): OpenSeaAttribute[];
24
+ /**
25
+ * Parse the quick inline trait form used on the CLI: `"Background=Blue; Edition=3"`.
26
+ * Semicolon- (or newline-) separated `key=value` pairs; a numeric value becomes a
27
+ * number. For anything richer (display_type, etc.) use a JSON file via
28
+ * {@link normalizeAttributes}.
29
+ */
30
+ export declare function parseTraitPairs(spec: string): OpenSeaAttribute[];
31
+ /**
32
+ * Merge on-chain and off-chain attributes into the served set. **On-chain wins per
33
+ * `trait_type`** (case-insensitively) — a trait committed on-chain overrides an
34
+ * off-chain one of the same name — and the rest are unioned. On-chain order is kept
35
+ * first, then any off-chain traits the chain didn't already define.
36
+ */
37
+ export declare function stitchAttributes(onChain: OpenSeaAttribute[] | null | undefined, offChain: OpenSeaAttribute[] | null | undefined): OpenSeaAttribute[];
38
+ //# sourceMappingURL=traits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.d.ts","sourceRoot":"","sources":["../src/traits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,wGAAwG;IACxG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AASD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,EAAE,CAyBtE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAchE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,gBAAgB,EAAE,GAAG,IAAI,GAAG,SAAS,EAC9C,QAAQ,EAAE,gBAAgB,EAAE,GAAG,IAAI,GAAG,SAAS,GAC9C,gBAAgB,EAAE,CAKpB"}
package/dist/traits.js ADDED
@@ -0,0 +1,92 @@
1
+ /**
2
+ * OpenSea-style token traits (`attributes`). The protocol stores them as one
3
+ * metadata field (`attributes`) carrying **inline JSON** when on-chain; off-chain,
4
+ * an operator keeps the same array in their resolver's registration. Either way the
5
+ * shape is the marketplace standard — `{trait_type, value, display_type?}` — and
6
+ * NOT a dumping ground for protocol facts (version, canonical, royalty); those are
7
+ * `abx_provenance` / ERC-2981 concerns, never traits. This module is the one place
8
+ * the toolkit parses, validates, and merges them, so the CLI (write side) and the
9
+ * resolver (read side) agree on exactly one normal form.
10
+ */
11
+ /** Coerce a loose value to a trait value: numbers stay numbers, everything else is a trimmed string. */
12
+ function coerceValue(v) {
13
+ if (typeof v === 'number' && Number.isFinite(v))
14
+ return v;
15
+ if (typeof v === 'boolean')
16
+ return v ? 'true' : 'false';
17
+ return String(v).trim();
18
+ }
19
+ /**
20
+ * Normalize arbitrary input into a validated OpenSea attribute array. Accepts either
21
+ * the canonical array form (`[{trait_type, value, display_type?}]`) or a convenience
22
+ * object map (`{Background: "Blue", Edition: 3}`). Drops entries with an empty
23
+ * `trait_type`. Throws only on a value that's structurally not traits at all.
24
+ */
25
+ export function normalizeAttributes(input) {
26
+ if (input == null)
27
+ return [];
28
+ const rows = [];
29
+ if (Array.isArray(input)) {
30
+ for (const raw of input) {
31
+ if (!raw || typeof raw !== 'object')
32
+ continue;
33
+ const r = raw;
34
+ const trait_type = String(r.trait_type ?? r.traitType ?? '').trim();
35
+ if (!trait_type)
36
+ continue;
37
+ const attr = { trait_type, value: coerceValue(r.value) };
38
+ const dt = r.display_type ?? r.displayType;
39
+ if (dt != null && String(dt).trim())
40
+ attr.display_type = String(dt).trim();
41
+ rows.push(attr);
42
+ }
43
+ return rows;
44
+ }
45
+ if (typeof input === 'object') {
46
+ for (const [k, v] of Object.entries(input)) {
47
+ const trait_type = k.trim();
48
+ if (!trait_type)
49
+ continue;
50
+ rows.push({ trait_type, value: coerceValue(v) });
51
+ }
52
+ return rows;
53
+ }
54
+ throw new Error('attributes must be a JSON array of {trait_type, value} or an object map of {name: value}');
55
+ }
56
+ /**
57
+ * Parse the quick inline trait form used on the CLI: `"Background=Blue; Edition=3"`.
58
+ * Semicolon- (or newline-) separated `key=value` pairs; a numeric value becomes a
59
+ * number. For anything richer (display_type, etc.) use a JSON file via
60
+ * {@link normalizeAttributes}.
61
+ */
62
+ export function parseTraitPairs(spec) {
63
+ const out = [];
64
+ for (const part of spec.split(/[;\n]+/)) {
65
+ const s = part.trim();
66
+ if (!s)
67
+ continue;
68
+ const eq = s.indexOf('=');
69
+ if (eq === -1)
70
+ throw new Error(`trait "${s}" must be key=value`);
71
+ const trait_type = s.slice(0, eq).trim();
72
+ const rawValue = s.slice(eq + 1).trim();
73
+ if (!trait_type)
74
+ throw new Error(`trait "${s}" has an empty name`);
75
+ const num = Number(rawValue);
76
+ out.push({ trait_type, value: rawValue !== '' && Number.isFinite(num) ? num : rawValue });
77
+ }
78
+ return out;
79
+ }
80
+ /**
81
+ * Merge on-chain and off-chain attributes into the served set. **On-chain wins per
82
+ * `trait_type`** (case-insensitively) — a trait committed on-chain overrides an
83
+ * off-chain one of the same name — and the rest are unioned. On-chain order is kept
84
+ * first, then any off-chain traits the chain didn't already define.
85
+ */
86
+ export function stitchAttributes(onChain, offChain) {
87
+ const chain = onChain ?? [];
88
+ const off = offChain ?? [];
89
+ const seen = new Set(chain.map((a) => a.trait_type.toLowerCase()));
90
+ return [...chain, ...off.filter((a) => !seen.has(a.trait_type.toLowerCase()))];
91
+ }
92
+ //# sourceMappingURL=traits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"traits.js","sourceRoot":"","sources":["../src/traits.ts"],"names":[],"mappings":"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"}